Merge master.kernel.org:/home/rmk/linux-2.6-arm

* master.kernel.org:/home/rmk/linux-2.6-arm:
  [ARM] 3657/1: S3C24XX: Documentation update of Overview.txt
  [ARM] Update mach-types
  [ARM] 3656/1: S3C2412: Add S3C2412 and S3C2413 documenation
  [ARM] 3654/1: add ajeco 1arm sbc support
  [ARM] fix drivers/mfd/ucb1x00-core.c IRQ probing bug
  [ARM] 3651/1: S3C24XX: Make arch list more detailed
  [ARM] 3650/1: S3C2412: Update s3c2410_defconfig
  [ARM] 3649/1: S3C24XX: Fix capitalisation of CPU on SMDK2440
  [ARM] 3612/1: make pci bus optional for ixp4xx platform
  [ARM] Remove MODE_(SVC|IRQ|FIQ|USR) and DEFAULT_FIQ
  [ARM] Remove save_lr/restore_pc macros
  [ARM] Remove partial non-v6 binutils compatibility
  [ARM] Remove LOADREGS macro
  [ARM] Remove RETINSTR macro
diff --git a/CREDITS b/CREDITS
index 9bf714a..85c7c70b7 100644
--- a/CREDITS
+++ b/CREDITS
@@ -24,6 +24,11 @@
 S: Iasi 6600
 S: Romania
 
+N: Mark Adler
+E: madler@alumni.caltech.edu
+W: http://alumnus.caltech.edu/~madler/
+D: zlib decompression
+
 N: Monalisa Agrawal
 E: magrawal@nortelnetworks.com
 D: Basic Interphase 5575 driver with UBR and ABR support.
@@ -1573,12 +1578,8 @@
 S: Czech Republic
 
 N: Niels Kristian Bech Jensen
-E: nkbj@image.dk
-W: http://www.image.dk/~nkbj
+E: nkbj1970@hotmail.com
 D: Miscellaneous kernel updates and fixes.
-S: Dr. Holsts Vej 34, lejl. 164
-S: DK-8230 Åbyhøj
-S: Denmark
 
 N: Michael K. Johnson
 E: johnsonm@redhat.com
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 31b727c..3630a0d 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -62,6 +62,8 @@
      <sect1><title>Internal Functions</title>
 !Ikernel/exit.c
 !Ikernel/signal.c
+!Iinclude/linux/kthread.h
+!Ekernel/kthread.c
      </sect1>
 
      <sect1><title>Kernel objects manipulation</title>
@@ -114,6 +116,29 @@
      </sect1>
   </chapter>
 
+  <chapter id="kernel-lib">
+     <title>Basic Kernel Library Functions</title>
+
+     <para>
+       The Linux kernel provides more basic utility functions.
+     </para>
+
+     <sect1><title>Bitmap Operations</title>
+!Elib/bitmap.c
+!Ilib/bitmap.c
+     </sect1>
+
+     <sect1><title>Command-line Parsing</title>
+!Elib/cmdline.c
+     </sect1>
+
+     <sect1><title>CRC Functions</title>
+!Elib/crc16.c
+!Elib/crc32.c
+!Elib/crc-ccitt.c
+     </sect1>
+  </chapter>
+
   <chapter id="mm">
      <title>Memory Management in Linux</title>
      <sect1><title>The Slab Cache</title>
@@ -281,12 +306,13 @@
      <sect1><title>MTRR Handling</title>
 !Earch/i386/kernel/cpu/mtrr/main.c
      </sect1>
+
      <sect1><title>PCI Support Library</title>
 !Edrivers/pci/pci.c
 !Edrivers/pci/pci-driver.c
 !Edrivers/pci/remove.c
 !Edrivers/pci/pci-acpi.c
-<!-- kerneldoc does not understand to __devinit
+<!-- kerneldoc does not understand __devinit
 X!Edrivers/pci/search.c
  -->
 !Edrivers/pci/msi.c
@@ -315,6 +341,13 @@
      </sect1>
   </chapter>
 
+  <chapter id="firmware">
+     <title>Firmware Interfaces</title>
+     <sect1><title>DMI Interfaces</title>
+!Edrivers/firmware/dmi_scan.c
+     </sect1>
+  </chapter>
+
   <chapter id="devfs">
      <title>The Device File System</title>
 !Efs/devfs/base.c
@@ -403,7 +436,6 @@
      </sect1>
   </chapter>
 
-
   <chapter id="blkdev">
      <title>Block Devices</title>
 !Eblock/ll_rw_blk.c
@@ -414,6 +446,14 @@
 !Edrivers/char/misc.c
   </chapter>
 
+  <chapter id="parportdev">
+     <title>Parallel Port Devices</title>
+!Iinclude/linux/parport.h
+!Edrivers/parport/ieee1284.c
+!Edrivers/parport/share.c
+!Idrivers/parport/daisy.c
+  </chapter>
+
   <chapter id="viddev">
      <title>Video4Linux</title>
 !Edrivers/media/video/videodev.c
diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
index 158ffe9..644c388 100644
--- a/Documentation/DocBook/kernel-locking.tmpl
+++ b/Documentation/DocBook/kernel-locking.tmpl
@@ -1590,7 +1590,7 @@
     <para>
       Our final dilemma is this: when can we actually destroy the
       removed element?  Remember, a reader might be stepping through
-      this element in the list right now: it we free this element and
+      this element in the list right now: if we free this element and
       the <symbol>next</symbol> pointer changes, the reader will jump
       off into garbage and crash.  We need to wait until we know that
       all the readers who were traversing the list when we deleted the
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 49e27cc..1d50cf0 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -144,9 +144,47 @@
 	whether the increased speed is worth it.
 
 8.	Although synchronize_rcu() is a bit slower than is call_rcu(),
-	it usually results in simpler code.  So, unless update performance
-	is important or the updaters cannot block, synchronize_rcu()
-	should be used in preference to call_rcu().
+	it usually results in simpler code.  So, unless update
+	performance is critically important or the updaters cannot block,
+	synchronize_rcu() should be used in preference to call_rcu().
+
+	An especially important property of the synchronize_rcu()
+	primitive is that it automatically self-limits: if grace periods
+	are delayed for whatever reason, then the synchronize_rcu()
+	primitive will correspondingly delay updates.  In contrast,
+	code using call_rcu() should explicitly limit update rate in
+	cases where grace periods are delayed, as failing to do so can
+	result in excessive realtime latencies or even OOM conditions.
+
+	Ways of gaining this self-limiting property when using call_rcu()
+	include:
+
+	a.	Keeping a count of the number of data-structure elements
+		used by the RCU-protected data structure, including those
+		waiting for a grace period to elapse.  Enforce a limit
+		on this number, stalling updates as needed to allow
+		previously deferred frees to complete.
+
+		Alternatively, limit only the number awaiting deferred
+		free rather than the total number of elements.
+
+	b.	Limiting update rate.  For example, if updates occur only
+		once per hour, then no explicit rate limiting is required,
+		unless your system is already badly broken.  The dcache
+		subsystem takes this approach -- updates are guarded
+		by a global lock, limiting their rate.
+
+	c.	Trusted update -- if updates can only be done manually by
+		superuser or some other trusted user, then it might not
+		be necessary to automatically limit them.  The theory
+		here is that superuser already has lots of ways to crash
+		the machine.
+
+	d.	Use call_rcu_bh() rather than call_rcu(), in order to take
+		advantage of call_rcu_bh()'s faster grace periods.
+
+	e.	Periodically invoke synchronize_rcu(), permitting a limited
+		number of updates per grace period.
 
 9.	All RCU list-traversal primitives, which include
 	list_for_each_rcu(), list_for_each_entry_rcu(),
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 6e45942..4f41a60 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -184,7 +184,17 @@
 	blocking, it registers a function and argument which are invoked
 	after all ongoing RCU read-side critical sections have completed.
 	This callback variant is particularly useful in situations where
-	it is illegal to block.
+	it is illegal to block or where update-side performance is
+	critically important.
+
+	However, the call_rcu() API should not be used lightly, as use
+	of the synchronize_rcu() API generally results in simpler code.
+	In addition, the synchronize_rcu() API has the nice property
+	of automatically limiting update rate should grace periods
+	be delayed.  This property results in system resilience in face
+	of denial-of-service attacks.  Code using call_rcu() should limit
+	update rate in order to gain this same sort of resilience.  See
+	checklist.txt for some approaches to limiting the update rate.
 
 rcu_assign_pointer()
 
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index 23a1c24..2a63d56 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -157,13 +157,13 @@
 	smp_mb__before_atomic_dec();
 	atomic_dec(&obj->ref_count);
 
-It makes sure that all memory operations preceeding the atomic_dec()
+It makes sure that all memory operations preceding the atomic_dec()
 call are strongly ordered with respect to the atomic counter
-operation.  In the above example, it guarentees that the assignment of
+operation.  In the above example, it guarantees that the assignment of
 "1" to obj->dead will be globally visible to other cpus before the
 atomic counter decrement.
 
-Without the explicitl smp_mb__before_atomic_dec() call, the
+Without the explicit smp_mb__before_atomic_dec() call, the
 implementation could legally allow the atomic counter update visible
 to other cpus before the "obj->dead = 1;" assignment.
 
@@ -173,11 +173,11 @@
 (smp_mb__{before,after}_atomic_inc()).
 
 A missing memory barrier in the cases where they are required by the
-atomic_t implementation above can have disasterous results.  Here is
-an example, which follows a pattern occuring frequently in the Linux
+atomic_t implementation above can have disastrous results.  Here is
+an example, which follows a pattern occurring frequently in the Linux
 kernel.  It is the use of atomic counters to implement reference
 counting, and it works such that once the counter falls to zero it can
-be guarenteed that no other entity can be accessing the object:
+be guaranteed that no other entity can be accessing the object:
 
 static void obj_list_add(struct obj *obj)
 {
@@ -291,9 +291,9 @@
 size.  The endianness of the bits within each "unsigned long" are the
 native endianness of the cpu.
 
-	void set_bit(unsigned long nr, volatils unsigned long *addr);
-	void clear_bit(unsigned long nr, volatils unsigned long *addr);
-	void change_bit(unsigned long nr, volatils unsigned long *addr);
+	void set_bit(unsigned long nr, volatile unsigned long *addr);
+	void clear_bit(unsigned long nr, volatile unsigned long *addr);
+	void change_bit(unsigned long nr, volatile unsigned long *addr);
 
 These routines set, clear, and change, respectively, the bit number
 indicated by "nr" on the bit mask pointed to by "ADDR".
@@ -301,9 +301,9 @@
 They must execute atomically, yet there are no implicit memory barrier
 semantics required of these interfaces.
 
-	int test_and_set_bit(unsigned long nr, volatils unsigned long *addr);
-	int test_and_clear_bit(unsigned long nr, volatils unsigned long *addr);
-	int test_and_change_bit(unsigned long nr, volatils unsigned long *addr);
+	int test_and_set_bit(unsigned long nr, volatile unsigned long *addr);
+	int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr);
+	int test_and_change_bit(unsigned long nr, volatile unsigned long *addr);
 
 Like the above, except that these routines return a boolean which
 indicates whether the changed bit was set _BEFORE_ the atomic bit
@@ -335,7 +335,7 @@
 		/* ... */;
 	obj->killed = 1;
 
-The implementation of test_and_set_bit() must guarentee that
+The implementation of test_and_set_bit() must guarantee that
 "obj->dead = 1;" is visible to cpus before the atomic memory operation
 done by test_and_set_bit() becomes visible.  Likewise, the atomic
 memory operation done by test_and_set_bit() must become visible before
@@ -474,7 +474,7 @@
 strictly orders all subsequent memory operations (including
 the cas()) with respect to itself, things will be fine.
 
-Said another way, _atomic_dec_and_lock() must guarentee that
+Said another way, _atomic_dec_and_lock() must guarantee that
 a counter dropping to zero is never made visible before the
 spinlock being acquired.
 
diff --git a/Documentation/console/console.txt b/Documentation/console/console.txt
new file mode 100644
index 0000000..d3e1744
--- /dev/null
+++ b/Documentation/console/console.txt
@@ -0,0 +1,144 @@
+Console Drivers
+===============
+
+The linux kernel has 2 general types of console drivers.  The first type is
+assigned by the kernel to all the virtual consoles during the boot process.
+This type will be called 'system driver', and only one system driver is allowed
+to exist. The system driver is persistent and it can never be unloaded, though
+it may become inactive.
+
+The second type has to be explicitly loaded and unloaded. This will be called
+'modular driver' by this document. Multiple modular drivers can coexist at
+any time with each driver sharing the console with other drivers including
+the system driver. However, modular drivers cannot take over the console
+that is currently occupied by another modular driver. (Exception: Drivers that
+call take_over_console() will succeed in the takeover regardless of the type
+of driver occupying the consoles.) They can only take over the console that is
+occupied by the system driver. In the same token, if the modular driver is
+released by the console, the system driver will take over.
+
+Modular drivers, from the programmer's point of view, has to call:
+
+	 take_over_console() - load and bind driver to console layer
+	 give_up_console() - unbind and unload driver
+
+In newer kernels, the following are also available:
+
+	 register_con_driver()
+	 unregister_con_driver()
+
+If sysfs is enabled, the contents of /sys/class/vtconsole can be
+examined. This shows the console backends currently registered by the
+system which are named vtcon<n> where <n> is an integer fro 0 to 15. Thus:
+
+       ls /sys/class/vtconsole
+       .  ..  vtcon0  vtcon1
+
+Each directory in /sys/class/vtconsole has 3 files:
+
+     ls /sys/class/vtconsole/vtcon0
+     .  ..  bind  name  uevent
+
+What do these files signify?
+
+     1. bind - this is a read/write file. It shows the status of the driver if
+        read, or acts to bind or unbind the driver to the virtual consoles
+        when written to. The possible values are:
+
+	0 - means the driver is not bound and if echo'ed, commands the driver
+	    to unbind
+
+        1 - means the driver is bound and if echo'ed, commands the driver to
+	    bind
+
+     2. name - read-only file. Shows the name of the driver in this format:
+
+	cat /sys/class/vtconsole/vtcon0/name
+	(S) VGA+
+
+	    '(S)' stands for a (S)ystem driver, ie, it cannot be directly
+	    commanded to bind or unbind
+
+	    'VGA+' is the name of the driver
+
+	cat /sys/class/vtconsole/vtcon1/name
+	(M) frame buffer device
+
+	    In this case, '(M)' stands for a (M)odular driver, one that can be
+	    directly commanded to bind or unbind.
+
+     3. uevent - ignore this file
+
+When unbinding, the modular driver is detached first, and then the system
+driver takes over the consoles vacated by the driver. Binding, on the other
+hand, will bind the driver to the consoles that are currently occupied by a
+system driver.
+
+NOTE1: Binding and binding must be selected in Kconfig. It's under:
+
+Device Drivers -> Character devices -> Support for binding and unbinding
+console drivers
+
+NOTE2: If any of the virtual consoles are in KD_GRAPHICS mode, then binding or
+unbinding will not succeed. An example of an application that sets the console
+to KD_GRAPHICS is X.
+
+How useful is this feature? This is very useful for console driver
+developers. By unbinding the driver from the console layer, one can unload the
+driver, make changes, recompile, reload and rebind the driver without any need
+for rebooting the kernel. For regular users who may want to switch from
+framebuffer console to VGA console and vice versa, this feature also makes
+this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb
+for more details).
+
+Notes for developers:
+=====================
+
+take_over_console() is now broken up into:
+
+     register_con_driver()
+     bind_con_driver() - private function
+
+give_up_console() is a wrapper to unregister_con_driver(), and a driver must
+be fully unbound for this call to succeed. con_is_bound() will check if the
+driver is bound or not.
+
+Guidelines for console driver writers:
+=====================================
+
+In order for binding to and unbinding from the console to properly work,
+console drivers must follow these guidelines:
+
+1. All drivers, except system drivers, must call either register_con_driver()
+   or take_over_console(). register_con_driver() will just add the driver to
+   the console's internal list. It won't take over the
+   console. take_over_console(), as it name implies, will also take over (or
+   bind to) the console.
+
+2. All resources allocated during con->con_init() must be released in
+   con->con_deinit().
+
+3. All resources allocated in con->con_startup() must be released when the
+   driver, which was previously bound, becomes unbound.  The console layer
+   does not have a complementary call to con->con_startup() so it's up to the
+   driver to check when it's legal to release these resources. Calling
+   con_is_bound() in con->con_deinit() will help.  If the call returned
+   false(), then it's safe to release the resources.  This balance has to be
+   ensured because con->con_startup() can be called again when a request to
+   rebind the driver to the console arrives.
+
+4. Upon exit of the driver, ensure that the driver is totally unbound. If the
+   condition is satisfied, then the driver must call unregister_con_driver()
+   or give_up_console().
+
+5. unregister_con_driver() can also be called on conditions which make it
+   impossible for the driver to service console requests.  This can happen
+   with the framebuffer console that suddenly lost all of its drivers.
+
+The current crop of console drivers should still work correctly, but binding
+and unbinding them may cause problems. With minimal fixes, these drivers can
+be made to work correctly.
+
+==========================
+Antonino Daplas <adaplas@pol.net>
+
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index b2f593f..4aaf68f 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -3,7 +3,7 @@
 
 	     Maintained by Torben Mathiasen <device@lanana.org>
 
-		      Last revised: 01 March 2006
+		      Last revised: 15 May 2006
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
@@ -2791,6 +2791,7 @@
 		 170 = /dev/ttyNX0		Hilscher netX serial port 0
 		    ...
 		 185 = /dev/ttyNX15		Hilscher netX serial port 15
+		 186 = /dev/ttyJ0		JTAG1 DCC protocol based serial port emulation
 
 205 char	Low-density serial ports (alternate device)
 		  0 = /dev/culu0		Callout device for ttyLU0
@@ -3108,6 +3109,10 @@
 		  ...
 		240 = /dev/rfdp		16th RFD FTL layer
 
+257 char	Phoenix Technologies Cryptographic Services Driver
+		  0 = /dev/ptlsec	Crypto Services Driver
+
+
 
  ****	ADDITIONAL /dev DIRECTORY ENTRIES
 
diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
index ac4a7a7..2050c9f 100644
--- a/Documentation/driver-model/overview.txt
+++ b/Documentation/driver-model/overview.txt
@@ -18,7 +18,7 @@
 (sometimes just a list) for the devices they control. There wasn't any
 uniformity across the different bus types.
 
-The current driver model provides a comon, uniform data model for describing
+The current driver model provides a common, uniform data model for describing
 a bus and the devices that can appear under the bus. The unified bus
 model includes a set of common attributes which all busses carry, and a set
 of common callbacks, such as device discovery during bus probing, bus
diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt
index 08dce0f..f373df1 100644
--- a/Documentation/fb/fbcon.txt
+++ b/Documentation/fb/fbcon.txt
@@ -135,10 +135,10 @@
 
 	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}
+	 /sys/class/graphics/fbcon
 
-		con_rotate     - rotate the display of the active console
-		con_rotate_all - rotate the display of all consoles
+		rotate     - rotate the display of the active console
+		rotate_all - rotate the display of all consoles
 
 	Console rotation will only become available if Console Rotation
 	Support is compiled in your kernel.
@@ -148,5 +148,177 @@
 	Actually, the underlying fb driver is totally ignorant of console
 	rotation.
 
----
+C. Attaching, Detaching and Unloading
+
+Before going on on how to attach, detach and unload the framebuffer console, an
+illustration of the dependencies may help.
+
+The console layer, as with most subsystems, needs a driver that interfaces with
+the hardware. Thus, in a VGA console:
+
+console ---> VGA driver ---> hardware.
+
+Assuming the VGA driver can be unloaded, one must first unbind the VGA driver
+from the console layer before unloading the driver.  The VGA driver cannot be
+unloaded if it is still bound to the console layer. (See
+Documentation/console/console.txt for more information).
+
+This is more complicated in the case of the the framebuffer console (fbcon),
+because fbcon is an intermediate layer between the console and the drivers:
+
+console ---> fbcon ---> fbdev drivers ---> hardware
+
+The fbdev drivers cannot be unloaded if it's bound to fbcon, and fbcon cannot
+be unloaded if it's bound to the console layer.
+
+So to unload the fbdev drivers, one must first unbind fbcon from the console,
+then unbind the fbdev drivers from fbcon.  Fortunately, unbinding fbcon from
+the console layer will automatically unbind framebuffer drivers from
+fbcon. Thus, there is no need to explicitly unbind the fbdev drivers from
+fbcon.
+
+So, how do we unbind fbcon from the console? Part of the answer is in
+Documentation/console/console.txt. To summarize:
+
+Echo a value to the bind file that represents the framebuffer console
+driver. So assuming vtcon1 represents fbcon, then:
+
+echo 1 > sys/class/vtconsole/vtcon1/bind - attach framebuffer console to
+                                           console layer
+echo 0 > sys/class/vtconsole/vtcon1/bind - detach framebuffer console from
+                                           console layer
+
+If fbcon is detached from the console layer, your boot console driver (which is
+usually VGA text mode) will take over.  A few drivers (rivafb and i810fb) will
+restore VGA text mode for you.  With the rest, before detaching fbcon, you
+must take a few additional steps to make sure that your VGA text mode is
+restored properly. The following is one of the several methods that you can do:
+
+1. Download or install vbetool.  This utility is included with most
+   distributions nowadays, and is usually part of the suspend/resume tool.
+
+2. In your kernel configuration, ensure that CONFIG_FRAMEBUFFER_CONSOLE is set
+   to 'y' or 'm'. Enable one or more of your favorite framebuffer drivers.
+
+3. Boot into text mode and as root run:
+
+	vbetool vbestate save > <vga state file>
+
+	The above command saves the register contents of your graphics
+	hardware to <vga state file>.  You need to do this step only once as
+	the state file can be reused.
+
+4. If fbcon is compiled as a module, load fbcon by doing:
+
+       modprobe fbcon
+
+5. Now to detach fbcon:
+
+       vbetool vbestate restore < <vga state file> && \
+       echo 0 > /sys/class/vtconsole/vtcon1/bind
+
+6. That's it, you're back to VGA mode. And if you compiled fbcon as a module,
+   you can unload it by 'rmmod fbcon'
+
+7. To reattach fbcon:
+
+       echo 1 > /sys/class/vtconsole/vtcon1/bind
+
+8. Once fbcon is unbound, all drivers registered to the system will also
+become unbound.  This means that fbcon and individual framebuffer drivers
+can be unloaded or reloaded at will. Reloading the drivers or fbcon will
+automatically bind the console, fbcon and the drivers together. Unloading
+all the drivers without unloading fbcon will make it impossible for the
+console to bind fbcon.
+
+Notes for vesafb users:
+=======================
+
+Unfortunately, if your bootline includes a vga=xxx parameter that sets the
+hardware in graphics mode, such as when loading vesafb, vgacon will not load.
+Instead, vgacon will replace the default boot console with dummycon, and you
+won't get any display after detaching fbcon. Your machine is still alive, so
+you can reattach vesafb. However, to reattach vesafb, you need to do one of
+the following:
+
+Variation 1:
+
+    a. Before detaching fbcon, do
+
+       vbetool vbemode save > <vesa state file> # do once for each vesafb mode,
+						# the file can be reused
+
+    b. Detach fbcon as in step 5.
+
+    c. Attach fbcon
+
+        vbetool vbestate restore < <vesa state file> && \
+	echo 1 > /sys/class/vtconsole/vtcon1/bind
+
+Variation 2:
+
+    a. Before detaching fbcon, do:
+	echo <ID> > /sys/class/tty/console/bind
+
+
+       vbetool vbemode get
+
+    b. Take note of the mode number
+
+    b. Detach fbcon as in step 5.
+
+    c. Attach fbcon:
+
+       vbetool vbemode set <mode number> && \
+       echo 1 > /sys/class/vtconsole/vtcon1/bind
+
+Samples:
+========
+
+Here are 2 sample bash scripts that you can use to bind or unbind the
+framebuffer console driver if you are in an X86 box:
+
+---------------------------------------------------------------------------
+#!/bin/bash
+# Unbind fbcon
+
+# Change this to where your actual vgastate file is located
+# Or Use VGASTATE=$1 to indicate the state file at runtime
+VGASTATE=/tmp/vgastate
+
+# path to vbetool
+VBETOOL=/usr/local/bin
+
+
+for (( i = 0; i < 16; i++))
+do
+  if test -x /sys/class/vtconsole/vtcon$i; then
+      if [ `cat /sys/class/vtconsole/vtcon$i/name | grep -c "frame buffer"` \
+           = 1 ]; then
+	    if test -x $VBETOOL/vbetool; then
+	       echo Unbinding vtcon$i
+	       $VBETOOL/vbetool vbestate restore < $VGASTATE
+	       echo 0 > /sys/class/vtconsole/vtcon$i/bind
+	    fi
+      fi
+  fi
+done
+
+---------------------------------------------------------------------------
+#!/bin/bash
+# Bind fbcon
+
+for (( i = 0; i < 16; i++))
+do
+  if test -x /sys/class/vtconsole/vtcon$i; then
+      if [ `cat /sys/class/vtconsole/vtcon$i/name | grep -c "frame buffer"` \
+           = 1 ]; then
+	  echo Unbinding vtcon$i
+	  echo 1 > /sys/class/vtconsole/vtcon$i/bind
+      fi
+  fi
+done
+---------------------------------------------------------------------------
+
+--
 Antonino Daplas <adaplas@pol.net>
diff --git a/Documentation/filesystems/automount-support.txt b/Documentation/filesystems/automount-support.txt
index 58c65a1..7cac200 100644
--- a/Documentation/filesystems/automount-support.txt
+++ b/Documentation/filesystems/automount-support.txt
@@ -19,7 +19,7 @@
 
  (2) Have the follow_link() op do the following steps:
 
-     (a) Call do_kern_mount() to call the appropriate filesystem to set up a
+     (a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
          superblock and gain a vfsmount structure representing it.
 
      (b) Copy the nameidata provided as an argument and substitute the dentry
diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt
index afb1335..4aecc9b 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -113,6 +113,14 @@
 grpquota
 usrquota
 
+bh		(*)	ext3 associates buffer heads to data pages to
+nobh			(a) cache disk block mapping information
+			(b) link pages into transaction to provide
+			    ordering guarantees.
+			"bh" option forces use of buffer heads.
+			"nobh" option tries to avoid associating buffer
+			heads (supported only for "writeback" mode).
+
 
 Specification
 =============
diff --git a/Documentation/filesystems/fuse.txt b/Documentation/filesystems/fuse.txt
index 33f7431..a584f05 100644
--- a/Documentation/filesystems/fuse.txt
+++ b/Documentation/filesystems/fuse.txt
@@ -18,6 +18,14 @@
   user.  NOTE: this is not the same as mounts allowed with the "user"
   option in /etc/fstab, which is not discussed here.
 
+Filesystem connection:
+
+  A connection between the filesystem daemon and the kernel.  The
+  connection exists until either the daemon dies, or the filesystem is
+  umounted.  Note that detaching (or lazy umounting) the filesystem
+  does _not_ break the connection, in this case it will exist until
+  the last reference to the filesystem is released.
+
 Mount owner:
 
   The user who does the mounting.
@@ -86,16 +94,20 @@
   The default is infinite.  Note that the size of read requests is
   limited anyway to 32 pages (which is 128kbyte on i386).
 
-Sysfs
-~~~~~
+Control filesystem
+~~~~~~~~~~~~~~~~~~
 
-FUSE sets up the following hierarchy in sysfs:
+There's a control filesystem for FUSE, which can be mounted by:
 
-  /sys/fs/fuse/connections/N/
+  mount -t fusectl none /sys/fs/fuse/connections
 
-where N is an increasing number allocated to each new connection.
+Mounting it under the '/sys/fs/fuse/connections' directory makes it
+backwards compatible with earlier versions.
 
-For each connection the following attributes are defined:
+Under the fuse control filesystem each connection has a directory
+named by a unique number.
+
+For each connection the following files exist within this directory:
 
  'waiting'
 
@@ -110,7 +122,47 @@
   connection.  This means that all waiting requests will be aborted an
   error returned for all aborted and new requests.
 
-Only a privileged user may read or write these attributes.
+Only the owner of the mount may read or write these files.
+
+Interrupting filesystem operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If a process issuing a FUSE filesystem request is interrupted, the
+following will happen:
+
+  1) If the request is not yet sent to userspace AND the signal is
+     fatal (SIGKILL or unhandled fatal signal), then the request is
+     dequeued and returns immediately.
+
+  2) If the request is not yet sent to userspace AND the signal is not
+     fatal, then an 'interrupted' flag is set for the request.  When
+     the request has been successfully transfered to userspace and
+     this flag is set, an INTERRUPT request is queued.
+
+  3) If the request is already sent to userspace, then an INTERRUPT
+     request is queued.
+
+INTERRUPT requests take precedence over other requests, so the
+userspace filesystem will receive queued INTERRUPTs before any others.
+
+The userspace filesystem may ignore the INTERRUPT requests entirely,
+or may honor them by sending a reply to the _original_ request, with
+the error set to EINTR.
+
+It is also possible that there's a race between processing the
+original request and it's INTERRUPT request.  There are two possibilities:
+
+  1) The INTERRUPT request is processed before the original request is
+     processed
+
+  2) The INTERRUPT request is processed after the original request has
+     been answered
+
+If the filesystem cannot find the original request, it should wait for
+some timeout and/or a number of new requests to arrive, after which it
+should reply to the INTERRUPT request with an EAGAIN error.  In case
+1) the INTERRUPT request will be requeued.  In case 2) the INTERRUPT
+reply will be ignored.
 
 Aborting a filesystem connection
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -139,8 +191,8 @@
   - Use forced umount (umount -f).  Works in all cases but only if
     filesystem is still attached (it hasn't been lazy unmounted)
 
-  - Abort filesystem through the sysfs interface.  Most powerful
-    method, always works.
+  - Abort filesystem through the FUSE control filesystem.  Most
+    powerful method, always works.
 
 How do non-privileged mounts work?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -304,25 +356,7 @@
  |                                    |     for "file"]
  |                                    |    *DEADLOCK*
 
-The solution for this is to allow requests to be interrupted while
-they are in userspace:
-
- |      [interrupted by signal]       |
- |    <fuse_unlink()                  |
- |    [release semaphore]             |    [semaphore acquired]
- |  <sys_unlink()                     |
- |                                    |    >fuse_unlink()
- |                                    |      [queue req on fc->pending]
- |                                    |      [wake up fc->waitq]
- |                                    |      [sleep on req->waitq]
-
-If the filesystem daemon was single threaded, this will stop here,
-since there's no other thread to dequeue and execute the request.
-In this case the solution is to kill the FUSE daemon as well.  If
-there are multiple serving threads, you just have to kill them as
-long as any remain.
-
-Moral: a filesystem which deadlocks, can soon find itself dead.
+The solution for this is to allow the filesystem to be aborted.
 
 Scenario 2 - Tricky deadlock
 ----------------------------
@@ -355,24 +389,14 @@
  |                                    |           [lock page]
  |                                    |           * DEADLOCK *
 
-Solution is again to let the the request be interrupted (not
-elaborated further).
+Solution is basically the same as above.
 
-An additional problem is that while the write buffer is being
-copied to the request, the request must not be interrupted.  This
-is because the destination address of the copy may not be valid
-after the request is interrupted.
+An additional problem is that while the write buffer is being copied
+to the request, the request must not be interrupted/aborted.  This is
+because the destination address of the copy may not be valid after the
+request has returned.
 
-This is solved with doing the copy atomically, and allowing
-interruption while the page(s) belonging to the write buffer are
-faulted with get_user_pages().  The 'req->locked' flag indicates
-when the copy is taking place, and interruption is delayed until
-this flag is unset.
-
-Scenario 3 - Tricky deadlock with asynchronous read
----------------------------------------------------
-
-The same situation as above, except thread-1 will wait on page lock
-and hence it will be uninterruptible as well.  The solution is to
-abort the connection with forced umount (if mount is attached) or
-through the abort attribute in sysfs.
+This is solved with doing the copy atomically, and allowing abort
+while the page(s) belonging to the write buffer are faulted with
+get_user_pages().  The 'req->locked' flag indicates when the copy is
+taking place, and abort is delayed until this flag is unset.
diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
index 60ab61e..25981e2 100644
--- a/Documentation/filesystems/ramfs-rootfs-initramfs.txt
+++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
@@ -70,11 +70,13 @@
 What is rootfs?
 ---------------
 
-Rootfs is a special instance of ramfs, which is always present in 2.6 systems.
-(It's used internally as the starting and stopping point for searches of the
-kernel's doubly-linked list of mount points.)
+Rootfs is a special instance of ramfs (or tmpfs, if that's enabled), which is
+always present in 2.6 systems.  You can't unmount rootfs for approximately the
+same reason you can't kill the init process; rather than having special code
+to check for and handle an empty list, it's smaller and simpler for the kernel
+to just make sure certain lists can't become empty.
 
-Most systems just mount another filesystem over it and ignore it.  The
+Most systems just mount another filesystem over rootfs and ignore it.  The
 amount of space an empty instance of ramfs takes up is tiny.
 
 What is initramfs?
@@ -92,14 +94,16 @@
 
 All this differs from the old initrd in several ways:
 
-  - The old initrd was a separate file, while the initramfs archive is linked
-    into the linux kernel image.  (The directory linux-*/usr is devoted to
-    generating this archive during the build.)
+  - The old initrd was always a separate file, while the initramfs archive is
+    linked into the linux kernel image.  (The directory linux-*/usr is devoted
+    to generating this archive during the build.)
 
   - The old initrd file was a gzipped filesystem image (in some file format,
-    such as ext2, that had to be built into the kernel), while the new
+    such as ext2, that needed a driver built into the kernel), while the new
     initramfs archive is a gzipped cpio archive (like tar only simpler,
-    see cpio(1) and Documentation/early-userspace/buffer-format.txt).
+    see cpio(1) and Documentation/early-userspace/buffer-format.txt).  The
+    kernel's cpio extraction code is not only extremely small, it's also
+    __init data that can be discarded during the boot process.
 
   - The program run by the old initrd (which was called /initrd, not /init) did
     some setup and then returned to the kernel, while the init program from
@@ -124,13 +128,14 @@
 
 The 2.6 kernel build process always creates a gzipped cpio format initramfs
 archive and links it into the resulting kernel binary.  By default, this
-archive is empty (consuming 134 bytes on x86).  The config option
-CONFIG_INITRAMFS_SOURCE (for some reason buried under devices->block devices
-in menuconfig, and living in usr/Kconfig) can be used to specify a source for
-the initramfs archive, which will automatically be incorporated into the
-resulting binary.  This option can point to an existing gzipped cpio archive, a
-directory containing files to be archived, or a text file specification such
-as the following example:
+archive is empty (consuming 134 bytes on x86).
+
+The config option CONFIG_INITRAMFS_SOURCE (for some reason buried under
+devices->block devices in menuconfig, and living in usr/Kconfig) can be used
+to specify a source for the initramfs archive, which will automatically be
+incorporated into the resulting binary.  This option can point to an existing
+gzipped cpio archive, a directory containing files to be archived, or a text
+file specification such as the following example:
 
   dir /dev 755 0 0
   nod /dev/console 644 0 0 c 5 1
@@ -146,23 +151,84 @@
 Run "usr/gen_init_cpio" (after the kernel build) to get a usage message
 documenting the above file format.
 
-One advantage of the text file is that root access is not required to
+One advantage of the configuration file is that root access is not required to
 set permissions or create device nodes in the new archive.  (Note that those
 two example "file" entries expect to find files named "init.sh" and "busybox" in
 a directory called "initramfs", under the linux-2.6.* directory.  See
 Documentation/early-userspace/README for more details.)
 
-The kernel does not depend on external cpio tools, gen_init_cpio is created
-from usr/gen_init_cpio.c which is entirely self-contained, and the kernel's
-boot-time extractor is also (obviously) self-contained.  However, if you _do_
-happen to have cpio installed, the following command line can extract the
-generated cpio image back into its component files:
+The kernel does not depend on external cpio tools.  If you specify a
+directory instead of a configuration file, the kernel's build infrastructure
+creates a configuration file from that directory (usr/Makefile calls
+scripts/gen_initramfs_list.sh), and proceeds to package up that directory
+using the config file (by feeding it to usr/gen_init_cpio, which is created
+from usr/gen_init_cpio.c).  The kernel's build-time cpio creation code is
+entirely self-contained, and the kernel's boot-time extractor is also
+(obviously) self-contained.
+
+The one thing you might need external cpio utilities installed for is creating
+or extracting your own preprepared cpio files to feed to the kernel build
+(instead of a config file or directory).
+
+The following command line can extract a cpio image (either by the above script
+or by the kernel build) back into its component files:
 
   cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames
 
+The following shell script can create a prebuilt cpio archive you can
+use in place of the above config file:
+
+  #!/bin/sh
+
+  # Copyright 2006 Rob Landley <rob@landley.net> and TimeSys Corporation.
+  # Licensed under GPL version 2
+
+  if [ $# -ne 2 ]
+  then
+    echo "usage: mkinitramfs directory imagename.cpio.gz"
+    exit 1
+  fi
+
+  if [ -d "$1" ]
+  then
+    echo "creating $2 from $1"
+    (cd "$1"; find . | cpio -o -H newc | gzip) > "$2"
+  else
+    echo "First argument must be a directory"
+    exit 1
+  fi
+
+Note: The cpio man page contains some bad advice that will break your initramfs
+archive if you follow it.  It says "A typical way to generate the list
+of filenames is with the find command; you should give find the -depth option
+to minimize problems with permissions on directories that are unwritable or not
+searchable."  Don't do this when creating initramfs.cpio.gz images, it won't
+work.  The Linux kernel cpio extractor won't create files in a directory that
+doesn't exist, so the directory entries must go before the files that go in
+those directories.  The above script gets them in the right order.
+
+External initramfs images:
+--------------------------
+
+If the kernel has initrd support enabled, an external cpio.gz archive can also
+be passed into a 2.6 kernel in place of an initrd.  In this case, the kernel
+will autodetect the type (initramfs, not initrd) and extract the external cpio
+archive into rootfs before trying to run /init.
+
+This has the memory efficiency advantages of initramfs (no ramdisk block
+device) but the separate packaging of initrd (which is nice if you have
+non-GPL code you'd like to run from initramfs, without conflating it with
+the GPL licensed Linux kernel binary).
+
+It can also be used to supplement the kernel's built-in initamfs image.  The
+files in the external archive will overwrite any conflicting files in
+the built-in initramfs archive.  Some distributors also prefer to customize
+a single kernel image with task-specific initramfs images, without recompiling.
+
 Contents of initramfs:
 ----------------------
 
+An initramfs archive is a complete self-contained root filesystem for Linux.
 If you don't already understand what shared libraries, devices, and paths
 you need to get a minimal root filesystem up and running, here are some
 references:
@@ -176,13 +242,36 @@
 
 I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net)
 myself.  These are LGPL and GPL, respectively.  (A self-contained initramfs
-package is planned for the busybox 1.2 release.)
+package is planned for the busybox 1.3 release.)
 
 In theory you could use glibc, but that's not well suited for small embedded
 uses like this.  (A "hello world" program statically linked against glibc is
 over 400k.  With uClibc it's 7k.  Also note that glibc dlopens libnss to do
 name lookups, even when otherwise statically linked.)
 
+A good first step is to get initramfs to run a statically linked "hello world"
+program as init, and test it under an emulator like qemu (www.qemu.org) or
+User Mode Linux, like so:
+
+  cat > hello.c << EOF
+  #include <stdio.h>
+  #include <unistd.h>
+
+  int main(int argc, char *argv[])
+  {
+    printf("Hello world!\n");
+    sleep(999999999);
+  }
+  EOF
+  gcc -static hello2.c -o init
+  echo init | cpio -o -H newc | gzip > test.cpio.gz
+  # Testing external initramfs using the initrd loading mechanism.
+  qemu -kernel /boot/vmlinuz -initrd test.cpio.gz /dev/zero
+
+When debugging a normal root filesystem, it's nice to be able to boot with
+"init=/bin/sh".  The initramfs equivalent is "rdinit=/bin/sh", and it's
+just as useful.
+
 Why cpio rather than tar?
 -------------------------
 
@@ -241,7 +330,7 @@
 Future directions:
 ------------------
 
-Today (2.6.14), initramfs is always compiled in, but not always used.  The
+Today (2.6.16), initramfs is always compiled in, but not always used.  The
 kernel falls back to legacy boot code that is reached only if initramfs does
 not contain an /init program.  The fallback is legacy code, there to ensure a
 smooth transition and allowing early boot functionality to gradually move to
@@ -258,8 +347,9 @@
 
 This kind of complexity (which inevitably includes policy) is rightly handled
 in userspace.  Both klibc and busybox/uClibc are working on simple initramfs
-packages to drop into a kernel build, and when standard solutions are ready
-and widely deployed, the kernel's legacy early boot code will become obsolete
-and a candidate for the feature removal schedule.
+packages to drop into a kernel build.
 
-But that's a while off yet.
+The klibc package has now been accepted into Andrew Morton's 2.6.17-mm tree.
+The kernel's current early boot code (partition detection, etc) will probably
+be migrated into a default initramfs, automatically created and used by the
+kernel build.
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index a9c00fa..14ef3868 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -1123,6 +1123,14 @@
 	$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE).  The user may
 	override this value on the command line if desired.
 
+    INSTALL_MOD_STRIP
+
+	If this variable is specified, will cause modules to be stripped
+	after they are installed.  If INSTALL_MOD_STRIP is '1', then the
+	default option --strip-debug will be used.  Otherwise,
+	INSTALL_MOD_STRIP will used as the option(s) to the strip command.
+
+
 === 8 Makefile language
 
 The kernel Makefiles are designed to run with GNU Make.  The Makefiles
diff --git a/Documentation/kdump/gdbmacros.txt b/Documentation/kdump/gdbmacros.txt
index dcf5580..9b9b454 100644
--- a/Documentation/kdump/gdbmacros.txt
+++ b/Documentation/kdump/gdbmacros.txt
@@ -175,7 +175,7 @@
 document trapinfo
 	Run info threads and lookup pid of thread #1
 	'trapinfo <pid>' will tell you by which trap & possibly
-	addresthe kernel paniced.
+	address the kernel panicked.
 end
 
 
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 212cf3c..08bafa8 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -1,155 +1,325 @@
-Documentation for kdump - the kexec-based crash dumping solution
+================================================================
+Documentation for Kdump - The kexec-based Crash Dumping Solution
 ================================================================
 
-DESIGN
-======
+This document includes overview, setup and installation, and analysis
+information.
 
-Kdump uses kexec to reboot to a second kernel whenever a dump needs to be
-taken. This second kernel is booted with very little memory. The first kernel
-reserves the section of memory that the second kernel uses. This ensures that
-on-going DMA from the first kernel does not corrupt the second kernel.
+Overview
+========
 
-All the necessary information about Core image is encoded in ELF format and
-stored in reserved area of memory before crash. Physical address of start of
-ELF header is passed to new kernel through command line parameter elfcorehdr=.
+Kdump uses kexec to quickly boot to a dump-capture kernel whenever a
+dump of the system kernel's memory needs to be taken (for example, when
+the system panics). The system kernel's memory image is preserved across
+the reboot and is accessible to the dump-capture kernel.
 
-On i386, the first 640 KB of physical memory is needed to boot, irrespective
-of where the kernel loads. Hence, this region is backed up by kexec just before
-rebooting into the new kernel.
+You can use common Linux commands, such as cp and scp, to copy the
+memory image to a dump file on the local disk, or across the network to
+a remote system.
 
-In the second kernel, "old memory" can be accessed in two ways.
+Kdump and kexec are currently supported on the x86, x86_64, and ppc64
+architectures.
 
-- The first one is through a /dev/oldmem device interface. A capture utility
-  can read the device file and write out the memory in raw format. This is raw
-  dump of memory and analysis/capture tool should be intelligent enough to
-  determine where to look for the right information. ELF headers (elfcorehdr=)
-  can become handy here.
+When the system kernel boots, it reserves a small section of memory for
+the dump-capture kernel. This ensures that ongoing Direct Memory Access
+(DMA) from the system kernel does not corrupt the dump-capture kernel.
+The kexec -p command loads the dump-capture kernel into this reserved
+memory.
 
-- The second interface is through /proc/vmcore. This exports the dump as an ELF
-  format file which can be written out using any file copy command
-  (cp, scp, etc). Further, gdb can be used to perform limited debugging on
-  the dump file. This method ensures methods ensure that there is correct
-  ordering of the dump pages (corresponding to the first 640 KB that has been
-  relocated).
+On x86 machines, the first 640 KB of physical memory is needed to boot,
+regardless of where the kernel loads. Therefore, kexec backs up this
+region just before rebooting into the dump-capture kernel.
 
-SETUP
-=====
+All of the necessary information about the system kernel's core image is
+encoded in the ELF format, and stored in a reserved area of memory
+before a crash. The physical address of the start of the ELF header is
+passed to the dump-capture kernel through the elfcorehdr= boot
+parameter.
 
-1) Download the upstream kexec-tools userspace package from
-   http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz.
+With the dump-capture kernel, you can access the memory image, or "old
+memory," in two ways:
 
-   Apply the latest consolidated kdump patch on top of kexec-tools-1.101
-   from http://lse.sourceforge.net/kdump/. This arrangment has been made
-   till all the userspace patches supporting kdump are integrated with
-   upstream kexec-tools userspace.
+- Through a /dev/oldmem device interface. A capture utility can read the
+  device file and write out the memory in raw format. This is a raw dump
+  of memory. Analysis and capture tools must be intelligent enough to
+  determine where to look for the right information.
 
-2) Download and build the appropriate (2.6.13-rc1 onwards) vanilla kernels.
-   Two kernels need to be built in order to get this feature working.
-   Following are the steps to properly configure the two kernels specific
-   to kexec and kdump features:
-
-  A) First kernel or regular kernel:
-  ----------------------------------
-   a) Enable "kexec system call" feature (in Processor type and features).
-      CONFIG_KEXEC=y
-   b) Enable "sysfs file system support" (in Pseudo filesystems).
-      CONFIG_SYSFS=y
-   c) make
-   d) Boot into first kernel with the command line parameter "crashkernel=Y@X".
-      Use appropriate values for X and Y. Y denotes how much memory to reserve
-      for the second kernel, and X denotes at what physical address the
-      reserved memory section starts. For example: "crashkernel=64M@16M".
+- Through /proc/vmcore. This exports the dump as an ELF-format file that
+  you can write out using file copy commands such as cp or scp. Further,
+  you can use analysis tools such as the GNU Debugger (GDB) and the Crash
+  tool to debug the dump file. This method ensures that the dump pages are
+  correctly ordered.
 
 
-  B) Second kernel or dump capture kernel:
-  ---------------------------------------
-   a) For i386 architecture enable Highmem support
-      CONFIG_HIGHMEM=y
-   b) Enable "kernel crash dumps" feature (under "Processor type and features")
-      CONFIG_CRASH_DUMP=y
-   c) Make sure a suitable value for "Physical address where the kernel is
-      loaded" (under "Processor type and features"). By default this value
-      is 0x1000000 (16MB) and it should be same as X (See option d above),
-      e.g., 16 MB or 0x1000000.
-      CONFIG_PHYSICAL_START=0x1000000
-   d) Enable "/proc/vmcore support" (Optional, under "Pseudo filesystems").
-      CONFIG_PROC_VMCORE=y
+Setup and Installation
+======================
 
-3) After booting to regular kernel or first kernel, load the second kernel
-   using the following command:
+Install kexec-tools and the Kdump patch
+---------------------------------------
 
-   kexec -p <second-kernel> --args-linux --elf32-core-headers
-   --append="root=<root-dev> init 1 irqpoll maxcpus=1"
+1) Login as the root user.
 
-   Notes:
-   ======
-     i) <second-kernel> has to be a vmlinux image ie uncompressed elf image.
-        bzImage will not work, as of now.
-    ii) --args-linux has to be speicfied as if kexec it loading an elf image,
-        it needs to know that the arguments supplied are of linux type.
-   iii) By default ELF headers are stored in ELF64 format to support systems
-        with more than 4GB memory. Option --elf32-core-headers forces generation
-        of ELF32 headers. The reason for this option being, as of now gdb can
-        not open vmcore file with ELF64 headers on a 32 bit systems. So ELF32
-        headers can be used if one has non-PAE systems and hence memory less
-        than 4GB.
-    iv) Specify "irqpoll" as command line parameter. This reduces driver
-         initialization failures in second kernel due to shared interrupts.
-     v) <root-dev> needs to be specified in a format corresponding to the root
-        device name in the output of mount command.
-    vi) If you have built the drivers required to mount root file system as
-        modules in <second-kernel>, then, specify
-        --initrd=<initrd-for-second-kernel>.
-   vii) Specify maxcpus=1 as, if during first kernel run, if panic happens on
-        non-boot cpus, second kernel doesn't seem to be boot up all the cpus.
-        The other option is to always built the second kernel without SMP
-        support ie CONFIG_SMP=n
+2) Download the kexec-tools user-space package from the following URL:
 
-4) After successfully loading the second kernel as above, if a panic occurs
-   system reboots into the second kernel. A module can be written to force
-   the panic or "ALT-SysRq-c" can be used initiate a crash dump for testing
-   purposes.
+   http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
 
-5) Once the second kernel has booted, write out the dump file using
+3) Unpack the tarball with the tar command, as follows:
+
+   tar xvpzf kexec-tools-1.101.tar.gz
+
+4) Download the latest consolidated Kdump patch from the following URL:
+
+   http://lse.sourceforge.net/kdump/
+
+   (This location is being used until all the user-space Kdump patches
+   are integrated with the kexec-tools package.)
+
+5) Change to the kexec-tools-1.101 directory, as follows:
+
+   cd kexec-tools-1.101
+
+6) Apply the consolidated patch to the kexec-tools-1.101 source tree
+   with the patch command, as follows. (Modify the path to the downloaded
+   patch as necessary.)
+
+   patch -p1 < /path-to-kdump-patch/kexec-tools-1.101-kdump.patch
+
+7) Configure the package, as follows:
+
+   ./configure
+
+8) Compile the package, as follows:
+
+   make
+
+9) Install the package, as follows:
+
+   make install
+
+
+Download and build the system and dump-capture kernels
+------------------------------------------------------
+
+Download the mainline (vanilla) kernel source code (2.6.13-rc1 or newer)
+from http://www.kernel.org. Two kernels must be built: a system kernel
+and a dump-capture kernel. Use the following steps to configure these
+kernels with the necessary kexec and Kdump features:
+
+System kernel
+-------------
+
+1) Enable "kexec system call" in "Processor type and features."
+
+   CONFIG_KEXEC=y
+
+2) Enable "sysfs file system support" in "Filesystem" -> "Pseudo
+   filesystems." This is usually enabled by default.
+
+   CONFIG_SYSFS=y
+
+   Note that "sysfs file system support" might not appear in the "Pseudo
+   filesystems" menu if "Configure standard kernel features (for small
+   systems)" is not enabled in "General Setup." In this case, check the
+   .config file itself to ensure that sysfs is turned on, as follows:
+
+   grep 'CONFIG_SYSFS' .config
+
+3) Enable "Compile the kernel with debug info" in "Kernel hacking."
+
+   CONFIG_DEBUG_INFO=Y
+
+   This causes the kernel to be built with debug symbols. The dump
+   analysis tools require a vmlinux with debug symbols in order to read
+   and analyze a dump file.
+
+4) Make and install the kernel and its modules. Update the boot loader
+   (such as grub, yaboot, or lilo) configuration files as necessary.
+
+5) Boot the system kernel with the boot parameter "crashkernel=Y@X",
+   where Y specifies how much memory to reserve for the dump-capture kernel
+   and X specifies the beginning of this reserved memory. For example,
+   "crashkernel=64M@16M" tells the system kernel to reserve 64 MB of memory
+   starting at physical address 0x01000000 for the dump-capture kernel.
+
+   On x86 and x86_64, use "crashkernel=64M@16M".
+
+   On ppc64, use "crashkernel=128M@32M".
+
+
+The dump-capture kernel
+-----------------------
+
+1) Under "General setup," append "-kdump" to the current string in
+   "Local version."
+
+2) On x86, enable high memory support under "Processor type and
+   features":
+
+   CONFIG_HIGHMEM64G=y
+   or
+   CONFIG_HIGHMEM4G
+
+3) On x86 and x86_64, disable symmetric multi-processing support
+   under "Processor type and features":
+
+   CONFIG_SMP=n
+   (If CONFIG_SMP=y, then specify maxcpus=1 on the kernel command line
+   when loading the dump-capture kernel, see section "Load the Dump-capture
+   Kernel".)
+
+4) On ppc64, disable NUMA support and enable EMBEDDED support:
+
+   CONFIG_NUMA=n
+   CONFIG_EMBEDDED=y
+   CONFIG_EEH=N for the dump-capture kernel
+
+5) Enable "kernel crash dumps" support under "Processor type and
+   features":
+
+   CONFIG_CRASH_DUMP=y
+
+6) Use a suitable value for "Physical address where the kernel is
+   loaded" (under "Processor type and features"). This only appears when
+   "kernel crash dumps" is enabled. By default this value is 0x1000000
+   (16MB). It should be the same as X in the "crashkernel=Y@X" boot
+   parameter discussed above.
+
+   On x86 and x86_64, use "CONFIG_PHYSICAL_START=0x1000000".
+
+   On ppc64 the value is automatically set at 32MB when
+   CONFIG_CRASH_DUMP is set.
+
+6) Optionally enable "/proc/vmcore support" under "Filesystems" ->
+   "Pseudo filesystems".
+
+   CONFIG_PROC_VMCORE=y
+   (CONFIG_PROC_VMCORE is set by default when CONFIG_CRASH_DUMP is selected.)
+
+7) Make and install the kernel and its modules. DO NOT add this kernel
+   to the boot loader configuration files.
+
+
+Load the Dump-capture Kernel
+============================
+
+After booting to the system kernel, load the dump-capture kernel using
+the following command:
+
+   kexec -p <dump-capture-kernel> \
+   --initrd=<initrd-for-dump-capture-kernel> --args-linux \
+   --append="root=<root-dev> init 1 irqpoll"
+
+
+Notes on loading the dump-capture kernel:
+
+* <dump-capture-kernel> must be a vmlinux image (that is, an
+  uncompressed ELF image). bzImage does not work at this time.
+
+* By default, the ELF headers are stored in ELF64 format to support
+  systems with more than 4GB memory. The --elf32-core-headers option can
+  be used to force the generation of ELF32 headers. This is necessary
+  because GDB currently cannot open vmcore files with ELF64 headers on
+  32-bit systems. ELF32 headers can be used on non-PAE systems (that is,
+  less than 4GB of memory).
+
+* The "irqpoll" boot parameter reduces driver initialization failures
+  due to shared interrupts in the dump-capture kernel.
+
+* You must specify <root-dev> in the format corresponding to the root
+  device name in the output of mount command.
+
+* "init 1" boots the dump-capture kernel into single-user mode without
+  networking. If you want networking, use "init 3."
+
+
+Kernel Panic
+============
+
+After successfully loading the dump-capture kernel as previously
+described, the system will reboot into the dump-capture kernel if a
+system crash is triggered.  Trigger points are located in panic(),
+die(), die_nmi() and in the sysrq handler (ALT-SysRq-c).
+
+The following conditions will execute a crash trigger point:
+
+If a hard lockup is detected and "NMI watchdog" is configured, the system
+will boot into the dump-capture kernel ( die_nmi() ).
+
+If die() is called, and it happens to be a thread with pid 0 or 1, or die()
+is called inside interrupt context or die() is called and panic_on_oops is set,
+the system will boot into the dump-capture kernel.
+
+On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system system will boot into the dump-capture kernel.
+
+For testing purposes, you can trigger a crash by using "ALT-SysRq-c",
+"echo c > /proc/sysrq-trigger or write a module to force the panic.
+
+Write Out the Dump File
+=======================
+
+After the dump-capture kernel is booted, write out the dump file with
+the following command:
 
    cp /proc/vmcore <dump-file>
 
-   Dump memory can also be accessed as a /dev/oldmem device for a linear/raw
-   view.  To create the device, type:
+You can also access dumped memory as a /dev/oldmem device for a linear
+and raw view. To create the device, use the following command:
 
-   mknod /dev/oldmem c 1 12
+    mknod /dev/oldmem c 1 12
 
-   Use "dd" with suitable options for count, bs and skip to access specific
-   portions of the dump.
+Use the dd command with suitable options for count, bs, and skip to
+access specific portions of the dump.
 
-   Entire memory:  dd if=/dev/oldmem of=oldmem.001
+To see the entire memory, use the following command:
+
+   dd if=/dev/oldmem of=oldmem.001
 
 
-ANALYSIS
+Analysis
 ========
-Limited analysis can be done using gdb on the dump file copied out of
-/proc/vmcore. Use vmlinux built with -g and run
 
-  gdb vmlinux <dump-file>
+Before analyzing the dump image, you should reboot into a stable kernel.
 
-Stack trace for the task on processor 0, register display, memory display
-work fine.
+You can do limited analysis using GDB on the dump file copied out of
+/proc/vmcore. Use the debug vmlinux built with -g and run the following
+command:
 
-Note: gdb cannot analyse core files generated in ELF64 format for i386.
+   gdb vmlinux <dump-file>
 
-Latest "crash" (crash-4.0-2.18) as available on Dave Anderson's site
-http://people.redhat.com/~anderson/ works well with kdump format.
+Stack trace for the task on processor 0, register display, and memory
+display work fine.
+
+Note: GDB cannot analyze core files generated in ELF64 format for x86.
+On systems with a maximum of 4GB of memory, you can generate
+ELF32-format headers using the --elf32-core-headers kernel option on the
+dump kernel.
+
+You can also use the Crash utility to analyze dump files in Kdump
+format. Crash is available on Dave Anderson's site at the following URL:
+
+   http://people.redhat.com/~anderson/
 
 
-TODO
-====
-1) Provide a kernel pages filtering mechanism so that core file size is not
-   insane on systems having huge memory banks.
-2) Relocatable kernel can help in maintaining multiple kernels for crashdump
-   and same kernel as the first kernel can be used to capture the dump.
+To Do
+=====
+
+1) Provide a kernel pages filtering mechanism, so core file size is not
+   extreme on systems with huge memory banks.
+
+2) Relocatable kernel can help in maintaining multiple kernels for
+   crash_dump, and the same kernel as the system kernel can be used to
+   capture the dump.
 
 
-CONTACT
+Contact
 =======
+
 Vivek Goyal (vgoyal@in.ibm.com)
 Maneesh Soni (maneesh@in.ibm.com)
+
+
+Trademark
+=========
+
+Linux is a trademark of Linus Torvalds in the United States, other
+countries, or both.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bca6f38..2e352a6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -61,6 +61,7 @@
 	MTD	MTD support is enabled.
 	NET	Appropriate network support is enabled.
 	NUMA	NUMA support is enabled.
+	GENERIC_TIME The generic timeofday code is enabled.
 	NFS	Appropriate NFS support is enabled.
 	OSS	OSS sound support is enabled.
 	PARIDE	The ParIDE subsystem is enabled.
@@ -179,6 +180,11 @@
 			override platform specific driver.
 			See also Documentation/acpi-hotkey.txt.
 
+	acpi_pm_good	[IA-32,X86-64]
+			Override the pmtimer bug detection: force the kernel
+			to assume that this machine's pmtimer latches its value
+			and always returns good values.
+
 	enable_timer_pin_1 [i386,x86-64]
 			Enable PIN 1 of APIC timer
 			Can be useful to work around chipset bugs
@@ -341,10 +347,11 @@
 			Value can be changed at runtime via
 				/selinux/checkreqprot.
 
- 	clock=		[BUGS=IA-32,HW] gettimeofday timesource override.
-			Forces specified timesource (if avaliable) to be used
-			when calculating gettimeofday(). If specicified
-			timesource is not avalible, it defaults to PIT.
+	clock=		[BUGS=IA-32, HW] gettimeofday clocksource override.
+			[Deprecated]
+			Forces specified clocksource (if avaliable) to be used
+			when calculating gettimeofday(). If specified
+			clocksource is not avalible, it defaults to PIT.
 			Format: { pit | tsc | cyclone | pmtmr }
 
 	disable_8254_timer
@@ -1617,6 +1624,10 @@
 
 	time		Show timing data prefixed to each printk message line
 
+	clocksource=	[GENERIC_TIME] Override the default clocksource
+			Override the default clocksource and use the clocksource
+			with the name specified.
+
 	tipar.timeout=	[HW,PPT]
 			Set communications timeout in tenths of a second
 			(default 15).
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index 3bbe157..61c0fad 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -241,25 +241,30 @@
 controls can be applied to keys created within various contexts.  This support
 is preliminary, and is likely to change quite significantly in the near future.
 Currently, all of the basic permissions explained above are provided in SELinux
-as well; SE Linux is simply invoked after all basic permission checks have been
+as well; SELinux is simply invoked after all basic permission checks have been
 performed.
 
-Each key is labeled with the same context as the task to which it belongs.
-Typically, this is the same task that was running when the key was created.
-The default keyrings are handled differently, but in a way that is very
-intuitive:
+The value of the file /proc/self/attr/keycreate influences the labeling of
+newly-created keys.  If the contents of that file correspond to an SELinux
+security context, then the key will be assigned that context.  Otherwise, the
+key will be assigned the current context of the task that invoked the key
+creation request.  Tasks must be granted explicit permission to assign a
+particular context to newly-created keys, using the "create" permission in the
+key security class.
 
- (*) The user and user session keyrings that are created when the user logs in
-     are currently labeled with the context of the login manager.
-
- (*) The keyrings associated with new threads are each labeled with the context
-     of their associated thread, and both session and process keyrings are
-     handled similarly.
+The default keyrings associated with users will be labeled with the default
+context of the user if and only if the login programs have been instrumented to
+properly initialize keycreate during the login process.  Otherwise, they will
+be labeled with the context of the login program itself.
 
 Note, however, that the default keyrings associated with the root user are
 labeled with the default kernel context, since they are created early in the
 boot process, before root has a chance to log in.
 
+The keyrings associated with new threads are each labeled with the context of
+their associated thread, and both session and process keyrings are handled
+similarly.
+
 
 ================
 NEW PROCFS FILES
@@ -270,9 +275,17 @@
 
  (*) /proc/keys
 
-     This lists all the keys on the system, giving information about their
-     type, description and permissions. The payload of the key is not available
-     this way:
+     This lists the keys that are currently viewable by the task reading the
+     file, giving information about their type, description and permissions.
+     It is not possible to view the payload of the key this way, though some
+     information about it may be given.
+
+     The only keys included in the list are those that grant View permission to
+     the reading process whether or not it possesses them.  Note that LSM
+     security checks are still performed, and may further filter out keys that
+     the current process is not authorised to view.
+
+     The contents of the file look like this:
 
 	SERIAL   FLAGS  USAGE EXPY PERM     UID   GID   TYPE      DESCRIPTION: SUMMARY
 	00000001 I-----    39 perm 1f3f0000     0     0 keyring   _uid_ses.0: 1/4
@@ -300,7 +313,7 @@
  (*) /proc/key-users
 
      This file lists the tracking data for each user that has at least one key
-     on the system. Such data includes quota information and statistics:
+     on the system.  Such data includes quota information and statistics:
 
 	[root@andromeda root]# cat /proc/key-users
 	0:     46 45/45 1/100 13/10000
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 03a13c4..0668f9d 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -200,6 +200,17 @@
      This can be written only while the array is being assembled, not
      after it is started.
 
+  layout
+     The "layout" for the array for the particular level.  This is
+     simply a number that is interpretted differently by different
+     levels.  It can be written while assembling an array.
+
+  resync_start
+     The point at which resync should start.  If no resync is needed,
+     this will be a very large number.  At array creation it will
+     default to 0, though starting the array as 'clean' will
+     set it much larger.
+
    new_dev
      This file can be written but not read.  The value written should
      be a block device number as major:minor.  e.g. 8:0
@@ -207,6 +218,54 @@
      available.  It will then appear at md/dev-XXX (depending on the
      name of the device) and further configuration is then possible.
 
+   safe_mode_delay
+     When an md array has seen no write requests for a certain period
+     of time, it will be marked as 'clean'.  When another write
+     request arrive, the array is marked as 'dirty' before the write
+     commenses.  This is known as 'safe_mode'.
+     The 'certain period' is controlled by this file which stores the
+     period as a number of seconds.  The default is 200msec (0.200).
+     Writing a value of 0 disables safemode.
+
+   array_state
+     This file contains a single word which describes the current
+     state of the array.  In many cases, the state can be set by
+     writing the word for the desired state, however some states
+     cannot be explicitly set, and some transitions are not allowed.
+
+     clear
+         No devices, no size, no level
+         Writing is equivalent to STOP_ARRAY ioctl
+     inactive
+         May have some settings, but array is not active
+            all IO results in error
+         When written, doesn't tear down array, but just stops it
+     suspended (not supported yet)
+         All IO requests will block. The array can be reconfigured.
+         Writing this, if accepted, will block until array is quiessent
+     readonly
+         no resync can happen.  no superblocks get written.
+         write requests fail
+     read-auto
+         like readonly, but behaves like 'clean' on a write request.
+
+     clean - no pending writes, but otherwise active.
+         When written to inactive array, starts without resync
+         If a write request arrives then
+           if metadata is known, mark 'dirty' and switch to 'active'.
+           if not known, block and switch to write-pending
+         If written to an active array that has pending writes, then fails.
+     active
+         fully active: IO and resync can be happening.
+         When written to inactive array, starts with resync
+
+     write-pending
+         clean, but writes are blocked waiting for 'active' to be written.
+
+     active-idle
+         like active, but no writes have been seen for a while (safe_mode_delay).
+
+
    sync_speed_min
    sync_speed_max
      This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
@@ -250,10 +309,18 @@
 	      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
+	      writemostly - device will only be subject to read
+		         requests if there are no other options.
+			 This applies only to raid1 arrays.
 	      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.
+	This can be written to.
+	Writing "faulty"  simulates a failure on the device.
+	Writing "remove" removes the device from the array.
+	Writing "writemostly" sets the writemostly flag.
+	Writing "-writemostly" clears the writemostly flag.
 
       errors
 	An approximate count of read errors that have been detected on
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 4710845..cf0d541 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -262,9 +262,14 @@
 CPU to restrict the order.
 
 Memory barriers are such interventions.  They impose a perceived partial
-ordering between the memory operations specified on either side of the barrier.
-They request that the sequence of memory events generated appears to other
-parts of the system as if the barrier is effective on that CPU.
+ordering over the memory operations on either side of the barrier.
+
+Such enforcement is important because the CPUs and other devices in a system
+can use a variety of tricks to improve performance - including reordering,
+deferral and combination of memory operations; speculative loads; speculative
+branch prediction and various types of caching.  Memory barriers are used to
+override or suppress these tricks, allowing the code to sanely control the
+interaction of multiple CPUs and/or devices.
 
 
 VARIETIES OF MEMORY BARRIER
@@ -282,7 +287,7 @@
      A write barrier is a partial ordering on stores only; it is not required
      to have any effect on loads.
 
-     A CPU can be viewed as as commiting a sequence of store operations to the
+     A CPU can be viewed as committing a sequence of store operations to the
      memory system as time progresses.  All stores before a write barrier will
      occur in the sequence _before_ all the stores after the write barrier.
 
@@ -413,7 +418,7 @@
      indirect effect will be the order in which the second CPU sees the effects
      of the first CPU's accesses occur, but see the next point:
 
- (*) There is no guarantee that the a CPU will see the correct order of effects
+ (*) There is no guarantee that a CPU will see the correct order of effects
      from a second CPU's accesses, even _if_ the second CPU uses a memory
      barrier, unless the first CPU _also_ uses a matching memory barrier (see
      the subsection on "SMP Barrier Pairing").
@@ -461,8 +466,8 @@
 isn't, and this behaviour can be observed on certain real CPUs (such as the DEC
 Alpha).
 
-To deal with this, a data dependency barrier must be inserted between the
-address load and the data load:
+To deal with this, a data dependency barrier or better must be inserted
+between the address load and the data load:
 
 	CPU 1		CPU 2
 	===============	===============
@@ -484,7 +489,7 @@
 variable B might be stored in an even-numbered cache line.  Then, if the
 even-numbered bank of the reading CPU's cache is extremely busy while the
 odd-numbered bank is idle, one can see the new value of the pointer P (&B),
-but the old value of the variable B (1).
+but the old value of the variable B (2).
 
 
 Another example of where data dependency barriers might by required is where a
@@ -744,7 +749,7 @@
 	                                        :       :
 
 
-If, however, a read barrier were to be placed between the load of E and the
+If, however, a read barrier were to be placed between the load of B and the
 load of A on CPU 2:
 
 	CPU 1			CPU 2
@@ -1461,9 +1466,8 @@
 
 On a UP system - where this wouldn't be a problem - the smp_mb() is just a
 compiler barrier, thus making sure the compiler emits the instructions in the
-right order without actually intervening in the CPU.  Since there there's only
-one CPU, that CPU's dependency ordering logic will take care of everything
-else.
+right order without actually intervening in the CPU.  Since there's only one
+CPU, that CPU's dependency ordering logic will take care of everything else.
 
 
 ATOMIC OPERATIONS
@@ -1640,9 +1644,9 @@
 
      The PCI bus, amongst others, defines an I/O space concept - which on such
      CPUs as i386 and x86_64 cpus readily maps to the CPU's concept of I/O
-     space.  However, it may also mapped as a virtual I/O space in the CPU's
-     memory map, particularly on those CPUs that don't support alternate
-     I/O spaces.
+     space.  However, it may also be mapped as a virtual I/O space in the CPU's
+     memory map, particularly on those CPUs that don't support alternate I/O
+     spaces.
 
      Accesses to this space may be fully synchronous (as on i386), but
      intermediary bridges (such as the PCI host bridge) may not fully honour
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 95d17b3..2a58f98 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -44,8 +44,10 @@
 Programming and/or enabling interrupt frequencies greater than 64Hz is
 only allowed by root. This is perhaps a bit conservative, but we don't want
 an evil user generating lots of IRQs on a slow 386sx-16, where it might have
-a negative impact on performance.  Note that the interrupt handler is only
-a few lines of code to minimize any possibility of this effect.
+a negative impact on performance. This 64Hz limit can be changed by writing
+a different value to /proc/sys/dev/rtc/max-user-freq. Note that the
+interrupt handler is only a few lines of code to minimize any possibility
+of this effect.
 
 Also, if the kernel time is synchronized with an external source, the 
 kernel will write the time back to the CMOS clock every 11 minutes. In 
@@ -81,6 +83,7 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <linux/rtc.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
diff --git a/Documentation/scsi/ppa.txt b/Documentation/scsi/ppa.txt
index 0dac88d..5d9223b 100644
--- a/Documentation/scsi/ppa.txt
+++ b/Documentation/scsi/ppa.txt
@@ -12,5 +12,3 @@
 Email list for Linux Parport
 linux-parport@torque.net
 
-Email for problems with ZIP or ZIP Plus drivers
-campbell@torque.net
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index ad0bedf..e0188a2 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -115,8 +115,9 @@
 when you would try to login. It will kill all programs on given console
 and thus letting you make sure that the login prompt you see is actually
 the one from init, not some trojan program.
-IMPORTANT:In its true form it is not a true SAK like the one in   :IMPORTANT
-IMPORTANT:c2 compliant systems, and it should be mistook as such. :IMPORTANT
+IMPORTANT: In its true form it is not a true SAK like the one in a :IMPORTANT
+IMPORTANT: c2 compliant system, and it should not be mistaken as   :IMPORTANT
+IMPORTANT: such.                                                   :IMPORTANT
        It seems other find it useful as (System Attention Key) which is
 useful when you want to exit a program that will not let you switch consoles.
 (For example, X or a svgalib program.)
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
index 8ff7bc2..dab5660 100644
--- a/Documentation/tty.txt
+++ b/Documentation/tty.txt
@@ -80,13 +80,6 @@
 			for processing. Semantics currently rather
 			mysterious 8(
 
-receive_room()	-	Can be called by the driver layer at any time when
-			the ldisc is opened. The ldisc must be able to
-			handle the reported amount of data at that instant.
-			Synchronization between active receive_buf and
-			receive_room calls is down to the driver not the
-			ldisc. Must not sleep.
-
 write_wakeup()	-	May be called at any point between open and close.
 			The TTY_DO_WRITE_WAKEUP flag indicates if a call
 			is needed but always races versus calls. Thus the
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index b72706c..4efa464 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -87,7 +87,7 @@
  86 -> Osprey 101/151 w/ svid
  87 -> Osprey 200/201/250/251
  88 -> Osprey 200/250                                      [0070:ff01]
- 89 -> Osprey 210/220
+ 89 -> Osprey 210/220/230
  90 -> Osprey 500                                          [0070:ff02]
  91 -> Osprey 540                                          [0070:ff04]
  92 -> Osprey 2000                                         [0070:ff03]
@@ -111,7 +111,7 @@
 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]
+113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00,1822:0026]
 114 -> Winfast VC100                                       [107d:6607]
 115 -> Teppro TEV-560/InterVision IV-560
 116 -> SIMUS GVC1100                                       [aa6a:82b2]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 3b39a91..6cb63dd 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -15,7 +15,7 @@
  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]
+ 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810,18ac:d800]
  18 -> Hauppauge Nova-T DVB-T                              [0070:9002,0070:9001]
  19 -> Conexant DVB-T reference design                     [14f1:0187]
  20 -> Provideo PV259                                      [1540:2580]
@@ -40,8 +40,13 @@
  39 -> KWorld DVB-S 100                                    [17de:08b2]
  40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid                [0070:9400,0070:9402]
  41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)  [0070:9800,0070:9802]
- 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
+ 42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025,1822:0019]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
  45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
  46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
+ 47 -> pcHDTV HD5500 HDTV                                  [7063:5500]
+ 48 -> Kworld MCE 200 Deluxe                               [17de:0841]
+ 49 -> PixelView PlayTV P7000                              [1554:4813]
+ 50 -> NPG Tech Real TV FM Top 10                          [14f1:0842]
+ 51 -> WinFast DTV2000 H                                   [107d:665e]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index bca5090..9068b66 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -93,3 +93,4 @@
  92 -> AVerMedia A169 B1                        [1461:6360]
  93 -> Medion 7134 Bridge #2                    [16be:0005]
  94 -> LifeView FlyDVB-T Hybrid Cardbus         [5168:3306,5168:3502]
+ 95 -> LifeView FlyVIDEO3000 (NTSC)             [5169:0138]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 1bcdac6..44134f0 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -62,7 +62,7 @@
 tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
 tuner=62 - Philips TEA5767HN FM Radio
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
-tuner=64 - LG TDVS-H062F/TUA6034
+tuner=64 - LG TDVS-H06xF
 tuner=65 - Ymec TVF66T5-B/DFF
 tuner=66 - LG TALN series
 tuner=67 - Philips TD1316 Hybrid Tuner
@@ -71,3 +71,4 @@
 tuner=70 - Samsung TCPN 2121P30A
 tuner=71 - Xceive xc3028
 tuner=72 - Thomson FE6600
+tuner=73 - Samsung TCPG 6121P30A
diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt
index 464e4ce..ade8651 100644
--- a/Documentation/video4linux/CQcam.txt
+++ b/Documentation/video4linux/CQcam.txt
@@ -185,207 +185,10 @@
 
 9.0 --- A sample program using v4lgrabber,
 
-This program is a simple image grabber that will copy a frame from the
+v4lgrab is a simple image grabber that will copy a frame from the
 first video device, /dev/video0 to standard output in portable pixmap
-format (.ppm)  Using this like: 'v4lgrab | convert - c-qcam.jpg'
-produced this picture of me at
-    http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
-
--------------------- 8< ---------------- 8< -----------------------------
-
-/* Simple Video4Linux image grabber. */
-/*
- *	Video4Linux Driver Test/Example Framegrabbing Program
- *
- *	Compile with:
- *		gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
- *      Use as:
- *              v4lgrab >image.ppm
- *
- *	Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
- *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
- *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
- *
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-
-#include <linux/types.h>
-#include <linux/videodev.h>
-
-#define FILE "/dev/video0"
-
-/* Stole this from tvset.c */
-
-#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
-{                                                                       \
-	switch (format)                                                 \
-	{                                                               \
-		case VIDEO_PALETTE_GREY:                                \
-			switch (depth)                                  \
-			{                                               \
-				case 4:                                 \
-				case 6:                                 \
-				case 8:                                 \
-					(r) = (g) = (b) = (*buf++ << 8);\
-					break;                          \
-									\
-				case 16:                                \
-					(r) = (g) = (b) =               \
-						*((unsigned short *) buf);      \
-					buf += 2;                       \
-					break;                          \
-			}                                               \
-			break;                                          \
-									\
-									\
-		case VIDEO_PALETTE_RGB565:                              \
-		{                                                       \
-			unsigned short tmp = *(unsigned short *)buf;    \
-			(r) = tmp&0xF800;                               \
-			(g) = (tmp<<5)&0xFC00;                          \
-			(b) = (tmp<<11)&0xF800;                         \
-			buf += 2;                                       \
-		}                                                       \
-		break;                                                  \
-									\
-		case VIDEO_PALETTE_RGB555:                              \
-			(r) = (buf[0]&0xF8)<<8;                         \
-			(g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
-			(b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
-			buf += 2;                                       \
-			break;                                          \
-									\
-		case VIDEO_PALETTE_RGB24:                               \
-			(r) = buf[0] << 8; (g) = buf[1] << 8;           \
-			(b) = buf[2] << 8;                              \
-			buf += 3;                                       \
-			break;                                          \
-									\
-		default:                                                \
-			fprintf(stderr,                                 \
-				"Format %d not yet supported\n",        \
-				format);                                \
-	}                                                               \
-}
-
-int get_brightness_adj(unsigned char *image, long size, int *brightness) {
-  long i, tot = 0;
-  for (i=0;i<size*3;i++)
-    tot += image[i];
-  *brightness = (128 - tot/(size*3))/3;
-  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
-}
-
-int main(int argc, char ** argv)
-{
-  int fd = open(FILE, O_RDONLY), f;
-  struct video_capability cap;
-  struct video_window win;
-  struct video_picture vpic;
-
-  unsigned char *buffer, *src;
-  int bpp = 24, r, g, b;
-  unsigned int i, src_depth;
-
-  if (fd < 0) {
-    perror(FILE);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
-    perror("VIDIOGCAP");
-    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
-    close(fd);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
-    perror("VIDIOCGWIN");
-    close(fd);
-    exit(1);
-  }
-
-  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
-    perror("VIDIOCGPICT");
-    close(fd);
-    exit(1);
-  }
-
-  if (cap.type & VID_TYPE_MONOCHROME) {
-    vpic.depth=8;
-    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
-    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-      vpic.depth=6;
-      if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-	vpic.depth=4;
-	if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-	  fprintf(stderr, "Unable to find a supported capture format.\n");
-	  close(fd);
-	  exit(1);
-	}
-      }
-    }
-  } else {
-    vpic.depth=24;
-    vpic.palette=VIDEO_PALETTE_RGB24;
-
-    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
-      vpic.palette=VIDEO_PALETTE_RGB565;
-      vpic.depth=16;
-
-      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-	vpic.palette=VIDEO_PALETTE_RGB555;
-	vpic.depth=15;
-
-	if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-	  fprintf(stderr, "Unable to find a supported capture format.\n");
-	  return -1;
-	}
-      }
-    }
-  }
-
-  buffer = malloc(win.width * win.height * bpp);
-  if (!buffer) {
-    fprintf(stderr, "Out of memory.\n");
-    exit(1);
-  }
-
-  do {
-    int newbright;
-    read(fd, buffer, win.width * win.height * bpp);
-    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
-    if (f) {
-      vpic.brightness += (newbright << 8);
-      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
-	perror("VIDIOSPICT");
-	break;
-      }
-    }
-  } while (f);
-
-  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
-
-  src = buffer;
-
-  for (i = 0; i < win.width * win.height; i++) {
-    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
-    fputc(r>>8, stdout);
-    fputc(g>>8, stdout);
-    fputc(b>>8, stdout);
-  }
-
-  close(fd);
-  return 0;
-}
--------------------- 8< ---------------- 8< -----------------------------
+format (.ppm)  To produce .jpg output, you can use it like this:
+'v4lgrab | convert - c-qcam.jpg'
 
 
 10.0 --- Other Information
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index be9f21b..040a2c8 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -33,6 +33,21 @@
 Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
 Card number: 7
 
+AverMedia 6 Eyes AVS6EYES:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Samsung ks0127 TV decoder
+* Conexant bt866  TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+		videocodec, ks0127, bt866, zr36060, zr36067
+Inputs/outputs: Six physical inputs. 1-6 are composite,
+		1-2, 3-4, 5-6 doubles as S-video,
+		1-3 triples as component.
+		One composite output.
+Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 8
+Not autodetected, card=8 is necessary.
+
 Linux Media Labs LML33:
 * Zoran zr36067 PCI controller
 * Zoran zr36060 MJPEG codec
@@ -192,6 +207,10 @@
 was introduced in 1996, is used in the DC30 and DC30+ and
 can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb
 
+Samsung ks0127 TV decoder
+is used in the AVS6EYES card and
+can handle: NTSC-M/N/44, PAL-M/N/B/G/H/I/D/K/L and SECAM
+
 ===========================
 
 1.2 What the TV encoder can do an what not
@@ -221,6 +240,10 @@
 was introduced in 1991, is used in the DC10 old
 can generate: PAL , NTSC , SECAM
 
+Conexant bt866 TV encoder
+is used in AVS6EYES, and
+can generate: NTSC/PAL, PAL­M, PAL­N
+
 The adv717x, should be able to produce PAL N. But you find nothing PAL N
 specific in the registers. Seem that you have to reuse a other standard
 to generate PAL N, maybe it would work if you use the PAL M settings.
diff --git a/Documentation/video4linux/bttv/CONTRIBUTORS b/Documentation/video4linux/bttv/CONTRIBUTORS
index aef49db..8aad6dd 100644
--- a/Documentation/video4linux/bttv/CONTRIBUTORS
+++ b/Documentation/video4linux/bttv/CONTRIBUTORS
@@ -1,4 +1,4 @@
-Contributors to bttv: 
+Contributors to bttv:
 
 Michael Chu <mmchu@pobox.com>
   AverMedia fix and more flexible card recognition
@@ -8,8 +8,8 @@
 
 Chris Kleitsch
   Hardware I2C
-  
-Gerd Knorr <kraxel@cs.tu-berlin.de> 
+
+Gerd Knorr <kraxel@cs.tu-berlin.de>
   Radio card (ITT sound processor)
 
 bigfoot <bigfoot@net-way.net>
@@ -18,7 +18,7 @@
 
 
 + many more (please mail me if you are missing in this list and would
-             like to be mentioned)
+	     like to be mentioned)
 
 
 
diff --git a/Documentation/video4linux/cx2341x/fw-calling.txt b/Documentation/video4linux/cx2341x/fw-calling.txt
new file mode 100644
index 0000000..8d21181
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-calling.txt
@@ -0,0 +1,69 @@
+This page describes how to make calls to the firmware api.
+
+How to call
+===========
+
+The preferred calling convention is known as the firmware mailbox. The
+mailboxes are basically a fixed length array that serves as the call-stack.
+
+Firmware mailboxes can be located by searching the encoder and decoder memory
+for a 16 byte signature. That signature will be located on a 256-byte boundary.
+
+Signature:
+0x78, 0x56, 0x34, 0x12, 0x12, 0x78, 0x56, 0x34,
+0x34, 0x12, 0x78, 0x56, 0x56, 0x34, 0x12, 0x78
+
+The firmware implements 20 mailboxes of 20 32-bit words. The first 10 are
+reserved for API calls. The second 10 are used by the firmware for event
+notification.
+
+  Index  Name
+  -----  ----
+  0      Flags
+  1      Command
+  2      Return value
+  3      Timeout
+  4-19   Parameter/Result
+
+
+The flags are defined in the following table. The direction is from the
+perspective of the firmware.
+
+  Bit  Direction  Purpose
+  ---  ---------  -------
+  2    O          Firmware has processed the command.
+  1    I          Driver has finished setting the parameters.
+  0    I          Driver is using this mailbox.
+
+
+The command is a 32-bit enumerator. The API specifics may be found in the
+fw-*-api.txt documents.
+
+The return value is a 32-bit enumerator. Only two values are currently defined:
+0=success and -1=command undefined.
+
+There are 16 parameters/results 32-bit fields. The driver populates these fields
+with values for all the parameters required by the call. The driver overwrites
+these fields with result values returned by the call. The API specifics may be
+found in the fw-*-api.txt documents.
+
+The timeout value protects the card from a hung driver thread. If the driver
+doesn't handle the completed call within the timeout specified, the firmware
+will reset that mailbox.
+
+To make an API call, the driver iterates over each mailbox looking for the
+first one available (bit 0 has been cleared). The driver sets that bit, fills
+in the command enumerator, the timeout value and any required parameters. The
+driver then sets the parameter ready bit (bit 1). The firmware scans the
+mailboxes for pending commands, processes them, sets the result code, populates
+the result value array with that call's return values and sets the call
+complete bit (bit 2). Once bit 2 is set, the driver should retrieve the results
+and clear all the flags. If the driver does not perform this task within the
+time set in the timeout register, the firmware will reset that mailbox.
+
+Event notifications are sent from the firmware to the host. The host tells the
+firmware which events it is interested in via an API call. That call tells the
+firmware which notification mailbox to use. The firmware signals the host via
+an interrupt. Only the 16 Results fields are used, the Flags, Command, Return
+value and Timeout words are not used.
+
diff --git a/Documentation/video4linux/cx2341x/fw-decoder-api.txt b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
new file mode 100644
index 0000000..9df4fb3
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
@@ -0,0 +1,319 @@
+Decoder firmware API description
+================================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_PING_FW
+Enum 	0/0x00
+Description
+	This API call does nothing. It may be used to check if the firmware
+	is responding.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_START_PLAYBACK
+Enum 	1/0x01
+Description
+	Begin or resume playback.
+Param[0]
+	0 based frame number in GOP to begin playback from.
+Param[1]
+	Specifies the number of muted audio frames to play before normal
+	audio resumes.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_STOP_PLAYBACK
+Enum 	2/0x02
+Description
+	Ends playback and clears all decoder buffers. If PTS is not zero,
+	playback stops at specified PTS.
+Param[0]
+	Display 0=last frame, 1=black
+Param[1]
+	PTS low
+Param[2]
+	PTS high
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_PLAYBACK_SPEED
+Enum 	3/0x03
+Description
+	Playback stream at speed other than normal. There are two modes of
+	operation:
+	    Smooth: host transfers entire stream and firmware drops unused
+		    frames.
+	    Coarse: host drops frames based on indexing as required to achieve
+		    desired speed.
+Param[0]
+	Bitmap:
+	    0:7  0 normal
+		 1 fast only "1.5 times"
+		 n nX fast, 1/nX slow
+	    30   Framedrop:
+		     '0' during 1.5 times play, every other B frame is dropped
+		     '1' during 1.5 times play, stream is unchanged (bitrate
+			 must not exceed 8mbps)
+	    31   Speed:
+		     '0' slow
+		     '1' fast
+Param[1]
+	Direction: 0=forward, 1=reverse
+Param[2]
+	Picture mask:
+	    1=I frames
+	    3=I, P frames
+	    7=I, P, B frames
+Param[3]
+	B frames per GOP (for reverse play only)
+Param[4]
+	Mute audio: 0=disable, 1=enable
+Param[5]
+	Display 0=frame, 1=field
+Param[6]
+	Specifies the number of muted audio frames to play before normal audio
+	resumes.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_STEP_VIDEO
+Enum 	5/0x05
+Description
+	Each call to this API steps the playback to the next unit defined below
+	in the current playback direction.
+Param[0]
+	0=frame, 1=top field, 2=bottom field
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_DMA_BLOCK_SIZE
+Enum 	8/0x08
+Description
+	Set DMA transfer block size. Counterpart to API 0xC9
+Param[0]
+	DMA transfer block size in bytes. A different size may be specified
+	when issuing the DMA transfer command.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_XFER_INFO
+Enum 	9/0x09
+Description
+	This API call may be used to detect an end of stream condtion.
+Result[0]
+	Stream type
+Result[1]
+	Address offset
+Result[2]
+	Maximum bytes to transfer
+Result[3]
+	Buffer fullness
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_DMA_STATUS
+Enum 	10/0x0A
+Description
+	Status of the last DMA transfer
+Result[0]
+	Bit 1 set means transfer complete
+	Bit 2 set means DMA error
+	Bit 3 set means linked list error
+Result[1]
+	DMA type: 0=MPEG, 1=OSD, 2=YUV
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SCHED_DMA_FROM_HOST
+Enum 	11/0x0B
+Description
+	Setup DMA from host operation. Counterpart to API 0xCC
+Param[0]
+	Memory address of link list
+Param[1]
+	Total # of bytes to transfer
+Param[2]
+	DMA type (0=MPEG, 1=OSD, 2=YUV)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_PAUSE_PLAYBACK
+Enum 	13/0x0D
+Description
+	Freeze playback immediately. In this mode, when internal buffers are
+	full, no more data will be accepted and data request IRQs will be
+	masked.
+Param[0]
+	Display: 0=last frame, 1=black
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_HALT_FW
+Enum 	14/0x0E
+Description
+	The firmware is halted and no further API calls are serviced until
+	the firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_STANDARD
+Enum 	16/0x10
+Description
+	Selects display standard
+Param[0]
+	0=NTSC, 1=PAL
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_VERSION
+Enum 	17/0x11
+Description
+	Returns decoder firmware version information
+Result[0]
+	Version bitmask:
+	    Bits  0:15 build
+	    Bits 16:23 minor
+	    Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_STREAM_INPUT
+Enum 	20/0x14
+Description
+	Select decoder stream input port
+Param[0]
+	0=memory (default), 1=streaming
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_GET_TIMING_INFO
+Enum 	21/0x15
+Description
+	Returns timing information from start of playback
+Result[0]
+	Frame count by decode order
+Result[1]
+	Video PTS bits 0:31 by display order
+Result[2]
+	Video PTS bit 32 by display order
+Result[3]
+	SCR bits 0:31 by display order
+Result[4]
+	SCR bit 32 by display order
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_AUDIO_MODE
+Enum 	22/0x16
+Description
+	Select audio mode
+Param[0]
+	Dual mono mode action
+Param[1]
+	Stereo mode action:
+	    0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_EVENT_NOTIFICATION
+Enum 	23/0x17
+Description
+	Setup firmware to notify the host about a particular event.
+	Counterpart to API 0xD5
+Param[0]
+	Event: 0=Audio mode change between stereo and dual channel
+Param[1]
+	Notification 0=disabled, 1=enabled
+Param[2]
+	Interrupt bit
+Param[3]
+	Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_DISPLAY_BUFFERS
+Enum 	24/0x18
+Description
+	Number of display buffers. To decode all frames in reverse playback you
+	must use nine buffers.
+Param[0]
+	0=six buffers, 1=nine buffers
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_EXTRACT_VBI
+Enum 	25/0x19
+Description
+	Extracts VBI data
+Param[0]
+	0=extract from extension & user data, 1=extract from private packets
+Result[0]
+	VBI table location
+Result[1]
+	VBI table size
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_DECODER_SOURCE
+Enum 	26/0x1A
+Description
+	Selects decoder source. Ensure that the parameters passed to this
+	API match the encoder settings.
+Param[0]
+	Mode: 0=MPEG from host, 1=YUV from encoder, 2=YUV from host
+Param[1]
+	YUV picture width
+Param[2]
+	YUV picture height
+Param[3]
+	Bitmap: see Param[0] of API 0xBD
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_AUDIO_OUTPUT
+Enum 	27/0x1B
+Description
+	Select audio output format
+Param[0]
+	Bitmask:
+	     0:1  Data size:
+		      '00' 16 bit
+		      '01' 20 bit
+		      '10' 24 bit
+	     2:7  Unused
+	     8:9  Mode:
+		      '00' 2 channels
+		      '01' 4 channels
+		      '10' 6 channels
+		      '11' 6 channels with one line data mode
+			   (for left justified MSB first mode, 20 bit only)
+	    10:11 Unused
+	    12:13 Channel format:
+		      '00' right justified MSB first mode
+		      '01' left justified MSB first mode
+		      '10' I2S mode
+	    14:15 Unused
+	    16:21 Right justify bit count
+	    22:31 Unused
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_AV_DELAY
+Enum 	28/0x1C
+Description
+	Set audio/video delay in 90Khz ticks
+Param[0]
+	0=A/V in sync, negative=audio lags, positive=video lags
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_DEC_SET_PREBUFFERING
+Enum 	30/0x1E
+Description
+	Decoder prebuffering, when enabled up to 128KB are buffered for
+	streams <8mpbs or 640KB for streams >8mbps
+Param[0]
+	0=off, 1=on
diff --git a/Documentation/video4linux/cx2341x/fw-dma.txt b/Documentation/video4linux/cx2341x/fw-dma.txt
new file mode 100644
index 0000000..8123e26
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-dma.txt
@@ -0,0 +1,94 @@
+This page describes the structures and procedures used by the cx2341x DMA
+engine.
+
+Introduction
+============
+
+The cx2341x PCI interface is busmaster capable. This means it has a DMA
+engine to efficiently transfer large volumes of data between the card and main
+memory without requiring help from a CPU. Like most hardware, it must operate
+on contiguous physical memory. This is difficult to come by in large quantities
+on virtual memory machines.
+
+Therefore, it also supports a technique called "scatter-gather". The card can
+transfer multiple buffers in one operation. Instead of allocating one large
+contiguous buffer, the driver can allocate several smaller buffers.
+
+In practice, I've seen the average transfer to be roughly 80K, but transfers
+above 128K were not uncommon, particularly at startup. The 128K figure is
+important, because that is the largest block that the kernel can normally
+allocate. Even still, 128K blocks are hard to come by, so the driver writer is
+urged to choose a smaller block size and learn the scatter-gather technique.
+
+Mailbox #10 is reserved for DMA transfer information.
+
+Flow
+====
+
+This section describes, in general, the order of events when handling DMA
+transfers. Detailed information follows this section.
+
+- The card raises the Encoder interrupt.
+- The driver reads the transfer type, offset and size from Mailbox #10.
+- The driver constructs the scatter-gather array from enough free dma buffers
+  to cover the size.
+- The driver schedules the DMA transfer via the ScheduleDMAtoHost API call.
+- The card raises the DMA Complete interrupt.
+- The driver checks the DMA status register for any errors.
+- The driver post-processes the newly transferred buffers.
+
+NOTE! It is possible that the Encoder and DMA Complete interrupts get raised
+simultaneously. (End of the last, start of the next, etc.)
+
+Mailbox #10
+===========
+
+The Flags, Command, Return Value and Timeout fields are ignored.
+
+Name:       Mailbox #10
+Results[0]: Type: 0: MPEG.
+Results[1]: Offset: The position relative to the card's memory space.
+Results[2]: Size: The exact number of bytes to transfer.
+
+My speculation is that since the StartCapture API has a capture type of "RAW"
+available, that the type field will have other values that correspond to YUV
+and PCM data.
+
+Scatter-Gather Array
+====================
+
+The scatter-gather array is a contiguously allocated block of memory that
+tells the card the source and destination of each data-block to transfer.
+Card "addresses" are derived from the offset supplied by Mailbox #10. Host
+addresses are the physical memory location of the target DMA buffer.
+
+Each S-G array element is a struct of three 32-bit words. The first word is
+the source address, the second is the destination address. Both take up the
+entire 32 bits. The lowest 16 bits of the third word is the transfer byte
+count. The high-bit of the third word is the "last" flag. The last-flag tells
+the card to raise the DMA_DONE interrupt. From hard personal experience, if
+you forget to set this bit, the card will still "work" but the stream will
+most likely get corrupted.
+
+The transfer count must be a multiple of 256. Therefore, the driver will need
+to track how much data in the target buffer is valid and deal with it
+accordingly.
+
+Array Element:
+
+- 32-bit Source Address
+- 32-bit Destination Address
+- 16-bit reserved (high bit is the last flag)
+- 16-bit byte count
+
+DMA Transfer Status
+===================
+
+Register 0x0004 holds the DMA Transfer Status:
+
+Bit
+4   Scatter-Gather array error
+3   DMA write error
+2   DMA read error
+1   write completed
+0   read completed
diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
new file mode 100644
index 0000000..001c686
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
@@ -0,0 +1,694 @@
+Encoder firmware API description
+================================
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_PING_FW
+Enum 	128/0x80
+Description
+	Does nothing. Can be used to check if the firmware is responding.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_START_CAPTURE
+Enum 	129/0x81
+Description
+	Commences the capture of video, audio and/or VBI data. All encoding
+	parameters must be initialized prior to this API call. Captures frames
+	continuously or until a predefined number of frames have been captured.
+Param[0]
+	Capture stream type:
+	    0=MPEG
+	    1=Raw
+	    2=Raw passthrough
+	    3=VBI
+
+Param[1]
+	Bitmask:
+	    Bit 0 when set, captures YUV
+	    Bit 1 when set, captures PCM audio
+	    Bit 2 when set, captures VBI (same as param[0]=3)
+	    Bit 3 when set, the capture destination is the decoder
+		(same as param[0]=2)
+	    Bit 4 when set, the capture destination is the host
+	Note: this parameter is only meaningful for RAW capture type.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_STOP_CAPTURE
+Enum 	130/0x82
+Description
+	Ends a capture in progress
+Param[0]
+	0=stop at end of GOP (generates IRQ)
+	1=stop immediate (no IRQ)
+Param[1]
+	Stream type to stop, see param[0] of API 0x81
+Param[2]
+	Subtype, see param[1] of API 0x81
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_AUDIO_ID
+Enum 	137/0x89
+Description
+	Assigns the transport stream ID of the encoded audio stream
+Param[0]
+	Audio Stream ID
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_VIDEO_ID
+Enum 	139/0x8B
+Description
+	Set video transport stream ID
+Param[0]
+	Video stream ID
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_PCR_ID
+Enum 	141/0x8D
+Description
+	Assigns the transport stream ID for PCR packets
+Param[0]
+	PCR Stream ID
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_FRAME_RATE
+Enum 	143/0x8F
+Description
+	Set video frames per second. Change occurs at start of new GOP.
+Param[0]
+	0=30fps
+	1=25fps
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_FRAME_SIZE
+Enum 	145/0x91
+Description
+	Select video stream encoding resolution.
+Param[0]
+	Height in lines. Default 480
+Param[1]
+	Width in pixels. Default 720
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_BIT_RATE
+Enum 	149/0x95
+Description
+	Assign average video stream bitrate. Note on the last three params:
+	Param[3] and [4] seem to be always 0, param [5] doesn't seem to be used.
+Param[0]
+	0=variable bitrate, 1=constant bitrate
+Param[1]
+	bitrate in bits per second
+Param[2]
+	peak bitrate in bits per second, divided by 400
+Param[3]
+	Mux bitrate in bits per second, divided by 400. May be 0 (default).
+Param[4]
+	Rate Control VBR Padding
+Param[5]
+	VBV Buffer used by encoder
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_GOP_PROPERTIES
+Enum 	151/0x97
+Description
+	Setup the GOP structure
+Param[0]
+	GOP size (maximum is 34)
+Param[1]
+	Number of B frames between the I and P frame, plus 1.
+	For example: IBBPBBPBBPBB --> GOP size: 12, number of B frames: 2+1 = 3
+	Note that GOP size must be a multiple of (B-frames + 1).
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_ASPECT_RATIO
+Enum 	153/0x99
+Description
+	Sets the encoding aspect ratio. Changes in the aspect ratio take effect
+	at the start of the next GOP.
+Param[0]
+	'0000' forbidden
+	'0001' 1:1 square
+	'0010' 4:3
+	'0011' 16:9
+	'0100' 2.21:1
+	'0101' reserved
+	 ....
+	'1111' reserved
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_DNR_FILTER_MODE
+Enum 	155/0x9B
+Description
+	Assign Dynamic Noise Reduction operating mode
+Param[0]
+	Bit0: Spatial filter, set=auto, clear=manual
+	Bit1: Temporal filter, set=auto, clear=manual
+Param[1]
+	Median filter:
+	    0=Disabled
+	    1=Horizontal
+	    2=Vertical
+	    3=Horiz/Vert
+	    4=Diagonal
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_DNR_FILTER_PROPS
+Enum 	157/0x9D
+Description
+	These Dynamic Noise Reduction filter values are only meaningful when
+	the respective filter is set to "manual" (See API 0x9B)
+Param[0]
+	Spatial filter: default 0, range 0:15
+Param[1]
+	Temporal filter: default 0, range 0:31
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_CORING_LEVELS
+Enum 	159/0x9F
+Description
+	Assign Dynamic Noise Reduction median filter properties.
+Param[0]
+	Threshold above which the luminance median filter is enabled.
+	Default: 0, range 0:255
+Param[1]
+	Threshold below which the luminance median filter is enabled.
+	Default: 255, range 0:255
+Param[2]
+	Threshold above which the chrominance median filter is enabled.
+	Default: 0, range 0:255
+Param[3]
+	Threshold below which the chrominance median filter is enabled.
+	Default: 255, range 0:255
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
+Enum 	161/0xA1
+Description
+	Assign spatial prefilter parameters
+Param[0]
+	Luminance filter
+	    0=Off
+	    1=1D Horizontal
+	    2=1D Vertical
+	    3=2D H/V Separable (default)
+	    4=2D Symmetric non-separable
+Param[1]
+	Chrominance filter
+	    0=Off
+	    1=1D Horizontal (default)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_3_2_PULLDOWN
+Enum 	177/0xB1
+Description
+	3:2 pulldown properties
+Param[0]
+	0=enabled
+	1=disabled
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_VBI_LINE
+Enum 	183/0xB7
+Description
+	Selects VBI line number.
+Param[0]
+	Bits 0:4 	line number
+	Bit  31		0=top_field, 1=bottom_field
+	Bits 0:31 	all set specifies "all lines"
+Param[1]
+	VBI line information features: 0=disabled, 1=enabled
+Param[2]
+	Slicing: 0=None, 1=Closed Caption
+	Almost certainly not implemented. Set to 0.
+Param[3]
+	Luminance samples in this line.
+	Almost certainly not implemented. Set to 0.
+Param[4]
+	Chrominance samples in this line
+	Almost certainly not implemented. Set to 0.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_STREAM_TYPE
+Enum 	185/0xB9
+Description
+	Assign stream type
+	Note: Transport stream is not working in recent firmwares.
+	And in older firmwares the timestamps in the TS seem to be
+	unreliable.
+Param[0]
+	 0=Program stream
+	 1=Transport stream
+	 2=MPEG1 stream
+	 3=PES A/V stream
+	 5=PES Video stream
+	 7=PES Audio stream
+	10=DVD stream
+	11=VCD stream
+	12=SVCD stream
+	13=DVD_S1 stream
+	14=DVD_S2 stream
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_OUTPUT_PORT
+Enum 	187/0xBB
+Description
+	Assign stream output port. Normally 0 when the data is copied through
+	the PCI bus (DMA), and 1 when the data is streamed to another chip
+	(pvrusb and cx88-blackbird).
+Param[0]
+	0=Memory (default)
+	1=Streaming
+	2=Serial
+Param[1]
+	Unknown, but leaving this to 0 seems to work best. Indications are that
+	this might have to do with USB support, although passing anything but 0
+	onl breaks things.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_AUDIO_PROPERTIES
+Enum 	189/0xBD
+Description
+	Set audio stream properties, may be called while encoding is in progress.
+	Note: all bitfields are consistent with ISO11172 documentation except
+	bits 2:3 which ISO docs define as:
+		'11' Layer I
+		'10' Layer II
+		'01' Layer III
+		'00' Undefined
+	This discrepancy may indicate a possible error in the documentation.
+	Testing indicated that only Layer II is actually working, and that
+	the minimum bitrate should be 192 kbps.
+Param[0]
+	Bitmask:
+	   0:1  '00' 44.1Khz
+		'01' 48Khz
+		'10' 32Khz
+		'11' reserved
+
+	   2:3  '01'=Layer I
+		'10'=Layer II
+
+	   4:7  Bitrate:
+		     Index | Layer I     | Layer II
+		     ------+-------------+------------
+		    '0000' | free format | free format
+		    '0001' |  32 kbit/s  |  32 kbit/s
+		    '0010' |  64 kbit/s  |  48 kbit/s
+		    '0011' |  96 kbit/s  |  56 kbit/s
+		    '0100' | 128 kbit/s  |  64 kbit/s
+		    '0101' | 160 kbit/s  |  80 kbit/s
+		    '0110' | 192 kbit/s  |  96 kbit/s
+		    '0111' | 224 kbit/s  | 112 kbit/s
+		    '1000' | 256 kbit/s  | 128 kbit/s
+		    '1001' | 288 kbit/s  | 160 kbit/s
+		    '1010' | 320 kbit/s  | 192 kbit/s
+		    '1011' | 352 kbit/s  | 224 kbit/s
+		    '1100' | 384 kbit/s  | 256 kbit/s
+		    '1101' | 416 kbit/s  | 320 kbit/s
+		    '1110' | 448 kbit/s  | 384 kbit/s
+		Note: For Layer II, not all combinations of total bitrate
+		and mode are allowed. See ISO11172-3 3-Annex B, Table 3-B.2
+
+	   8:9  '00'=Stereo
+		'01'=JointStereo
+		'10'=Dual
+		'11'=Mono
+		Note: testing seems to indicate that Mono and possibly
+		JointStereo are not working (default to stereo).
+		Dual does work, though.
+
+	  10:11 Mode Extension used in joint_stereo mode.
+		In Layer I and II they indicate which subbands are in
+		intensity_stereo. All other subbands are coded in stereo.
+		    '00' subbands 4-31 in intensity_stereo, bound==4
+		    '01' subbands 8-31 in intensity_stereo, bound==8
+		    '10' subbands 12-31 in intensity_stereo, bound==12
+		    '11' subbands 16-31 in intensity_stereo, bound==16
+
+	  12:13 Emphasis:
+		    '00' None
+		    '01' 50/15uS
+		    '10' reserved
+		    '11' CCITT J.17
+
+	  14 	CRC:
+		    '0' off
+		    '1' on
+
+	  15    Copyright:
+		    '0' off
+		    '1' on
+
+	  16    Generation:
+		    '0' copy
+		    '1' original
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_HALT_FW
+Enum 	195/0xC3
+Description
+	The firmware is halted and no further API calls are serviced until the
+	firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_VERSION
+Enum 	196/0xC4
+Description
+	Returns the version of the encoder firmware.
+Result[0]
+	Version bitmask:
+	    Bits  0:15 build
+	    Bits 16:23 minor
+	    Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_GOP_CLOSURE
+Enum 	197/0xC5
+Description
+	Assigns the GOP open/close property.
+Param[0]
+	0=Open
+	1=Closed
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_SEQ_END
+Enum 	198/0xC6
+Description
+	Obtains the sequence end code of the encoder's buffer. When a capture
+	is started a number of interrupts are still generated, the last of
+	which will have Result[0] set to 1 and Result[1] will contain the size
+	of the buffer.
+Result[0]
+	State of the transfer (1 if last buffer)
+Result[1]
+	If Result[0] is 1, this contains the size of the last buffer, undefined
+	otherwise.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_PGM_INDEX_INFO
+Enum 	199/0xC7
+Description
+	Sets the Program Index Information.
+Param[0]
+	Picture Mask:
+	    0=No index capture
+	    1=I frames
+	    3=I,P frames
+	    7=I,P,B frames
+Param[1]
+	Elements requested (up to 400)
+Result[0]
+	Offset in SDF memory of the table.
+Result[1]
+	Number of allocated elements up to a maximum of Param[1]
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_VBI_CONFIG
+Enum 	200/0xC8
+Description
+	Configure VBI settings
+Param[0]
+	Bitmap:
+	    0    Mode '0' Sliced, '1' Raw
+	    1:3  Insertion:
+		     '000' insert in extension & user data
+		     '001' insert in private packets
+		     '010' separate stream and user data
+		     '111' separate stream and private data
+	    8:15 Stream ID (normally 0xBD)
+Param[1]
+	Frames per interrupt (max 8). Only valid in raw mode.
+Param[2]
+	Total raw VBI frames. Only valid in raw mode.
+Param[3]
+	Start codes
+Param[4]
+	Stop codes
+Param[5]
+	Lines per frame
+Param[6]
+	Byte per line
+Result[0]
+	Observed frames per interrupt in raw mode only. Rage 1 to Param[1]
+Result[1]
+	Observed number of frames in raw mode. Range 1 to Param[2]
+Result[2]
+	Memory offset to start or raw VBI data
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_DMA_BLOCK_SIZE
+Enum 	201/0xC9
+Description
+	Set DMA transfer block size
+Param[0]
+	DMA transfer block size in bytes or frames. When unit is bytes,
+	supported block sizes are 2^7, 2^8 and 2^9 bytes.
+Param[1]
+	Unit: 0=bytes, 1=frames
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_PREV_DMA_INFO_MB_10
+Enum 	202/0xCA
+Description
+	Returns information on the previous DMA transfer in conjunction with
+	bit 27 of the interrupt mask. Uses mailbox 10.
+Result[0]
+	Type of stream
+Result[1]
+	Address Offset
+Result[2]
+	Maximum size of transfer
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_GET_PREV_DMA_INFO_MB_9
+Enum 	203/0xCB
+Description
+	Returns information on the previous DMA transfer in conjunction with
+	bit 27 of the interrupt mask. Uses mailbox 9.
+Result[0]
+	Status bits:
+	    Bit 0 set indicates transfer complete
+	    Bit 2 set indicates transfer error
+	    Bit 4 set indicates linked list error
+Result[1]
+	DMA type
+Result[2]
+	Presentation Time Stamp bits 0..31
+Result[3]
+	Presentation Time Stamp bit 32
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SCHED_DMA_TO_HOST
+Enum 	204/0xCC
+Description
+	Setup DMA to host operation
+Param[0]
+	Memory address of link list
+Param[1]
+	Length of link list (wtf: what units ???)
+Param[2]
+	DMA type (0=MPEG)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_INITIALIZE_INPUT
+Enum 	205/0xCD
+Description
+	Initializes the video input
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_FRAME_DROP_RATE
+Enum 	208/0xD0
+Description
+	For each frame captured, skip specified number of frames.
+Param[0]
+	Number of frames to skip
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_PAUSE_ENCODER
+Enum 	210/0xD2
+Description
+	During a pause condition, all frames are dropped instead of being encoded.
+Param[0]
+	0=Pause encoding
+	1=Continue encoding
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_REFRESH_INPUT
+Enum 	211/0xD3
+Description
+	Refreshes the video input
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_COPYRIGHT
+Enum 	212/0xD4
+Description
+	Sets stream copyright property
+Param[0]
+	0=Stream is not copyrighted
+	1=Stream is copyrighted
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_EVENT_NOTIFICATION
+Enum 	213/0xD5
+Description
+	Setup firmware to notify the host about a particular event. Host must
+	unmask the interrupt bit.
+Param[0]
+	Event (0=refresh encoder input)
+Param[1]
+	Notification 0=disabled 1=enabled
+Param[2]
+	Interrupt bit
+Param[3]
+	Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_NUM_VSYNC_LINES
+Enum 	214/0xD6
+Description
+	Depending on the analog video decoder used, this assigns the number
+	of lines for field 1 and 2.
+Param[0]
+	Field 1 number of lines:
+	    0x00EF for SAA7114
+	    0x00F0 for SAA7115
+	    0x0105 for Micronas
+Param[1]
+	Field 2 number of lines:
+	    0x00EF for SAA7114
+	    0x00F0 for SAA7115
+	    0x0106 for Micronas
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_SET_PLACEHOLDER
+Enum 	215/0xD7
+Description
+	Provides a mechanism of inserting custom user data in the MPEG stream.
+Param[0]
+	0=extension & user data
+	1=private packet with stream ID 0xBD
+Param[1]
+	Rate at which to insert data, in units of frames (for private packet)
+	or GOPs (for ext. & user data)
+Param[2]
+	Number of data DWORDs (below) to insert
+Param[3]
+	Custom data 0
+Param[4]
+	Custom data 1
+Param[5]
+	Custom data 2
+Param[6]
+	Custom data 3
+Param[7]
+	Custom data 4
+Param[8]
+	Custom data 5
+Param[9]
+	Custom data 6
+Param[10]
+	Custom data 7
+Param[11]
+	Custom data 8
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_MUTE_VIDEO
+Enum 	217/0xD9
+Description
+	Video muting
+Param[0]
+	Bit usage:
+	 0    	'0'=video not muted
+		'1'=video muted, creates frames with the YUV color defined below
+	 1:7  	Unused
+	 8:15 	V chrominance information
+	16:23 	U chrominance information
+	24:31 	Y luminance information
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_MUTE_AUDIO
+Enum 	218/0xDA
+Description
+	Audio muting
+Param[0]
+	0=audio not muted
+	1=audio muted (produces silent mpeg audio stream)
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_UNKNOWN
+Enum 	219/0xDB
+Description
+	Unknown API, it's used by Hauppauge though.
+Param[0]
+	0 This is the value Hauppauge uses, Unknown what it means.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_ENC_MISC
+Enum 	220/0xDC
+Description
+	Miscellaneous actions. Not known for 100% what it does. It's really a
+	sort of ioctl call. The first parameter is a command number, the second
+	the value.
+Param[0]
+	Command number:
+	 1=set initial SCR value when starting encoding.
+	 2=set quality mode (apparently some test setting).
+	 3=setup advanced VIM protection handling (supposedly only for the cx23416
+	   for raw YUV).
+	   Actually it looks like this should be 0 for saa7114/5 based card and 1
+	   for cx25840 based cards.
+	 4=generate artificial PTS timestamps
+	 5=USB flush mode
+	 6=something to do with the quantization matrix
+	 7=set navigation pack insertion for DVD
+	 8=enable scene change detection (seems to be a failure)
+	 9=set history parameters of the video input module
+	10=set input field order of VIM
+	11=set quantization matrix
+	12=reset audio interface
+	13=set audio volume delay
+	14=set audio delay
+
+Param[1]
+	Command value.
diff --git a/Documentation/video4linux/cx2341x/fw-memory.txt b/Documentation/video4linux/cx2341x/fw-memory.txt
new file mode 100644
index 0000000..ef0aad3
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-memory.txt
@@ -0,0 +1,141 @@
+This document describes the cx2341x memory map and documents some of the register
+space.
+
+Warning! This information was figured out from searching through the memory and
+registers, this information may not be correct and is certainly not complete, and
+was not derived from anything more than searching through the memory space with
+commands like:
+
+	ivtvctl -O min=0x02000000,max=0x020000ff
+
+So take this as is, I'm always searching for more stuff, it's a large
+register space :-).
+
+Memory Map
+==========
+
+The cx2341x exposes its entire 64M memory space to the PCI host via the PCI BAR0
+(Base Address Register 0). The addresses here are offsets relative to the
+address held in BAR0.
+
+0x00000000-0x00ffffff Encoder memory space
+0x00000000-0x0003ffff Encode.rom
+      ???-???         MPEG buffer(s)
+      ???-???         Raw video capture buffer(s)
+      ???-???         Raw audio capture buffer(s)
+      ???-???         Display buffers (6 or 9)
+
+0x01000000-0x01ffffff Decoder memory space
+0x01000000-0x0103ffff Decode.rom
+      ???-???         MPEG buffers(s)
+0x0114b000-0x0115afff Audio.rom (deprecated?)
+
+0x02000000-0x0200ffff Register Space
+
+Registers
+=========
+
+The registers occupy the 64k space starting at the 0x02000000 offset from BAR0.
+All of these registers are 32 bits wide.
+
+DMA Registers 0x000-0xff:
+
+ 0x00 - Control:
+	0=reset/cancel, 1=read, 2=write, 4=stop
+ 0x04 - DMA status:
+	1=read busy, 2=write busy, 4=read error, 8=write error, 16=link list error
+ 0x08 - pci DMA pointer for read link list
+ 0x0c - pci DMA pointer for write link list
+ 0x10 - read/write DMA enable:
+	1=read enable, 2=write enable
+ 0x14 - always 0xffffffff, if set any lower instability occurs, 0x00 crashes
+ 0x18 - ??
+ 0x1c - always 0x20 or 32, smaller values slow down DMA transactions
+ 0x20 - always value of 0x780a010a
+ 0x24-0x3c - usually just random values???
+ 0x40 - Interrupt status
+ 0x44 - Write a bit here and shows up in Interrupt status 0x40
+ 0x48 - Interrupt Mask
+ 0x4C - always value of 0xfffdffff,
+	if changed to 0xffffffff DMA write interrupts break.
+ 0x50 - always 0xffffffff
+ 0x54 - always 0xffffffff (0x4c, 0x50, 0x54 seem like interrupt masks, are
+	3 processors on chip, Java ones, VPU, SPU, APU, maybe these are the
+	interrupt masks???).
+ 0x60-0x7C - random values
+ 0x80 - first write linked list reg, for Encoder Memory addr
+ 0x84 - first write linked list reg, for pci memory addr
+ 0x88 - first write linked list reg, for length of buffer in memory addr
+	(|0x80000000 or this for last link)
+ 0x8c-0xcc - rest of write linked list reg, 8 sets of 3 total, DMA goes here
+	from linked list addr in reg 0x0c, firmware must push through or
+	something.
+ 0xe0 - first (and only) read linked list reg, for pci memory addr
+ 0xe4 - first (and only) read linked list reg, for Decoder memory addr
+ 0xe8 - first (and only) read linked list reg, for length of buffer
+ 0xec-0xff - Nothing seems to be in these registers, 0xec-f4 are 0x00000000.
+
+Memory locations for Encoder Buffers 0x700-0x7ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for encoding, have to shift them by <<1 first.
+
+0x07F8: Encoder SDRAM refresh
+0x07FC: Encoder SDRAM pre-charge
+
+Memory locations for Decoder Buffers 0x800-0x8ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for decoding, have to shift them by <<1 first.
+
+0x08F8: Decoder SDRAM refresh
+0x08FC: Decoder SDRAM pre-charge
+
+Other memory locations:
+
+0x2800: Video Display Module control
+0x2D00: AO (audio output?) control
+0x2D24: Bytes Flushed
+0x7000: LSB I2C write clock bit (inverted)
+0x7004: LSB I2C write data bit (inverted)
+0x7008: LSB I2C read clock bit
+0x700c: LSB I2C read data bit
+0x9008: GPIO get input state
+0x900c: GPIO set output state
+0x9020: GPIO direction (Bit7 (GPIO 0..7) - 0:input, 1:output)
+0x9050: SPU control
+0x9054: Reset HW blocks
+0x9058: VPU control
+0xA018: Bit6: interrupt pending?
+0xA064: APU command
+
+
+Interrupt Status Register
+=========================
+
+The definition of the bits in the interrupt status register 0x0040, and the
+interrupt mask 0x0048. If a bit is cleared in the mask, then we want our ISR to
+execute.
+
+Bit
+31 Encoder Start Capture
+30 Encoder EOS
+29 Encoder VBI capture
+28 Encoder Video Input Module reset event
+27 Encoder DMA complete
+26
+25 Decoder copy protect detection event
+24 Decoder audio mode change detection event
+23
+22 Decoder data request
+21 Decoder I-Frame? done
+20 Decoder DMA complete
+19 Decoder VBI re-insertion
+18 Decoder DMA err (linked-list bad)
+
+Missing
+Encoder API call completed
+Decoder API call completed
+Encoder API post(?)
+Decoder API post(?)
+Decoder VTRACE event
diff --git a/Documentation/video4linux/cx2341x/fw-osd-api.txt b/Documentation/video4linux/cx2341x/fw-osd-api.txt
new file mode 100644
index 0000000..da98ae3
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-osd-api.txt
@@ -0,0 +1,342 @@
+OSD firmware API description
+============================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_FRAMEBUFFER
+Enum 	65/0x41
+Description
+	Return base and length of contiguous OSD memory.
+Result[0]
+	OSD base address
+Result[1]
+	OSD length
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_PIXEL_FORMAT
+Enum 	66/0x42
+Description
+	Query OSD format
+Result[0]
+	0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_PIXEL_FORMAT
+Enum 	67/0x43
+Description
+	Assign pixel format
+Param[0]
+	0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_STATE
+Enum 	68/0x44
+Description
+	Query OSD state
+Result[0]
+	Bit  0   0=off, 1=on
+	Bits 1:2 alpha control
+	Bits 3:5 pixel format
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_STATE
+Enum 	69/0x45
+Description
+	OSD switch
+Param[0]
+	0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_OSD_COORDS
+Enum 	70/0x46
+Description
+	Retrieve coordinates of OSD area blended with video
+Result[0]
+	OSD buffer address
+Result[1]
+	Stride in pixels
+Result[2]
+	Lines in OSD buffer
+Result[3]
+	Horizontal offset in buffer
+Result[4]
+	Vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_OSD_COORDS
+Enum 	71/0x47
+Description
+	Assign the coordinates of the OSD area to blend with video
+Param[0]
+	buffer address
+Param[1]
+	buffer stride in pixels
+Param[2]
+	lines in buffer
+Param[3]
+	horizontal offset
+Param[4]
+	vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_SCREEN_COORDS
+Enum 	72/0x48
+Description
+	Retrieve OSD screen area coordinates
+Result[0]
+	top left horizontal offset
+Result[1]
+	top left vertical offset
+Result[2]
+	bottom right hotizontal offset
+Result[3]
+	bottom right vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_SCREEN_COORDS
+Enum 	73/0x49
+Description
+	Assign the coordinates of the screen area to blend with video
+Param[0]
+	top left horizontal offset
+Param[1]
+	top left vertical offset
+Param[2]
+	bottom left horizontal offset
+Param[3]
+	bottom left vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_GLOBAL_ALPHA
+Enum 	74/0x4A
+Description
+	Retrieve OSD global alpha
+Result[0]
+	global alpha: 0=off, 1=on
+Result[1]
+	bits 0:7 global alpha
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_GLOBAL_ALPHA
+Enum 	75/0x4B
+Description
+	Update global alpha
+Param[0]
+	global alpha: 0=off, 1=on
+Param[1]
+	global alpha (8 bits)
+Param[2]
+	local alpha: 0=on, 1=off
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_BLEND_COORDS
+Enum 	78/0x4C
+Description
+	Move start of blending area within display buffer
+Param[0]
+	horizontal offset in buffer
+Param[1]
+	vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_FLICKER_STATE
+Enum 	79/0x4F
+Description
+	Retrieve flicker reduction module state
+Result[0]
+	flicker state: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_FLICKER_STATE
+Enum 	80/0x50
+Description
+	Set flicker reduction module state
+Param[0]
+	State: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_BLT_COPY
+Enum 	82/0x52
+Description
+	BLT copy
+Param[0]
+'0000'  zero
+'0001' ~destination AND ~source
+'0010' ~destination AND  source
+'0011' ~destination
+'0100'  destination AND ~source
+'0101'                  ~source
+'0110'  destination XOR  source
+'0111' ~destination OR  ~source
+'1000' ~destination AND ~source
+'1001'  destination XNOR source
+'1010'                   source
+'1011' ~destination OR   source
+'1100'  destination
+'1101'  destination OR  ~source
+'1110'  destination OR   source
+'1111'  one
+
+Param[1]
+	Resulting alpha blending
+	    '01' source_alpha
+	    '10' destination_alpha
+	    '11' source_alpha*destination_alpha+1
+		 (zero if both source and destination alpha are zero)
+Param[2]
+	'00' output_pixel = source_pixel
+
+	'01' if source_alpha=0:
+		 output_pixel = destination_pixel
+	     if 256 > source_alpha > 1:
+		 output_pixel = ((source_alpha + 1)*source_pixel +
+				 (255 - source_alpha)*destination_pixel)/256
+
+	'10' if destination_alpha=0:
+		 output_pixel = source_pixel
+	      if 255 > destination_alpha > 0:
+		 output_pixel = ((255 - destination_alpha)*source_pixel +
+				 (destination_alpha + 1)*destination_pixel)/256
+
+	'11' if source_alpha=0:
+		 source_temp = 0
+	     if source_alpha=255:
+		 source_temp = source_pixel*256
+	     if 255 > source_alpha > 0:
+		 source_temp = source_pixel*(source_alpha + 1)
+	     if destination_alpha=0:
+		 destination_temp = 0
+	     if destination_alpha=255:
+		 destination_temp = destination_pixel*256
+	     if 255 > destination_alpha > 0:
+		 destination_temp = destination_pixel*(destination_alpha + 1)
+	     output_pixel = (source_temp + destination_temp)/256
+Param[3]
+	width
+Param[4]
+	height
+Param[5]
+	destination pixel mask
+Param[6]
+	destination rectangle start address
+Param[7]
+	destination stride in dwords
+Param[8]
+	source stride in dwords
+Param[9]
+	source rectangle start address
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_BLT_FILL
+Enum 	83/0x53
+Description
+	BLT fill color
+Param[0]
+	Same as Param[0] on API 0x52
+Param[1]
+	Same as Param[1] on API 0x52
+Param[2]
+	Same as Param[2] on API 0x52
+Param[3]
+	width
+Param[4]
+	height
+Param[5]
+	destination pixel mask
+Param[6]
+	destination rectangle start address
+Param[7]
+	destination stride in dwords
+Param[8]
+	color fill value
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_BLT_TEXT
+Enum 	84/0x54
+Description
+	BLT for 8 bit alpha text source
+Param[0]
+	Same as Param[0] on API 0x52
+Param[1]
+	Same as Param[1] on API 0x52
+Param[2]
+	Same as Param[2] on API 0x52
+Param[3]
+	width
+Param[4]
+	height
+Param[5]
+	destination pixel mask
+Param[6]
+	destination rectangle start address
+Param[7]
+	destination stride in dwords
+Param[8]
+	source stride in dwords
+Param[9]
+	source rectangle start address
+Param[10]
+	color fill value
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_FRAMEBUFFER_WINDOW
+Enum 	86/0x56
+Description
+	Positions the main output window on the screen. The coordinates must be
+	such that the entire window fits on the screen.
+Param[0]
+	window width
+Param[1]
+	window height
+Param[2]
+	top left window corner horizontal offset
+Param[3]
+	top left window corner vertical offset
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_CHROMA_KEY
+Enum 	96/0x60
+Description
+	Chroma key switch and color
+Param[0]
+	state: 0=off, 1=on
+Param[1]
+	color
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_GET_ALPHA_CONTENT_INDEX
+Enum 	97/0x61
+Description
+	Retrieve alpha content index
+Result[0]
+	alpha content index, Range 0:15
+
+-------------------------------------------------------------------------------
+
+Name 	CX2341X_OSD_SET_ALPHA_CONTENT_INDEX
+Enum 	98/0x62
+Description
+	Assign alpha content index
+Param[0]
+	alpha content index, range 0:15
diff --git a/Documentation/video4linux/cx2341x/fw-upload.txt b/Documentation/video4linux/cx2341x/fw-upload.txt
new file mode 100644
index 0000000..60c502c
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/fw-upload.txt
@@ -0,0 +1,49 @@
+This document describes how to upload the cx2341x firmware to the card.
+
+How to find
+===========
+
+See the web pages of the various projects that uses this chip for information
+on how to obtain the firmware.
+
+The firmware stored in a Windows driver can be detected as follows:
+
+- Each firmware image is 256k bytes.
+- The 1st 32-bit word of the Encoder image is 0x0000da7
+- The 1st 32-bit word of the Decoder image is 0x00003a7
+- The 2nd 32-bit word of both images is 0xaa55bb66
+
+How to load
+===========
+
+- Issue the FWapi command to stop the encoder if it is running. Wait for the
+  command to complete.
+- Issue the FWapi command to stop the decoder if it is running. Wait for the
+  command to complete.
+- Issue the I2C command to the digitizer to stop emitting VSYNC events.
+- Issue the FWapi command to halt the encoder's firmware.
+- Sleep for 10ms.
+- Issue the FWapi command to halt the decoder's firmware.
+- Sleep for 10ms.
+- Write 0x00000000 to register 0x2800 to stop the Video Display Module.
+- Write 0x00000005 to register 0x2D00 to stop the AO (audio output?).
+- Write 0x00000000 to register 0xA064 to ping? the APU.
+- Write 0xFFFFFFFE to register 0x9058 to stop the VPU.
+- Write 0xFFFFFFFF to register 0x9054 to reset the HW blocks.
+- Write 0x00000001 to register 0x9050 to stop the SPU.
+- Sleep for 10ms.
+- Write 0x0000001A to register 0x07FC to init the Encoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x07F8 to init the Encoder SDRAM's refresh to 1us.
+- Write 0x0000001A to register 0x08FC to init the Decoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x08F8 to init the Decoder SDRAM's refresh to 1us.
+- Sleep for 512ms. (600ms is recommended)
+- Transfer the encoder's firmware image to offset 0 in Encoder memory space.
+- Transfer the decoder's firmware image to offset 0 in Decoder memory space.
+- Use a read-modify-write operation to Clear bit 0 of register 0x9050 to
+  re-enable the SPU.
+- Sleep for 1 second.
+- Use a read-modify-write operation to Clear bits 3 and 0 of register 0x9058
+  to re-enable the VPU.
+- Sleep for 1 second.
+- Issue status API commands to both firmware images to verify.
+
diff --git a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
new file mode 100644
index 0000000..93fec32
--- /dev/null
+++ b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
@@ -0,0 +1,54 @@
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0  GPIO1
+  0        0    TV Audio
+  1        0    FM radio
+  0        1    Line-In
+  1        1    Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004  PCI Interrupt Status
+  bit [18]  IR_SMP_INT Set when 32 input samples have been collected over
+  gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to  0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data)  An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well.  Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/  and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+
diff --git a/Documentation/video4linux/et61x251.txt b/Documentation/video4linux/et61x251.txt
index 2934028..cd584f2 100644
--- a/Documentation/video4linux/et61x251.txt
+++ b/Documentation/video4linux/et61x251.txt
@@ -1,9 +1,9 @@
 
-                       ET61X[12]51 PC Camera Controllers
-                                Driver for Linux
-                       =================================
+		       ET61X[12]51 PC Camera Controllers
+				Driver for Linux
+		       =================================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -156,46 +156,46 @@
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                registered camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 64 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		registered camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+		before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+		all the applications support this feature. This parameter is
+		specific for each detected camera.
+		0 = do not force memory unmapping
+		1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		specific for each detected camera. This parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used at the same time. It also shows some more informations
-                about the hardware being detected. This module parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = more verbose messages
+		Level 3 is useful for testing only, when only one device
+		is used at the same time. It also shows some more informations
+		about the hardware being detected. This module parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
diff --git a/Documentation/video4linux/ibmcam.txt b/Documentation/video4linux/ibmcam.txt
index 4a40a2e..397a94e 100644
--- a/Documentation/video4linux/ibmcam.txt
+++ b/Documentation/video4linux/ibmcam.txt
@@ -21,7 +21,7 @@
 Supported controls:
 - by V4L: Contrast,  Brightness, Color, Hue
 - by driver options: frame rate, lighting conditions, video format,
-                     default picture settings, sharpness.
+		     default picture settings, sharpness.
 
 SUPPORTED CAMERAS:
 
@@ -191,66 +191,66 @@
 init_model2_yb  Integer         0..255 [0xa0]   init_model2_yb=200
 
 debug           You don't need this option unless you are a developer.
-                If you are a developer then you will see in the code
-                what values do what. 0=off.
+		If you are a developer then you will see in the code
+		what values do what. 0=off.
 
 flags           This is a bit mask, and you can combine any number of
-                bits to produce what you want. Usually you don't want
-                any of extra features this option provides:
+		bits to produce what you want. Usually you don't want
+		any of extra features this option provides:
 
-                FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
-                                           VIDIOCSYNC ioctls without failing.
-                                           Will work with xawtv, will not
-                                           with xrealproducer. Default is
-                                           not set.
-                FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
-                FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
-                                           magic meaning to developers.
-                FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
-                                           useful only for debugging.
-                FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
-                FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
-                                           it was received from the camera.
-                                           Default (not set) is to mix the
-                                           preceding frame in to compensate
-                                           for occasional loss of Isoc data
-                                           on high frame rates.
-                FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
-                                           prior to use; relevant only if
-                                           FLAGS_SEPARATE_FRAMES is set.
-                                           Default is not to clean frames,
-                                           this is a little faster but may
-                                           produce flicker if frame rate is
-                                           too high and Isoc data gets lost.
-                FLAGS_NO_DECODING      128 This flag turns the video stream
-                                           decoder off, and dumps the raw
-                                           Isoc data from the camera into
-                                           the reading process. Useful to
-                                           developers, but not to users.
+		FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
+					   VIDIOCSYNC ioctls without failing.
+					   Will work with xawtv, will not
+					   with xrealproducer. Default is
+					   not set.
+		FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
+		FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
+					   magic meaning to developers.
+		FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
+					   useful only for debugging.
+		FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+		FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
+					   it was received from the camera.
+					   Default (not set) is to mix the
+					   preceding frame in to compensate
+					   for occasional loss of Isoc data
+					   on high frame rates.
+		FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
+					   prior to use; relevant only if
+					   FLAGS_SEPARATE_FRAMES is set.
+					   Default is not to clean frames,
+					   this is a little faster but may
+					   produce flicker if frame rate is
+					   too high and Isoc data gets lost.
+		FLAGS_NO_DECODING      128 This flag turns the video stream
+					   decoder off, and dumps the raw
+					   Isoc data from the camera into
+					   the reading process. Useful to
+					   developers, but not to users.
 
 framerate       This setting controls frame rate of the camera. This is
-                an approximate setting (in terms of "worst" ... "best")
-                because camera changes frame rate depending on amount
-                of light available. Setting 0 is slowest, 6 is fastest.
-                Beware - fast settings are very demanding and may not
-                work well with all video sizes. Be conservative.
+		an approximate setting (in terms of "worst" ... "best")
+		because camera changes frame rate depending on amount
+		of light available. Setting 0 is slowest, 6 is fastest.
+		Beware - fast settings are very demanding and may not
+		work well with all video sizes. Be conservative.
 
 hue_correction  This highly optional setting allows to adjust the
-                hue of the image in a way slightly different from
-                what usual "hue" control does. Both controls affect
-                YUV colorspace: regular "hue" control adjusts only
-                U component, and this "hue_correction" option similarly
-                adjusts only V component. However usually it is enough
-                to tweak only U or V to compensate for colored light or
-                color temperature; this option simply allows more
-                complicated correction when and if it is necessary.
+		hue of the image in a way slightly different from
+		what usual "hue" control does. Both controls affect
+		YUV colorspace: regular "hue" control adjusts only
+		U component, and this "hue_correction" option similarly
+		adjusts only V component. However usually it is enough
+		to tweak only U or V to compensate for colored light or
+		color temperature; this option simply allows more
+		complicated correction when and if it is necessary.
 
 init_brightness These settings specify _initial_ values which will be
 init_contrast   used to set up the camera. If your V4L application has
 init_color      its own controls to adjust the picture then these
 init_hue        controls will be used too. These options allow you to
-                preconfigure the camera when it gets connected, before
-                any V4L application connects to it. Good for webcams.
+		preconfigure the camera when it gets connected, before
+		any V4L application connects to it. Good for webcams.
 
 init_model2_rg  These initial settings alter color balance of the
 init_model2_rg2 camera on hardware level. All four settings may be used
@@ -258,47 +258,47 @@
 init_model2_yb  settings only apply to Model 2 cameras.
 
 lighting        This option selects one of three hardware-defined
-                photosensitivity settings of the camera. 0=bright light,
-                1=Medium (default), 2=Low light. This setting affects
-                frame rate: the dimmer the lighting the lower the frame
-                rate (because longer exposition time is needed). The
-                Model 2 cameras allow values more than 2 for this option,
-                thus enabling extremely high sensitivity at cost of frame
-                rate, color saturation and imaging sensor noise.
+		photosensitivity settings of the camera. 0=bright light,
+		1=Medium (default), 2=Low light. This setting affects
+		frame rate: the dimmer the lighting the lower the frame
+		rate (because longer exposition time is needed). The
+		Model 2 cameras allow values more than 2 for this option,
+		thus enabling extremely high sensitivity at cost of frame
+		rate, color saturation and imaging sensor noise.
 
 sharpness       This option controls smoothing (noise reduction)
-                made by camera. Setting 0 is most smooth, setting 6
-                is most sharp. Be aware that CMOS sensor used in the
-                camera is pretty noisy, so if you choose 6 you will
-                be greeted with "snowy" image. Default is 4. Model 2
-                cameras do not support this feature.
+		made by camera. Setting 0 is most smooth, setting 6
+		is most sharp. Be aware that CMOS sensor used in the
+		camera is pretty noisy, so if you choose 6 you will
+		be greeted with "snowy" image. Default is 4. Model 2
+		cameras do not support this feature.
 
 size            This setting chooses one of several image sizes that are
-                supported by this driver. Cameras may support more, but
-                it's difficult to reverse-engineer all formats.
-                Following video sizes are supported:
+		supported by this driver. Cameras may support more, but
+		it's difficult to reverse-engineer all formats.
+		Following video sizes are supported:
 
-                size=0     128x96  (Model 1 only)
-                size=1     160x120
-                size=2     176x144
-                size=3     320x240 (Model 2 only)
-                size=4     352x240 (Model 2 only)
-                size=5     352x288
-                size=6     640x480 (Model 3 only)
+		size=0     128x96  (Model 1 only)
+		size=1     160x120
+		size=2     176x144
+		size=3     320x240 (Model 2 only)
+		size=4     352x240 (Model 2 only)
+		size=5     352x288
+		size=6     640x480 (Model 3 only)
 
-                The 352x288 is the native size of the Model 1 sensor
-                array, so it's the best resolution the camera can
-                yield. The best resolution of Model 2 is 176x144, and
-                larger images are produced by stretching the bitmap.
-                Model 3 has sensor with 640x480 grid, and it works too,
-                but the frame rate will be exceptionally low (1-2 FPS);
-                it may be still OK for some applications, like security.
-                Choose the image size you need. The smaller image can
-                support faster frame rate. Default is 352x288.
+		The 352x288 is the native size of the Model 1 sensor
+		array, so it's the best resolution the camera can
+		yield. The best resolution of Model 2 is 176x144, and
+		larger images are produced by stretching the bitmap.
+		Model 3 has sensor with 640x480 grid, and it works too,
+		but the frame rate will be exceptionally low (1-2 FPS);
+		it may be still OK for some applications, like security.
+		Choose the image size you need. The smaller image can
+		support faster frame rate. Default is 352x288.
 
 For more information and the Troubleshooting FAQ visit this URL:
 
-                http://www.linux-usb.org/ibmcam/
+		http://www.linux-usb.org/ibmcam/
 
 WHAT NEEDS TO BE DONE:
 
diff --git a/Documentation/video4linux/ov511.txt b/Documentation/video4linux/ov511.txt
index 142741e..79af610 100644
--- a/Documentation/video4linux/ov511.txt
+++ b/Documentation/video4linux/ov511.txt
@@ -81,7 +81,7 @@
   TYPE: integer (Boolean)
   DEFAULT: 1
   DESC: Brightness is normally under automatic control and can't be set
-        manually by the video app. Set to 0 for manual control.
+	manually by the video app. Set to 0 for manual control.
 
   NAME: autogain
   TYPE: integer (Boolean)
@@ -97,13 +97,13 @@
   TYPE: integer (0-6)
   DEFAULT: 3
   DESC: Sets the threshold for printing debug messages. The higher the value,
-        the more is printed. The levels are cumulative, and are as follows:
-          0=no debug messages
-          1=init/detection/unload and other significant messages
-          2=some warning messages
-          3=config/control function calls
-          4=most function calls and data parsing messages
-          5=highly repetitive mesgs
+	the more is printed. The levels are cumulative, and are as follows:
+	  0=no debug messages
+	  1=init/detection/unload and other significant messages
+	  2=some warning messages
+	  3=config/control function calls
+	  4=most function calls and data parsing messages
+	  5=highly repetitive mesgs
 
   NAME: snapshot
   TYPE: integer (Boolean)
@@ -116,24 +116,24 @@
   TYPE: integer (1-4 for OV511, 1-31 for OV511+)
   DEFAULT: 1
   DESC: Number of cameras allowed to stream simultaneously on a single bus.
-        Values higher than 1 reduce the data rate of each camera, allowing two
-        or more to be used at once. If you have a complicated setup involving
-        both OV511 and OV511+ cameras, trial-and-error may be necessary for
-        finding the optimum setting.
+	Values higher than 1 reduce the data rate of each camera, allowing two
+	or more to be used at once. If you have a complicated setup involving
+	both OV511 and OV511+ cameras, trial-and-error may be necessary for
+	finding the optimum setting.
 
   NAME: compress
   TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: Set this to 1 to turn on the camera's compression engine. This can
-        potentially increase the frame rate at the expense of quality, if you
-        have a fast CPU. You must load the proper compression module for your
-        camera before starting your application (ov511_decomp or ov518_decomp).
+	potentially increase the frame rate at the expense of quality, if you
+	have a fast CPU. You must load the proper compression module for your
+	camera before starting your application (ov511_decomp or ov518_decomp).
 
   NAME: testpat
   TYPE: integer (Boolean)
   DEFAULT: 0
   DESC: This configures the camera's sensor to transmit a colored test-pattern
-        instead of an image. This does not work correctly yet.
+	instead of an image. This does not work correctly yet.
 
   NAME: dumppix
   TYPE: integer (0-2)
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
index 142920b..1d20895 100644
--- a/Documentation/video4linux/sn9c102.txt
+++ b/Documentation/video4linux/sn9c102.txt
@@ -1,9 +1,9 @@
 
-                         SN9C10x PC Camera Controllers
-                                Driver for Linux
-                         =============================
+			 SN9C10x PC Camera Controllers
+				Driver for Linux
+			 =============================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -176,46 +176,46 @@
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                recognized camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 64 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		recognized camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+		before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+		all the applications support this feature. This parameter is
+		specific for each detected camera.
+		0 = do not force memory unmapping
+		1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		specific for each detected camera. This parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used. It also shows some more informations about the
-                hardware being detected. This parameter can be changed at
-                runtime thanks to the /sys filesystem interface.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = more verbose messages
+		Level 3 is useful for testing only, when only one device
+		is used. It also shows some more informations about the
+		hardware being detected. This parameter can be changed at
+		runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -280,24 +280,24 @@
 0x04    0xC4          Frame synchronisation pattern.
 0x05    0x96          Frame synchronisation pattern.
 0x06    0xXX          Unknown meaning. The exact value depends on the chip;
-                      possible values are 0x00, 0x01 and 0x20.
+		      possible values are 0x00, 0x01 and 0x20.
 0x07    0xXX          Variable value, whose bits are ff00uzzc, where ff is a
-                      frame counter, u is unknown, zz is a size indicator
-                      (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
-                      "compression enabled" (1 = yes, 0 = no).
+		      frame counter, u is unknown, zz is a size indicator
+		      (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
+		      "compression enabled" (1 = yes, 0 = no).
 0x08    0xXX          Brightness sum inside Auto-Exposure area (low-byte).
 0x09    0xXX          Brightness sum inside Auto-Exposure area (high-byte).
-                      For a pure white image, this number will be equal to 500
-                      times the area of the specified AE area. For images
-                      that are not pure white, the value scales down according
-                      to relative whiteness.
+		      For a pure white image, this number will be equal to 500
+		      times the area of the specified AE area. For images
+		      that are not pure white, the value scales down according
+		      to relative whiteness.
 0x0A    0xXX          Brightness sum outside Auto-Exposure area (low-byte).
 0x0B    0xXX          Brightness sum outside Auto-Exposure area (high-byte).
-                      For a pure white image, this number will be equal to 125
-                      times the area outside of the specified AE area. For
-                      images that are not pure white, the value scales down
-                      according to relative whiteness.
-                      according to relative whiteness.
+		      For a pure white image, this number will be equal to 125
+		      times the area outside of the specified AE area. For
+		      images that are not pure white, the value scales down
+		      according to relative whiteness.
+		      according to relative whiteness.
 
 The following bytes are used by the SN9C103 bridge only:
 
diff --git a/Documentation/video4linux/v4lgrab.c b/Documentation/video4linux/v4lgrab.c
new file mode 100644
index 0000000..079b628
--- /dev/null
+++ b/Documentation/video4linux/v4lgrab.c
@@ -0,0 +1,192 @@
+/* Simple Video4Linux image grabber. */
+/*
+ *	Video4Linux Driver Test/Example Framegrabbing Program
+ *
+ *	Compile with:
+ *		gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
+ *      Use as:
+ *              v4lgrab >image.ppm
+ *
+ *	Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
+ *      Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
+ *      with minor modifications (Dave Forrest, drf5n@virginia.edu).
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+#include <linux/videodev.h>
+
+#define FILE "/dev/video0"
+
+/* Stole this from tvset.c */
+
+#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b)                   \
+{                                                                       \
+	switch (format)                                                 \
+	{                                                               \
+		case VIDEO_PALETTE_GREY:                                \
+			switch (depth)                                  \
+			{                                               \
+				case 4:                                 \
+				case 6:                                 \
+				case 8:                                 \
+					(r) = (g) = (b) = (*buf++ << 8);\
+					break;                          \
+									\
+				case 16:                                \
+					(r) = (g) = (b) =               \
+						*((unsigned short *) buf);      \
+					buf += 2;                       \
+					break;                          \
+			}                                               \
+			break;                                          \
+									\
+									\
+		case VIDEO_PALETTE_RGB565:                              \
+		{                                                       \
+			unsigned short tmp = *(unsigned short *)buf;    \
+			(r) = tmp&0xF800;                               \
+			(g) = (tmp<<5)&0xFC00;                          \
+			(b) = (tmp<<11)&0xF800;                         \
+			buf += 2;                                       \
+		}                                                       \
+		break;                                                  \
+									\
+		case VIDEO_PALETTE_RGB555:                              \
+			(r) = (buf[0]&0xF8)<<8;                         \
+			(g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8;    \
+			(b) = ((buf[1] << 2 ) & 0xF8)<<8;               \
+			buf += 2;                                       \
+			break;                                          \
+									\
+		case VIDEO_PALETTE_RGB24:                               \
+			(r) = buf[0] << 8; (g) = buf[1] << 8;           \
+			(b) = buf[2] << 8;                              \
+			buf += 3;                                       \
+			break;                                          \
+									\
+		default:                                                \
+			fprintf(stderr,                                 \
+				"Format %d not yet supported\n",        \
+				format);                                \
+	}                                                               \
+}
+
+int get_brightness_adj(unsigned char *image, long size, int *brightness) {
+  long i, tot = 0;
+  for (i=0;i<size*3;i++)
+    tot += image[i];
+  *brightness = (128 - tot/(size*3))/3;
+  return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
+}
+
+int main(int argc, char ** argv)
+{
+  int fd = open(FILE, O_RDONLY), f;
+  struct video_capability cap;
+  struct video_window win;
+  struct video_picture vpic;
+
+  unsigned char *buffer, *src;
+  int bpp = 24, r, g, b;
+  unsigned int i, src_depth;
+
+  if (fd < 0) {
+    perror(FILE);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
+    perror("VIDIOGCAP");
+    fprintf(stderr, "(" FILE " not a video4linux device?)\n");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
+    perror("VIDIOCGWIN");
+    close(fd);
+    exit(1);
+  }
+
+  if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
+    perror("VIDIOCGPICT");
+    close(fd);
+    exit(1);
+  }
+
+  if (cap.type & VID_TYPE_MONOCHROME) {
+    vpic.depth=8;
+    vpic.palette=VIDEO_PALETTE_GREY;    /* 8bit grey */
+    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+      vpic.depth=6;
+      if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+	vpic.depth=4;
+	if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+	  fprintf(stderr, "Unable to find a supported capture format.\n");
+	  close(fd);
+	  exit(1);
+	}
+      }
+    }
+  } else {
+    vpic.depth=24;
+    vpic.palette=VIDEO_PALETTE_RGB24;
+
+    if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+      vpic.palette=VIDEO_PALETTE_RGB565;
+      vpic.depth=16;
+
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+	vpic.palette=VIDEO_PALETTE_RGB555;
+	vpic.depth=15;
+
+	if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+	  fprintf(stderr, "Unable to find a supported capture format.\n");
+	  return -1;
+	}
+      }
+    }
+  }
+
+  buffer = malloc(win.width * win.height * bpp);
+  if (!buffer) {
+    fprintf(stderr, "Out of memory.\n");
+    exit(1);
+  }
+
+  do {
+    int newbright;
+    read(fd, buffer, win.width * win.height * bpp);
+    f = get_brightness_adj(buffer, win.width * win.height, &newbright);
+    if (f) {
+      vpic.brightness += (newbright << 8);
+      if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+	perror("VIDIOSPICT");
+	break;
+      }
+    }
+  } while (f);
+
+  fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
+
+  src = buffer;
+
+  for (i = 0; i < win.width * win.height; i++) {
+    READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
+    fputc(r>>8, stdout);
+    fputc(g>>8, stdout);
+    fputc(b>>8, stdout);
+  }
+
+  close(fd);
+  return 0;
+}
diff --git a/Documentation/video4linux/w9968cf.txt b/Documentation/video4linux/w9968cf.txt
index 3b704f2..0d53ce7 100644
--- a/Documentation/video4linux/w9968cf.txt
+++ b/Documentation/video4linux/w9968cf.txt
@@ -1,9 +1,9 @@
 
-                   W996[87]CF JPEG USB Dual Mode Camera Chip
-                     Driver for Linux 2.6 (basic version)
-                   =========================================
+		   W996[87]CF JPEG USB Dual Mode Camera Chip
+		     Driver for Linux 2.6 (basic version)
+		   =========================================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -188,57 +188,57 @@
 Type:            bool
 Syntax:          <0|1>
 Description:     Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled.
-                 If enabled, 'insmod' searches for the required 'ovcamchip'
-                 module in the system, according to its configuration, and
-                 loads that module automatically. This action is performed as
-                 once soon as the 'w9968cf' module is loaded into memory.
+		 If enabled, 'insmod' searches for the required 'ovcamchip'
+		 module in the system, according to its configuration, and
+		 loads that module automatically. This action is performed as
+		 once soon as the 'w9968cf' module is loaded into memory.
 Default:         1
 Note:            The kernel must be compiled with the CONFIG_KMOD option
-                 enabled for the 'ovcamchip' module to be loaded and for
-                 this parameter to be present.
+		 enabled for the 'ovcamchip' module to be loaded and for
+		 this parameter to be present.
 -------------------------------------------------------------------------------
 Name:           simcams
 Type:           int
 Syntax:         <n>
 Description:    Number of cameras allowed to stream simultaneously.
-                n may vary from 0 to 32.
+		n may vary from 0 to 32.
 Default:        32
 -------------------------------------------------------------------------------
 Name:           video_nr
 Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L minor mode number.
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 32 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                recognized camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 32 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		recognized camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           packet_size
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    Specify the maximum data payload size in bytes for alternate
-                settings, for each device. n is scaled between 63 and 1023.
+		settings, for each device. n is scaled between 63 and 1023.
 Default:        1023
 -------------------------------------------------------------------------------
 Name:           max_buffers
 Type:           int array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    For advanced users.
-                Specify the maximum number of video frame buffers to allocate
-                for each device, from 2 to 32.
+		Specify the maximum number of video frame buffers to allocate
+		for each device, from 2 to 32.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           double_buffer
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Hardware double buffering: 0 disabled, 1 enabled.
-                It should be enabled if you want smooth video output: if you
-                obtain out of sync. video, disable it, or try to
-                decrease the 'clockdiv' module parameter value.
+		It should be enabled if you want smooth video output: if you
+		obtain out of sync. video, disable it, or try to
+		decrease the 'clockdiv' module parameter value.
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           clamping
@@ -251,9 +251,9 @@
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|1|2[,...]>
 Description:    Video filter type.
-                0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
-                The filter is used to reduce noise and aliasing artifacts
-                produced by the CCD or CMOS image sensor.
+		0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
+		The filter is used to reduce noise and aliasing artifacts
+		produced by the CCD or CMOS image sensor.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           largeview
@@ -266,9 +266,9 @@
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Software scaling (for non-compressed video only):
-                0 disabled, 1 enabled.
-                Disable it if you have a slow CPU or you don't have enough
-                memory.
+		0 disabled, 1 enabled.
+		Disable it if you have a slow CPU or you don't have enough
+		memory.
 Default:        0 for every device.
 Note:           If 'w9968cf-vpp' is not present, this parameter is set to 0.
 -------------------------------------------------------------------------------
@@ -276,36 +276,36 @@
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|1|2[,...]>
 Description:    Software video decompression:
-                0 = disables decompression
-                    (doesn't allow formats needing decompression).
-                1 = forces decompression
-                    (allows formats needing decompression only).
-                2 = allows any permitted formats.
-                Formats supporting (de)compressed video are YUV422P and
-                YUV420P/YUV420 in any resolutions where width and height are
-                multiples of 16.
+		0 = disables decompression
+		    (doesn't allow formats needing decompression).
+		1 = forces decompression
+		    (allows formats needing decompression only).
+		2 = allows any permitted formats.
+		Formats supporting (de)compressed video are YUV422P and
+		YUV420P/YUV420 in any resolutions where width and height are
+		multiples of 16.
 Default:        2 for every device.
 Note:           If 'w9968cf-vpp' is not present, forcing decompression is not
-                allowed; in this case this parameter is set to 2.
+		allowed; in this case this parameter is set to 2.
 -------------------------------------------------------------------------------
 Name:           force_palette
 Type:           int array (min = 0, max = 32)
 Syntax:         <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
 Description:    Force picture palette.
-                In order:
-                 0 = Off - allows any of the following formats:
-                 9 = UYVY    16 bpp - Original video, compression disabled
-                10 = YUV420  12 bpp - Original video, compression enabled
-                13 = YUV422P 16 bpp - Original video, compression enabled
-                15 = YUV420P 12 bpp - Original video, compression enabled
-                 8 = YUVY    16 bpp - Software conversion from UYVY
-                 7 = YUV422  16 bpp - Software conversion from UYVY
-                 1 = GREY     8 bpp - Software conversion from UYVY
-                 6 = RGB555  16 bpp - Software conversion from UYVY
-                 3 = RGB565  16 bpp - Software conversion from UYVY
-                 4 = RGB24   24 bpp - Software conversion from UYVY
-                 5 = RGB32   32 bpp - Software conversion from UYVY
-                When not 0, this parameter will override 'decompression'.
+		In order:
+		 0 = Off - allows any of the following formats:
+		 9 = UYVY    16 bpp - Original video, compression disabled
+		10 = YUV420  12 bpp - Original video, compression enabled
+		13 = YUV422P 16 bpp - Original video, compression enabled
+		15 = YUV420P 12 bpp - Original video, compression enabled
+		 8 = YUVY    16 bpp - Software conversion from UYVY
+		 7 = YUV422  16 bpp - Software conversion from UYVY
+		 1 = GREY     8 bpp - Software conversion from UYVY
+		 6 = RGB555  16 bpp - Software conversion from UYVY
+		 3 = RGB565  16 bpp - Software conversion from UYVY
+		 4 = RGB24   24 bpp - Software conversion from UYVY
+		 5 = RGB32   32 bpp - Software conversion from UYVY
+		When not 0, this parameter will override 'decompression'.
 Default:        0 for every device. Initial palette is 9 (UYVY).
 Note:           If 'w9968cf-vpp' is not present, this parameter is set to 9.
 -------------------------------------------------------------------------------
@@ -313,77 +313,77 @@
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Read RGB video data instead of BGR:
-                1 = use RGB component ordering.
-                0 = use BGR component ordering.
-                This parameter has effect when using RGBX palettes only.
+		1 = use RGB component ordering.
+		0 = use BGR component ordering.
+		This parameter has effect when using RGBX palettes only.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autobright
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Image sensor automatically changes brightness:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           autoexp
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Image sensor automatically changes exposure:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        1 for every device.
 -------------------------------------------------------------------------------
 Name:           lightfreq
 Type:           int array (min = 0, max = 32)
 Syntax:         <50|60[,...]>
 Description:    Light frequency in Hz:
-                50 for European and Asian lighting, 60 for American lighting.
+		50 for European and Asian lighting, 60 for American lighting.
 Default:        50 for every device.
 -------------------------------------------------------------------------------
 Name:           bandingfilter
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Banding filter to reduce effects of fluorescent
-                lighting:
-                0 disabled, 1 enabled.
-                This filter tries to reduce the pattern of horizontal
-                light/dark bands caused by some (usually fluorescent) lighting.
+		lighting:
+		0 disabled, 1 enabled.
+		This filter tries to reduce the pattern of horizontal
+		light/dark bands caused by some (usually fluorescent) lighting.
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           clockdiv
 Type:           int array (min = 0, max = 32)
 Syntax:         <-1|n[,...]>
 Description:    Force pixel clock divisor to a specific value (for experts):
-                n may vary from 0 to 127.
-                -1 for automatic value.
-                See also the 'double_buffer' module parameter.
+		n may vary from 0 to 127.
+		-1 for automatic value.
+		See also the 'double_buffer' module parameter.
 Default:        -1 for every device.
 -------------------------------------------------------------------------------
 Name:           backlight
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Objects are lit from behind:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           mirror
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    Reverse image horizontally:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           monochrome
 Type:           bool array (min = 0, max = 32)
 Syntax:         <0|1[,...]>
 Description:    The image sensor is monochrome:
-                0 = no, 1 = yes
+		0 = no, 1 = yes
 Default:        0 for every device.
 -------------------------------------------------------------------------------
 Name:           brightness
 Type:           long array (min = 0, max = 32)
 Syntax:         <n[,...]>
 Description:    Set picture brightness (0-65535).
-                This parameter has no effect if 'autobright' is enabled.
+		This parameter has no effect if 'autobright' is enabled.
 Default:        31000 for every device.
 -------------------------------------------------------------------------------
 Name:           hue
@@ -414,23 +414,23 @@
 Type:           int
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 6:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = configuration or general messages
-                4 = warnings
-                5 = called functions
-                6 = function internals
-                Level 5 and 6 are useful for testing only, when only one
-                device is used.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = configuration or general messages
+		4 = warnings
+		5 = called functions
+		6 = function internals
+		Level 5 and 6 are useful for testing only, when only one
+		device is used.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           specific_debug
 Type:           bool
 Syntax:         <0|1>
 Description:    Enable or disable specific debugging messages:
-                0 = print messages concerning every level <= 'debug' level.
-                1 = print messages concerning the level indicated by 'debug'.
+		0 = print messages concerning every level <= 'debug' level.
+		1 = print messages concerning the level indicated by 'debug'.
 Default:        0
 -------------------------------------------------------------------------------
 
diff --git a/Documentation/video4linux/zc0301.txt b/Documentation/video4linux/zc0301.txt
index f55262c..f406f5e 100644
--- a/Documentation/video4linux/zc0301.txt
+++ b/Documentation/video4linux/zc0301.txt
@@ -1,9 +1,9 @@
 
-                    ZC0301 Image Processor and Control Chip
-                                Driver for Linux
-                    =======================================
+	      ZC0301 and ZC0301P Image Processor and Control Chip
+				Driver for Linux
+	      ===================================================
 
-                               - Documentation -
+			       - Documentation -
 
 
 Index
@@ -51,13 +51,13 @@
 
 4. Overview and features
 ========================
-This driver supports the video interface of the devices mounting the ZC0301
-Image Processor and Control Chip.
+This driver supports the video interface of the devices mounting the ZC0301 or
+ZC0301P Image Processors and Control Chips.
 
 The driver relies on the Video4Linux2 and USB core modules. It has been
 designed to run properly on SMP systems as well.
 
-The latest version of the ZC0301 driver can be found at the following URL:
+The latest version of the ZC0301[P] driver can be found at the following URL:
 http://www.linux-projects.org/
 
 Some of the features of the driver are:
@@ -117,7 +117,7 @@
 
 And finally:
 
-	# USB Multimedia devices
+	# V4L USB devices
 	#
 	CONFIG_USB_ZC0301=m
 
@@ -146,46 +146,46 @@
 Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]>
 Description:    Specify V4L2 minor mode number:
-                -1 = use next available
-                 n = use minor number n
-                You can specify up to 64 cameras this way.
-                For example:
-                video_nr=-1,2,-1 would assign minor number 2 to the second
-                registered camera and use auto for the first one and for every
-                other camera.
+		-1 = use next available
+		 n = use minor number n
+		You can specify up to 64 cameras this way.
+		For example:
+		video_nr=-1,2,-1 would assign minor number 2 to the second
+		registered camera and use auto for the first one and for every
+		other camera.
 Default:        -1
 -------------------------------------------------------------------------------
 Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]>
 Description:    Force the application to unmap previously mapped buffer memory
-                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
-                all the applications support this feature. This parameter is
-                specific for each detected camera.
-                0 = do not force memory unmapping
-                1 = force memory unmapping (save memory)
+		before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+		all the applications support this feature. This parameter is
+		specific for each detected camera.
+		0 = do not force memory unmapping
+		1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           frame_timeout
 Type:           uint array (min = 0, max = 64)
 Syntax:         <n[,...]>
 Description:    Timeout for a video frame in seconds. This parameter is
-                specific for each detected camera. This parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		specific for each detected camera. This parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
 Description:    Debugging information level, from 0 to 3:
-                0 = none (use carefully)
-                1 = critical errors
-                2 = significant informations
-                3 = more verbose messages
-                Level 3 is useful for testing only, when only one device
-                is used at the same time. It also shows some more informations
-                about the hardware being detected. This module parameter can be
-                changed at runtime thanks to the /sys filesystem interface.
+		0 = none (use carefully)
+		1 = critical errors
+		2 = significant informations
+		3 = more verbose messages
+		Level 3 is useful for testing only, when only one device
+		is used at the same time. It also shows some more informations
+		about the hardware being detected. This module parameter can be
+		changed at runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -204,11 +204,25 @@
 0x041e     0x4017
 0x041e     0x401c
 0x041e     0x401e
+0x041e     0x401f
+0x041e     0x4022
 0x041e     0x4034
 0x041e     0x4035
+0x041e     0x4036
+0x041e     0x403a
+0x0458     0x7007
+0x0458     0x700C
+0x0458     0x700f
+0x046d     0x08ae
+0x055f     0xd003
+0x055f     0xd004
 0x046d     0x08ae
 0x0ac8     0x0301
+0x0ac8     0x301b
+0x0ac8     0x303b
+0x10fd     0x0128
 0x10fd     0x8050
+0x10fd     0x804e
 
 The list above does not imply that all those devices work with this driver: up
 until now only the ones that mount the following image sensors are supported;
@@ -217,6 +231,7 @@
 Model       Manufacturer
 -----       ------------
 PAS202BCB   PixArt Imaging, Inc.
+PB-0330     Photobit Corporation
 
 
 9. Notes for V4L2 application developers
@@ -250,5 +265,6 @@
   been taken from the documentation of the ZC030x Video4Linux1 driver written
   by Andrew Birkett <andy@nobugs.org>;
 - The initialization values of the ZC0301 controller connected to the PAS202BCB
-  image sensor have been taken from the SPCA5XX driver maintained by
-  Michel Xhaard <mxhaard@magic.fr>.
+  and PB-0330 image sensors have been taken from the SPCA5XX driver maintained
+  by Michel Xhaard <mxhaard@magic.fr>;
+- Stanislav Lechev donated one camera.
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index f2cd6ef..6887d44 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -205,6 +205,27 @@
   pages  Prereserve that many 128K pages for the software IO bounce buffering.
   force  Force all IO through the software TLB.
 
+  calgary=[64k,128k,256k,512k,1M,2M,4M,8M]
+  calgary=[translate_empty_slots]
+  calgary=[disable=<PCI bus number>]
+
+    64k,...,8M - Set the size of each PCI slot's translation table
+    when using the Calgary IOMMU. This is the size of the translation
+    table itself in main memory. The smallest table, 64k, covers an IO
+    space of 32MB; the largest, 8MB table, can cover an IO space of
+    4GB. Normally the kernel will make the right choice by itself.
+
+    translate_empty_slots - Enable translation even on slots that have
+    no devices attached to them, in case a device will be hotplugged
+    in the future.
+
+    disable=<PCI bus number> - Disable translation on a given PHB. For
+    example, the built-in graphics adapter resides on the first bridge
+    (PCI bus number 0); if translation (isolation) is enabled on this
+    bridge, X servers that access the hardware directly from user
+    space might stop working. Use this option if you have devices that
+    are accessed from userspace directly on some PCI host bridge.
+
 Debugging
 
   oops=panic Always panic on oopses. Default is to just kill the process,
diff --git a/MAINTAINERS b/MAINTAINERS
index 4dcd2f1..31a1372 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1118,6 +1118,11 @@
 W:	http://www.lm-sensors.nu/
 S:	Maintained
 
+HARDWARE RANDOM NUMBER GENERATOR CORE
+P:	Michael Buesch
+M:	mb@bu3sch.de
+S:	Maintained
+
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 P:	Robert Love
 M:	rlove@rlove.org
@@ -1396,7 +1401,8 @@
 
 INPUT (KEYBOARD, MOUSE, JOYSTICK) DRIVERS
 P:	Dmitry Torokhov
-M:	dtor_core@ameritech.net
+M:	dmitry.torokhov@gmail.com
+M:	dtor@mail.ru
 L:	linux-input@atrey.karlin.mff.cuni.cz
 L:	linux-joystick@atrey.karlin.mff.cuni.cz
 T:	git kernel.org:/pub/scm/linux/kernel/git/dtor/input.git
@@ -1436,6 +1442,11 @@
 M:	tigran@veritas.com
 S:	Maintained
 
+INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
+P:	Deepak Saxena
+M:	dsaxena@plexity.net
+S:	Maintained
+
 INTEL PRO/100 ETHERNET SUPPORT
 P:	John Ronciak
 M:	john.ronciak@intel.com
@@ -2725,6 +2736,11 @@
 M:	hch@infradead.org
 S:	Maintained
 
+TI OMAP RANDOM NUMBER GENERATOR SUPPORT
+P:	Deepak Saxena
+M:	dsaxena@plexity.net
+S:	Maintained
+
 TI PARALLEL LINK CABLE DRIVER
 P:     Romain Lievin
 M:     roms@lpg.ticalc.org
diff --git a/Makefile b/Makefile
index 1700d3f..e9560c6 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,7 @@
 # In both cases the working directory must be the root of the kernel src.
 # 1) O=
 # Use "make O=dir/to/store/output/files/"
-# 
+#
 # 2) Set KBUILD_OUTPUT
 # Set the environment variable KBUILD_OUTPUT to point to the directory
 # where the output files shall be placed.
@@ -178,18 +178,20 @@
 # Architecture as present in compile.h
 UTS_MACHINE := $(ARCH)
 
+KCONFIG_CONFIG	?= .config
+
 # SHELL used by kbuild
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
 	  else if [ -x /bin/bash ]; then echo /bin/bash; \
 	  else echo sh; fi ; fi)
 
-HOSTCC  	= gcc
-HOSTCXX  	= g++
-HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-HOSTCXXFLAGS	= -O2
+HOSTCC       = gcc
+HOSTCXX      = g++
+HOSTCFLAGS   = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCXXFLAGS = -O2
 
-# 	Decide whether to build built-in, modular, or both.
-#	Normally, just do built-in.
+# Decide whether to build built-in, modular, or both.
+# Normally, just do built-in.
 
 KBUILD_MODULES :=
 KBUILD_BUILTIN := 1
@@ -197,7 +199,7 @@
 #	If we have only "make modules", don't compile built-in objects.
 #	When we're building modules with modversions, we need to consider
 #	the built-in objects during the descend as well, in order to
-#	make sure the checksums are uptodate before we record them.
+#	make sure the checksums are up to date before we record them.
 
 ifeq ($(MAKECMDGOALS),modules)
   KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
@@ -230,7 +232,7 @@
 #
 # If $(quiet) is empty, the whole command will be printed.
 # If it is set to "quiet_", only the short version will be printed. 
-# If it is set to "silent_", nothing wil be printed at all, since
+# If it is set to "silent_", nothing will be printed at all, since
 # the variable $(silent_cmd_cc_o_c) doesn't exist.
 #
 # A simple variant is to prefix commands with $(Q) - that's useful
@@ -265,10 +267,9 @@
 # We need some generic definitions
 include  $(srctree)/scripts/Kbuild.include
 
-# For maximum performance (+ possibly random breakage, uncomment
-# the following)
-
-#MAKEFLAGS += -rR
+# Do not use make's built-in rules and variables
+# This increases performance and avoid hard-to-debug behavour
+MAKEFLAGS += -rR
 
 # Make variables (CC, etc...)
 
@@ -305,21 +306,21 @@
 
 CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE)
 
-CFLAGS 		:= -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-	  	   -fno-strict-aliasing -fno-common
-AFLAGS		:= -D__ASSEMBLY__
+CFLAGS          := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
+                   -fno-strict-aliasing -fno-common
+AFLAGS          := -D__ASSEMBLY__
 
-# Read KERNELRELEASE from .kernelrelease (if it exists)
-KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null)
+# Read KERNELRELEASE from include/config/kernel.release (if it exists)
+KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
 KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
-export	VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \
-	ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
-	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \
-	HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
+export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
+export ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
+export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE
+export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
 
 export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
-export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE 
+export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
 export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 
 # When compiling out-of-tree modules, put MODVERDIR in the module
@@ -357,12 +358,13 @@
 # catch them early, and hand them over to scripts/kconfig/Makefile
 # It is allowed to specify more targets when calling make, including
 # mixing *config targets and build targets.
-# For example 'make oldconfig all'. 
+# For example 'make oldconfig all'.
 # Detect when mixed targets is specified, and make a second invocation
 # of make so .config is not included in this case either (for *config).
 
 no-dot-config-targets := clean mrproper distclean \
-			 cscope TAGS tags help %docs check%
+			 cscope TAGS tags help %docs check% \
+			 kernelrelease kernelversion
 
 config-targets := 0
 mixed-targets  := 0
@@ -404,9 +406,8 @@
 export KBUILD_DEFCONFIG
 
 config %config: scripts_basic outputmakefile FORCE
-	$(Q)mkdir -p include/linux
+	$(Q)mkdir -p include/linux include/config
 	$(Q)$(MAKE) $(build)=scripts/kconfig $@
-	$(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease
 
 else
 # ===========================================================================
@@ -416,13 +417,11 @@
 ifeq ($(KBUILD_EXTMOD),)
 # Additional helpers built in scripts/
 # Carefully list dependencies so we do not try to build scripts twice
-# in parrallel
+# in parallel
 PHONY += scripts
-scripts: scripts_basic include/config/MARKER
+scripts: scripts_basic include/config/auto.conf
 	$(Q)$(MAKE) $(build)=$(@)
 
-scripts_basic: include/linux/autoconf.h
-
 # Objects we will link into vmlinux / subdirs we need to visit
 init-y		:= init/
 drivers-y	:= drivers/ sound/
@@ -436,31 +435,32 @@
 
 # Read in dependencies to all Kconfig* files, make sure to run
 # oldconfig if changes are detected.
--include .kconfig.d
+-include include/config/auto.conf.cmd
+-include include/config/auto.conf
 
-include .config
-
-# If .config needs to be updated, it will be done via the dependency
-# that autoconf has on .config.
 # To avoid any implicit rule to kick in, define an empty command
-.config .kconfig.d: ;
+$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
 
-# If .config is newer than include/linux/autoconf.h, someone tinkered
+# If .config is newer than include/config/auto.conf, someone tinkered
 # with it and forgot to run make oldconfig.
-# If kconfig.d is missing then we are probarly in a cleaned tree so
+# if auto.conf.cmd is missing then we are probably in a cleaned tree so
 # we execute the config step to be sure to catch updated Kconfig files
-include/linux/autoconf.h: .kconfig.d .config
-	$(Q)mkdir -p include/linux
+include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
+ifeq ($(KBUILD_EXTMOD),)
 	$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
 else
+	$(error kernel configuration not valid - run 'make prepare' in $(srctree) to update it)
+endif
+
+else
 # Dummy target needed, because used as prerequisite
-include/linux/autoconf.h: ;
+include/config/auto.conf: ;
 endif
 
 # The all: target is the default when no target is given on the
 # command line.
 # This allow a user to issue only 'make' to build a kernel including modules
-# Defaults vmlinux but it is usually overriden in the arch makefile
+# Defaults vmlinux but it is usually overridden in the arch makefile
 all: vmlinux
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
@@ -492,11 +492,11 @@
 # warn about C99 declaration after statement
 CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
-# disable pointer signedness warnings in gcc 4.0
+# disable pointer signed / unsigned warnings in gcc 4.0
 CFLAGS += $(call cc-option,-Wno-pointer-sign,)
 
 # Default kernel image to build when no specific target is given.
-# KBUILD_IMAGE may be overruled on the commandline or
+# KBUILD_IMAGE may be overruled on the command line or
 # set in the environment
 # Also any assignments in arch/$(ARCH)/Makefile take precedence over
 # this default value
@@ -510,12 +510,29 @@
 #
 # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
 # relocations required by build roots.  This is not defined in the
-# makefile but the arguement can be passed to make if needed.
+# makefile but the argument can be passed to make if needed.
 #
 
 MODLIB	= $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
 export MODLIB
 
+#
+#  INSTALL_MOD_STRIP, if defined, will cause modules to be
+#  stripped after they are installed.  If INSTALL_MOD_STRIP is '1', then
+#  the default option --strip-debug will be used.  Otherwise,
+#  INSTALL_MOD_STRIP will used as the options to the strip command.
+
+ifdef INSTALL_MOD_STRIP
+ifeq ($(INSTALL_MOD_STRIP),1)
+mod_strip_cmd = $STRIP) --strip-debug
+else
+mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP)
+endif # INSTALL_MOD_STRIP=1
+else
+mod_strip_cmd = true
+endif # INSTALL_MOD_STRIP
+export mod_strip_cmd
+
 
 ifeq ($(KBUILD_EXTMOD),)
 core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/
@@ -539,7 +556,7 @@
 
 # Build vmlinux
 # ---------------------------------------------------------------------------
-# vmlinux is build from the objects selected by $(vmlinux-init) and
+# vmlinux is built from the objects selected by $(vmlinux-init) and
 # $(vmlinux-main). Most are built-in.o files from top-level directories
 # in the kernel tree, others are specified in arch/$(ARCH)Makefile.
 # Ordering when linking is important, and $(vmlinux-init) must be first.
@@ -590,7 +607,7 @@
 	$(MAKE) $(build)=init
 
 # Generate System.map
-quiet_cmd_sysmap = SYSMAP 
+quiet_cmd_sysmap = SYSMAP
       cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
 
 # Link of vmlinux
@@ -719,7 +736,7 @@
 	$(Q)$(MAKE) $(build)=$@
 
 # Build the kernel release string
-# The KERNELRELEASE is stored in a file named .kernelrelease
+# The KERNELRELEASE is stored in a file named include/config/kernel.release
 # to be used when executing for example make install or make modules_install
 #
 # Take the contents of any files called localversion* and the config
@@ -737,10 +754,10 @@
 localver = $(subst $(space),, \
 	   $(shell cat /dev/null $(_localver)) \
 	   $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
-	       
+
 # If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
 # and if the SCM is know a tag from the SCM is appended.
-# The appended tag is determinded by the SCM used.
+# The appended tag is determined by the SCM used.
 #
 # Currently, only git is supported.
 # Other SCMs can edit scripts/setlocalversion and add the appropriate
@@ -753,9 +770,9 @@
 
 localver-full = $(localver)$(localver-auto)
 
-# Store (new) KERNELRELASE string in .kernelrelease
+# Store (new) KERNELRELASE string in include/config/kernel.release
 kernelrelease = $(KERNELVERSION)$(localver-full)
-.kernelrelease: FORCE
+include/config/kernel.release: include/config/auto.conf FORCE
 	$(Q)rm -f $@
 	$(Q)echo $(kernelrelease) > $@
 
@@ -776,10 +793,10 @@
 # and if so do:
 # 1) Check that make has not been executed in the kernel src $(srctree)
 # 2) Create the include2 directory, used for the second asm symlink
-prepare3: .kernelrelease
+prepare3: include/config/kernel.release
 ifneq ($(KBUILD_SRC),)
 	@echo '  Using $(srctree) as source for kernel'
-	$(Q)if [ -f $(srctree)/.config ]; then \
+	$(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
 		echo "  $(srctree) is not clean, please run 'make mrproper'";\
 		echo "  in the '$(srctree)' directory.";\
 		/bin/false; \
@@ -792,7 +809,7 @@
 prepare2: prepare3 outputmakefile
 
 prepare1: prepare2 include/linux/version.h include/asm \
-                   include/config/MARKER
+                   include/config/auto.conf
 ifneq ($(KBUILD_MODULES),)
 	$(Q)mkdir -p $(MODVERDIR)
 	$(Q)rm -f $(MODVERDIR)/*
@@ -806,27 +823,20 @@
 # All the preparing..
 prepare prepare-all: prepare0
 
-#	Leave this as default for preprocessing vmlinux.lds.S, which is now
-#	done in arch/$(ARCH)/kernel/Makefile
+# Leave this as default for preprocessing vmlinux.lds.S, which is now
+# done in arch/$(ARCH)/kernel/Makefile
 
 export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
 
-# 	FIXME: The asm symlink changes when $(ARCH) changes. That's
-#	hard to detect, but I suppose "make mrproper" is a good idea
-#	before switching between archs anyway.
+# FIXME: The asm symlink changes when $(ARCH) changes. That's
+# hard to detect, but I suppose "make mrproper" is a good idea
+# before switching between archs anyway.
 
 include/asm:
 	@echo '  SYMLINK $@ -> include/asm-$(ARCH)'
 	$(Q)if [ ! -d include ]; then mkdir -p include; fi;
 	@ln -fsn asm-$(ARCH) $@
 
-# 	Split autoconf.h into include/linux/config/*
-
-include/config/MARKER: scripts/basic/split-include include/linux/autoconf.h
-	@echo '  SPLIT   include/linux/autoconf.h -> include/config/*'
-	@scripts/basic/split-include include/linux/autoconf.h include/config
-	@touch $@
-
 # Generate some files
 # ---------------------------------------------------------------------------
 
@@ -846,7 +856,7 @@
 	)
 endef
 
-include/linux/version.h: $(srctree)/Makefile .config .kernelrelease FORCE
+include/linux/version.h: $(srctree)/Makefile include/config/kernel.release FORCE
 	$(call filechk,version.h)
 
 # ---------------------------------------------------------------------------
@@ -860,7 +870,7 @@
 
 ifdef CONFIG_MODULES
 
-# 	By default, build modules as well
+# By default, build modules as well
 
 all: modules
 
@@ -942,7 +952,7 @@
 MRPROPER_DIRS  += include/config include2
 MRPROPER_FILES += .config .config.old include/asm .version .old_version \
                   include/linux/autoconf.h include/linux/version.h \
-		  .kernelrelease Module.symvers tags TAGS cscope*
+		  Module.symvers tags TAGS cscope*
 
 # clean - Delete most, but leave enough to build external modules
 #
@@ -958,8 +968,9 @@
 	$(call cmd,rmdirs)
 	$(call cmd,rmfiles)
 	@find . $(RCS_FIND_IGNORE) \
-	 	\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
+		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
+		-o -name '*.symtypes' \) \
 		-type f -print | xargs rm -f
 
 # mrproper - Delete all generated files, including .config
@@ -982,9 +993,9 @@
 
 distclean: mrproper
 	@find $(srctree) $(RCS_FIND_IGNORE) \
-	 	\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+		\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
 		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
-	 	-o -name '.*.rej' -o -size 0 \
+		-o -name '.*.rej' -o -size 0 \
 		-o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
 		-type f -print | xargs rm -f
 
@@ -994,9 +1005,9 @@
 # rpm target kept for backward compatibility
 package-dir	:= $(srctree)/scripts/package
 
-%pkg: FORCE
+%pkg: include/config/kernel.release FORCE
 	$(Q)$(MAKE) $(build)=$(package-dir) $@
-rpm: FORCE
+rpm: include/config/kernel.release FORCE
 	$(Q)$(MAKE) $(build)=$(package-dir) $@
 
 
@@ -1077,7 +1088,7 @@
 # make M=dir modules   Make all modules in specified dir
 # make M=dir	       Same as 'make M=dir modules'
 # make M=dir modules_install
-#                      Install the modules build in the module directory
+#                      Install the modules built in the module directory
 #                      Assumes install directory is already created
 
 # We are always building modules
@@ -1136,7 +1147,7 @@
 clean: $(clean-dirs)
 	$(call cmd,rmdirs)
 	@find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \
-	 	\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
+		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
 		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \
 		-type f -print | xargs rm -f
 
@@ -1175,31 +1186,41 @@
 ALLINCLUDE_ARCHS := $(ARCH)
 endif
 else
-#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behavour.
 ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
 endif
 
 ALLSOURCE_ARCHS := $(ARCH)
 
-define all-sources
-	( find $(__srctree) $(RCS_FIND_IGNORE) \
+define find-sources
+        ( find $(__srctree) $(RCS_FIND_IGNORE) \
 	       \( -name include -o -name arch \) -prune -o \
-	       -name '*.[chS]' -print; \
+	       -name $1 -print; \
 	  for ARCH in $(ALLSOURCE_ARCHS) ; do \
 	       find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
-	            -name '*.[chS]' -print; \
+	            -name $1 -print; \
 	  done ; \
 	  find $(__srctree)security/selinux/include $(RCS_FIND_IGNORE) \
-	       -name '*.[chS]' -print; \
+	       -name $1 -print; \
 	  find $(__srctree)include $(RCS_FIND_IGNORE) \
 	       \( -name config -o -name 'asm-*' \) -prune \
-	       -o -name '*.[chS]' -print; \
+	       -o -name $1 -print; \
 	  for ARCH in $(ALLINCLUDE_ARCHS) ; do \
 	       find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
-	            -name '*.[chS]' -print; \
+	            -name $1 -print; \
 	  done ; \
 	  find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
-	       -name '*.[chS]' -print )
+	       -name $1 -print )
+endef
+
+define all-sources
+	$(call find-sources,'*.[chS]')
+endef
+define all-kconfigs
+	$(call find-sources,'Kconfig*')
+endef
+define all-defconfigs
+	$(call find-sources,'defconfig')
 endef
 
 quiet_cmd_cscope-file = FILELST cscope.files
@@ -1219,7 +1240,13 @@
                 echo "-I __initdata,__exitdata,__acquires,__releases  \
                       -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL              \
                       --extra=+f --c-kinds=+px"`;                     \
-                $(all-sources) | xargs etags $$ETAGSF -a
+                $(all-sources) | xargs etags $$ETAGSF -a;             \
+	if test "x$$ETAGSF" = x; then                                 \
+		$(all-kconfigs) | xargs etags -a                      \
+		--regex='/^config[ \t]+\([a-zA-Z0-9_]+\)/\1/';        \
+		$(all-defconfigs) | xargs etags -a                    \
+		--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/';     \
+	fi
 endef
 
 TAGS: FORCE
@@ -1259,14 +1286,14 @@
 endif #ifeq ($(config-targets),1)
 endif #ifeq ($(mixed-targets),1)
 
-PHONY += checkstack
+PHONY += checkstack kernelrelease kernelversion
 checkstack:
 	$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
 	$(PERL) $(src)/scripts/checkstack.pl $(ARCH)
 
 kernelrelease:
-	$(if $(wildcard .kernelrelease), $(Q)echo $(KERNELRELEASE), \
-	$(error kernelrelease not valid - run 'make *config' to update it))
+	$(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
+	$(error kernelrelease not valid - run 'make prepare' to update it))
 kernelversion:
 	@echo $(KERNELVERSION)
 
@@ -1301,6 +1328,8 @@
 	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
 %.o: %.S prepare scripts FORCE
 	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+%.symtypes: %.c prepare scripts FORCE
+	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
 
 # Modules
 / %/: prepare scripts FORCE
diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c
index ba788cf..9fc0eeb 100644
--- a/arch/alpha/oprofile/common.c
+++ b/arch/alpha/oprofile/common.c
@@ -112,7 +112,7 @@
 
 	for (i = 0; i < model->num_counters; ++i) {
 		struct dentry *dir;
-		char buf[3];
+		char buf[4];
 
 		snprintf(buf, sizeof buf, "%d", i);
 		dir = oprofilefs_mkdir(sb, root, buf);
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 282b14e..a3bbaaf 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -177,7 +177,7 @@
 #	them changed.  We use .arch to indicate when they were updated
 #	last, otherwise make uses the target directory mtime.
 
-include/asm-arm/.arch: $(wildcard include/config/arch/*.h) include/config/MARKER
+include/asm-arm/.arch: $(wildcard include/config/arch/*.h) include/config/auto.conf
 	@echo '  SYMLINK include/asm-arm/arch -> include/asm-arm/$(INCDIR)'
 ifneq ($(KBUILD_SRC),)
 	$(Q)mkdir -p include/asm-arm
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index a7dc137..0dafba3 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -629,21 +629,6 @@
 #endif
 
 
-#define LCM_ALC_EN	0x8000
-
-void frontlight_set(struct locomo *lchip, int duty, int vr, int bpwf)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&lchip->lock, flags);
-	locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
-	udelay(100);
-	locomo_writel(duty, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);
-	locomo_writel(bpwf | LCM_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
-	spin_unlock_irqrestore(&lchip->lock, flags);
-}
-
-
 /**
  *	locomo_probe - probe for a single LoCoMo chip.
  *	@phys_addr: physical address of device.
@@ -698,14 +683,10 @@
 			, lchip->base + LOCOMO_GPD);
 	locomo_writel(0, lchip->base + LOCOMO_GIE);
 
-	/* FrontLight */
+	/* Frontlight */
 	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
 	locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);
 
-	/* Same constants can be used for collie and poodle
-	   (depending on CONFIG options in original sharp code)? */
-	frontlight_set(lchip, 163, 0, 148);
-
 	/* Longtime timer */
 	locomo_writel(0, lchip->base + LOCOMO_LTINT);
 	/* SPI */
@@ -1063,6 +1044,30 @@
 }
 
 /*
+ *	Frontlight control
+ */
+
+static struct locomo *locomo_chip_driver(struct locomo_dev *ldev);
+
+void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf)
+{
+	unsigned long flags;
+	struct locomo *lchip = locomo_chip_driver(dev);
+
+	if (vr)
+		locomo_gpio_write(dev, LOCOMO_GPIO_FL_VR, 1);
+	else
+		locomo_gpio_write(dev, LOCOMO_GPIO_FL_VR, 0);
+
+	spin_lock_irqsave(&lchip->lock, flags);
+	locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
+	udelay(100);
+	locomo_writel(duty, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD);
+	locomo_writel(bpwf | LOCOMO_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
+	spin_unlock_irqrestore(&lchip->lock, flags);
+}
+
+/*
  *	LoCoMo "Register Access Bus."
  *
  *	We model this as a regular bus type, and hang devices directly
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index de606df..302fc14 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -702,7 +702,6 @@
 	/*
 	 * Mark this as IO
 	 */
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	if (remap_pfn_range(vma, vma->vm_start, phys,
diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c
index 99d333d..a3745ed 100644
--- a/arch/arm/mach-ixp4xx/nas100d-power.c
+++ b/arch/arm/mach-ixp4xx/nas100d-power.c
@@ -20,11 +20,10 @@
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 
 #include <asm/mach-types.h>
 
-extern void ctrl_alt_del(void);
-
 static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
 	/* Signal init to do the ctrlaltdel action, this will bypass init if
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
index d80c362..6d38e97 100644
--- a/arch/arm/mach-ixp4xx/nslu2-power.c
+++ b/arch/arm/mach-ixp4xx/nslu2-power.c
@@ -20,11 +20,10 @@
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 
 #include <asm/mach-types.h>
 
-extern void ctrl_alt_del(void);
-
 static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
 	/* Signal init to do the ctrlaltdel action, this will bypass init if
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 24bc149..1e9d062 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -27,8 +27,6 @@
 	/* Leave vm_pgoff as-is, the PCI space address is the physical
 	 * address on this platform.
 	 */
-	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
 	prot = pgprot_val(vma->vm_page_prot);
 	vma->vm_page_prot = __pgprot(prot);
 
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 1596101..47c08bc 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -14,6 +14,10 @@
 	  486, 586, Pentiums, and various instruction-set-compatible chips by
 	  AMD, Cyrix, and others.
 
+config GENERIC_TIME
+	bool
+	default y
+
 config SEMAPHORE_SLEEPERS
 	bool
 	default y
@@ -324,6 +328,15 @@
 	  Enabling this feature will cause a message to be printed when the P4
 	  enters thermal throttling.
 
+config VM86
+	default y
+	bool "Enable VM86 support" if EMBEDDED
+	help
+          This option is required by programs like DOSEMU to run 16-bit legacy
+	  code on X86 processors. It also may be needed by software like
+          XFree86 to initialize some video cards via BIOS. Disabling this
+          option saves about 6k.
+
 config TOSHIBA
 	tristate "Toshiba Laptop support"
 	---help---
@@ -721,7 +734,7 @@
 	help
 	  kexec is a system call that implements the ability to shutdown your
 	  current kernel, and to start another kernel.  It is like a reboot
-	  but it is indepedent of the system firmware.   And like a reboot
+	  but it is independent of the system firmware.   And like a reboot
 	  you can start any kernel with it, not just Linux.
 
 	  The name comes from the similiarity to the exec system call.
@@ -1046,13 +1059,27 @@
 	tristate "NatSemi SCx200 support"
 	depends on !X86_VOYAGER
 	help
-	  This provides basic support for the National Semiconductor SCx200
-	  processor.  Right now this is just a driver for the GPIO pins.
+	  This provides basic support for National Semiconductor's
+	  (now AMD's) Geode processors.  The driver probes for the
+	  PCI-IDs of several on-chip devices, so its a good dependency
+	  for other scx200_* drivers.
 
-	  If you don't know what to do here, say N.
+	  If compiled as a module, the driver is named scx200.
 
-	  This support is also available as a module.  If compiled as a
-	  module, it will be called scx200.
+config SCx200HR_TIMER
+	tristate "NatSemi SCx200 27MHz High-Resolution Timer Support"
+	depends on SCx200 && GENERIC_TIME
+	default y
+	help
+	  This driver provides a clocksource built upon the on-chip
+	  27MHz high-resolution timer.  Its also a workaround for
+	  NSC Geode SC-1100's buggy TSC, which loses time when the
+	  processor goes idle (as is done by the scheduler).  The
+	  other workaround is idle=poll boot option.
+
+config K8_NB
+	def_bool y
+	depends on AGP_AMD64
 
 source "drivers/pcmcia/Kconfig"
 
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index eb13048..21c9a4e 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -41,7 +41,7 @@
 	  - "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
 	  - "Geode GX/LX" For AMD Geode GX and LX processors.
 	  - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
-	  - "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above).
+	  - "VIA C3-2" for VIA C3-2 "Nehemiah" (model 9 and above).
 
 	  If you don't know what to do, choose "386".
 
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index 33e5547..e979466 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -109,8 +109,13 @@
 isoimage: $(BOOTIMAGE)
 	-rm -rf $(obj)/isoimage
 	mkdir $(obj)/isoimage
-	cp `echo /usr/lib*/syslinux/isolinux.bin | awk '{ print $1; }'` \
-		$(obj)/isoimage
+	for i in lib lib64 share end ; do \
+		if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
+			cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
+			break ; \
+		fi ; \
+		if [ $$i = end ] ; then exit 1 ; fi ; \
+	done
 	cp $(BOOTIMAGE) $(obj)/isoimage/linux
 	echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
 	if [ -f '$(FDINITRD)' ] ; then \
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index f19f3a7..b2ccd54 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -24,14 +24,6 @@
 
 #undef memset
 #undef memcpy
-
-/*
- * Why do we do this? Don't ask me..
- *
- * Incomprehensible are the ways of bootloaders.
- */
-static void* memset(void *, int, size_t);
-static void* memcpy(void *, __const void *, size_t);
 #define memzero(s, n)     memset ((s), 0, (n))
 
 typedef unsigned char  uch;
@@ -93,7 +85,7 @@
 #endif
 #define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
 
-extern char input_data[];
+extern unsigned char input_data[];
 extern int input_len;
 
 static long bytes_out = 0;
@@ -103,6 +95,9 @@
 static void *malloc(int size);
 static void free(void *where);
 
+static void *memset(void *s, int c, unsigned n);
+static void *memcpy(void *dest, const void *src, unsigned n);
+
 static void putstr(const char *);
 
 extern int end;
@@ -205,7 +200,7 @@
 	outb_p(0xff & (pos >> 1), vidport+1);
 }
 
-static void* memset(void* s, int c, size_t n)
+static void* memset(void* s, int c, unsigned n)
 {
 	int i;
 	char *ss = (char*)s;
@@ -214,14 +209,13 @@
 	return s;
 }
 
-static void* memcpy(void* __dest, __const void* __src,
-			    size_t __n)
+static void* memcpy(void* dest, const void* src, unsigned n)
 {
 	int i;
-	char *d = (char *)__dest, *s = (char *)__src;
+	char *d = (char *)dest, *s = (char *)src;
 
-	for (i=0;i<__n;i++) d[i] = s[i];
-	return __dest;
+	for (i=0;i<n;i++) d[i] = s[i];
+	return dest;
 }
 
 /* ===========================================================================
@@ -309,7 +303,7 @@
 #else
 	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
-	output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */
+	output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
 	free_mem_end_ptr = (long)real_mode;
 }
 
@@ -324,11 +318,9 @@
 #ifdef STANDARD_MEMORY_BIOS_CALL
 	if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
 #else
-	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) <
-			(3*1024))
-		error("Less than 4MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
 #endif	
-	mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
+	mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
 	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
 	  ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
 	low_buffer_size = low_buffer_end - LOW_BUFFER_START;
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index c9343c3..8c2a6fa 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -1929,7 +1929,7 @@
 	ret
 
 store_edid:
-#ifdef CONFIG_FB_FIRMWARE_EDID
+#ifdef CONFIG_FIRMWARE_EDID
 	pushw	%es				# just save all registers
 	pushw	%ax
 	pushw	%bx
@@ -1947,6 +1947,22 @@
 	rep
 	stosl
 
+	pushw   %es				# save ES
+	xorw    %di, %di                        # Report Capability
+	pushw   %di
+	popw    %es                             # ES:DI must be 0:0
+	movw	$0x4f15, %ax
+	xorw	%bx, %bx
+	xorw	%cx, %cx
+	int	$0x10
+	popw    %es                             # restore ES
+
+	cmpb    $0x00, %ah                      # call successful
+	jne     no_edid
+
+	cmpb    $0x4f, %al                      # function supported
+	jne     no_edid
+
 	movw	$0x4f15, %ax                    # do VBE/DDC
 	movw	$0x01, %bx
 	movw	$0x00, %cx
@@ -1954,6 +1970,7 @@
 	movw	$0x140, %di
 	int	$0x10
 
+no_edid:
 	popw	%di				# restore all registers
 	popw	%dx
 	popw	%cx
diff --git a/arch/i386/crypto/aes-i586-asm.S b/arch/i386/crypto/aes-i586-asm.S
index 911b153..f942f0c 100644
--- a/arch/i386/crypto/aes-i586-asm.S
+++ b/arch/i386/crypto/aes-i586-asm.S
@@ -36,22 +36,19 @@
 .file "aes-i586-asm.S"
 .text
 
-// aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])//
-// aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])//
-	
+#include <asm/asm-offsets.h>
+
 #define tlen 1024   // length of each of 4 'xor' arrays (256 32-bit words)
 
-// offsets to parameters with one register pushed onto stack
+/* offsets to parameters with one register pushed onto stack */
+#define tfm 8
+#define out_blk 12
+#define in_blk 16
 
-#define in_blk    8  // input byte array address parameter
-#define out_blk  12  // output byte array address parameter
-#define ctx      16  // AES context structure
-
-// offsets in context structure
-
-#define ekey     0   // encryption key schedule base address
-#define nrnd   256   // number of rounds
-#define dkey   260   // decryption key schedule base address
+/* offsets in crypto_tfm structure */
+#define ekey (crypto_tfm_ctx_offset + 0)
+#define nrnd (crypto_tfm_ctx_offset + 256)
+#define dkey (crypto_tfm_ctx_offset + 260)
 
 // register mapping for encrypt and decrypt subroutines
 
@@ -220,6 +217,7 @@
 	do_col (table, r5,r0,r1,r4, r2,r3);		/* idx=r5 */
 
 // AES (Rijndael) Encryption Subroutine
+/* void aes_enc_blk(struct crypto_tfm *tfm, u8 *out_blk, const u8 *in_blk) */
 
 .global  aes_enc_blk
 
@@ -230,7 +228,7 @@
 
 aes_enc_blk:
 	push    %ebp
-	mov     ctx(%esp),%ebp      // pointer to context
+	mov     tfm(%esp),%ebp
 
 // CAUTION: the order and the values used in these assigns 
 // rely on the register mappings
@@ -295,6 +293,7 @@
 	ret
 
 // AES (Rijndael) Decryption Subroutine
+/* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out_blk, const u8 *in_blk) */
 
 .global  aes_dec_blk
 
@@ -305,7 +304,7 @@
 
 aes_dec_blk:
 	push    %ebp
-	mov     ctx(%esp),%ebp       // pointer to context
+	mov     tfm(%esp),%ebp
 
 // CAUTION: the order and the values used in these assigns 
 // rely on the register mappings
diff --git a/arch/i386/crypto/aes.c b/arch/i386/crypto/aes.c
index a50397b..d3806da 100644
--- a/arch/i386/crypto/aes.c
+++ b/arch/i386/crypto/aes.c
@@ -45,8 +45,8 @@
 #include <linux/crypto.h>
 #include <linux/linkage.h>
 
-asmlinkage void aes_enc_blk(const u8 *src, u8 *dst, void *ctx);
-asmlinkage void aes_dec_blk(const u8 *src, u8 *dst, void *ctx);
+asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 
 #define AES_MIN_KEY_SIZE	16
 #define AES_MAX_KEY_SIZE	32
@@ -378,12 +378,12 @@
 	k[8*(i)+11] = ss[3];						\
 }
 
-static int
-aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len, u32 *flags)
 {
 	int i;
 	u32 ss[8];
-	struct aes_ctx *ctx = ctx_arg;
+	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 
 	/* encryption schedule */
@@ -464,15 +464,15 @@
 	return 0;
 }
 
-static inline void aes_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	aes_enc_blk(src, dst, ctx);
-}
-static inline void aes_decrypt(void *ctx, u8 *dst, const u8 *src)
-{
-	aes_dec_blk(src, dst, ctx);
+	aes_enc_blk(tfm, dst, src);
 }
 
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	aes_dec_blk(tfm, dst, src);
+}
 
 static struct crypto_alg aes_alg = {
 	.cra_name		=	"aes",
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 96fb8a0..5e70c2f 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -7,10 +7,9 @@
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o \
 		ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
 		pci-dma.o i386_ksyms.o i387.o bootflag.o \
-		quirks.o i8237.o topology.o alternative.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc.o
 
 obj-y				+= cpu/
-obj-y				+= timers/
 obj-y				+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
@@ -37,6 +36,8 @@
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault.o
 obj-$(CONFIG_VM86)		+= vm86.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
+obj-$(CONFIG_K8_NB)		+= k8.o
 
 EXTRA_AFLAGS   := -traditional
 
@@ -76,3 +77,6 @@
 $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
 			$(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE
 	$(call if_changed,syscall)
+
+k8-y                      += ../../x86_64/kernel/k8.o
+
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index 5cbd6f9..50eb0e0 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -4,27 +4,41 @@
 #include <asm/alternative.h>
 #include <asm/sections.h>
 
-#define DEBUG 0
-#if DEBUG
-# define DPRINTK(fmt, args...) printk(fmt, args)
-#else
-# define DPRINTK(fmt, args...)
-#endif
+static int no_replacement    = 0;
+static int smp_alt_once      = 0;
+static int debug_alternative = 0;
 
+static int __init noreplacement_setup(char *s)
+{
+	no_replacement = 1;
+	return 1;
+}
+static int __init bootonly(char *str)
+{
+	smp_alt_once = 1;
+	return 1;
+}
+static int __init debug_alt(char *str)
+{
+	debug_alternative = 1;
+	return 1;
+}
+
+__setup("noreplacement", noreplacement_setup);
+__setup("smp-alt-boot", bootonly);
+__setup("debug-alternative", debug_alt);
+
+#define DPRINTK(fmt, args...) if (debug_alternative) \
+	printk(KERN_DEBUG fmt, args)
+
+#ifdef GENERIC_NOP1
 /* Use inline assembly to define this because the nops are defined
    as inline assembly strings in the include files and we cannot
    get them easily into strings. */
 asm("\t.data\nintelnops: "
 	GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6
 	GENERIC_NOP7 GENERIC_NOP8);
-asm("\t.data\nk8nops: "
-	K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
-	K8_NOP7 K8_NOP8);
-asm("\t.data\nk7nops: "
-	K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6
-	K7_NOP7 K7_NOP8);
-
-extern unsigned char intelnops[], k8nops[], k7nops[];
+extern unsigned char intelnops[];
 static unsigned char *intel_nops[ASM_NOP_MAX+1] = {
 	NULL,
 	intelnops,
@@ -36,6 +50,13 @@
 	intelnops + 1 + 2 + 3 + 4 + 5 + 6,
 	intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
 };
+#endif
+
+#ifdef K8_NOP1
+asm("\t.data\nk8nops: "
+	K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
+	K8_NOP7 K8_NOP8);
+extern unsigned char k8nops[];
 static unsigned char *k8_nops[ASM_NOP_MAX+1] = {
 	NULL,
 	k8nops,
@@ -47,6 +68,13 @@
 	k8nops + 1 + 2 + 3 + 4 + 5 + 6,
 	k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
 };
+#endif
+
+#ifdef K7_NOP1
+asm("\t.data\nk7nops: "
+	K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6
+	K7_NOP7 K7_NOP8);
+extern unsigned char k7nops[];
 static unsigned char *k7_nops[ASM_NOP_MAX+1] = {
 	NULL,
 	k7nops,
@@ -58,6 +86,18 @@
 	k7nops + 1 + 2 + 3 + 4 + 5 + 6,
 	k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
 };
+#endif
+
+#ifdef CONFIG_X86_64
+
+extern char __vsyscall_0;
+static inline unsigned char** find_nop_table(void)
+{
+	return k8_nops;
+}
+
+#else /* CONFIG_X86_64 */
+
 static struct nop {
 	int cpuid;
 	unsigned char **noptable;
@@ -67,14 +107,6 @@
 	{ -1, NULL }
 };
 
-
-extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
-extern struct alt_instr __smp_alt_instructions[], __smp_alt_instructions_end[];
-extern u8 *__smp_locks[], *__smp_locks_end[];
-
-extern u8 __smp_alt_begin[], __smp_alt_end[];
-
-
 static unsigned char** find_nop_table(void)
 {
 	unsigned char **noptable = intel_nops;
@@ -89,6 +121,14 @@
 	return noptable;
 }
 
+#endif /* CONFIG_X86_64 */
+
+extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+extern struct alt_instr __smp_alt_instructions[], __smp_alt_instructions_end[];
+extern u8 *__smp_locks[], *__smp_locks_end[];
+
+extern u8 __smp_alt_begin[], __smp_alt_end[];
+
 /* Replace instructions with better alternatives for this CPU type.
    This runs before SMP is initialized to avoid SMP problems with
    self modifying code. This implies that assymetric systems where
@@ -99,6 +139,7 @@
 {
 	unsigned char **noptable = find_nop_table();
 	struct alt_instr *a;
+	u8 *instr;
 	int diff, i, k;
 
 	DPRINTK("%s: alt table %p -> %p\n", __FUNCTION__, start, end);
@@ -106,7 +147,16 @@
 		BUG_ON(a->replacementlen > a->instrlen);
 		if (!boot_cpu_has(a->cpuid))
 			continue;
-		memcpy(a->instr, a->replacement, a->replacementlen);
+		instr = a->instr;
+#ifdef CONFIG_X86_64
+		/* vsyscall code is not mapped yet. resolve it manually. */
+		if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END) {
+			instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0));
+			DPRINTK("%s: vsyscall fixup: %p => %p\n",
+				__FUNCTION__, a->instr, instr);
+		}
+#endif
+		memcpy(instr, a->replacement, a->replacementlen);
 		diff = a->instrlen - a->replacementlen;
 		/* Pad the rest with nops */
 		for (i = a->replacementlen; diff > 0; diff -= k, i += k) {
@@ -186,14 +236,6 @@
 static LIST_HEAD(smp_alt_modules);
 static DEFINE_SPINLOCK(smp_alt);
 
-static int smp_alt_once = 0;
-static int __init bootonly(char *str)
-{
-	smp_alt_once = 1;
-	return 1;
-}
-__setup("smp-alt-boot", bootonly);
-
 void alternatives_smp_module_add(struct module *mod, char *name,
 				 void *locks, void *locks_end,
 				 void *text,  void *text_end)
@@ -201,6 +243,9 @@
 	struct smp_alt_module *smp;
 	unsigned long flags;
 
+	if (no_replacement)
+		return;
+
 	if (smp_alt_once) {
 		if (boot_cpu_has(X86_FEATURE_UP))
 			alternatives_smp_unlock(locks, locks_end,
@@ -235,7 +280,7 @@
 	struct smp_alt_module *item;
 	unsigned long flags;
 
-	if (smp_alt_once)
+	if (no_replacement || smp_alt_once)
 		return;
 
 	spin_lock_irqsave(&smp_alt, flags);
@@ -256,7 +301,7 @@
 	struct smp_alt_module *mod;
 	unsigned long flags;
 
-	if (smp_alt_once)
+	if (no_replacement || smp_alt_once)
 		return;
 	BUG_ON(!smp && (num_online_cpus() > 1));
 
@@ -285,6 +330,13 @@
 
 void __init alternative_instructions(void)
 {
+	if (no_replacement) {
+		printk(KERN_INFO "(SMP-)alternatives turned off\n");
+		free_init_pages("SMP alternatives",
+				(unsigned long)__smp_alt_begin,
+				(unsigned long)__smp_alt_end);
+		return;
+	}
 	apply_alternatives(__alt_instructions, __alt_instructions_end);
 
 	/* switch to patch-once-at-boottime-only mode and free the
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 5ab59c1..7ce0949 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -36,6 +36,7 @@
 #include <asm/arch_hooks.h>
 #include <asm/hpet.h>
 #include <asm/i8253.h>
+#include <asm/nmi.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
@@ -156,7 +157,7 @@
 	maxlvt = get_maxlvt();
 
 	/*
-	 * Masking an LVT entry on a P6 can trigger a local APIC error
+	 * Masking an LVT entry can trigger a local APIC error
 	 * if the vector is zero. Mask LVTERR first to prevent this.
 	 */
 	if (maxlvt >= 3) {
@@ -1117,7 +1118,18 @@
 		unsigned long v;
 
 		v = apic_read(APIC_LVTT);
-		apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+		/*
+		 * When an illegal vector value (0-15) is written to an LVT
+		 * entry and delivery mode is Fixed, the APIC may signal an
+		 * illegal vector error, with out regard to whether the mask
+		 * bit is set or whether an interrupt is actually seen on input.
+		 *
+		 * Boot sequence might call this function when the LVTT has
+		 * '0' vector value. So make sure vector field is set to
+		 * valid value.
+		 */
+		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+		apic_write_around(APIC_LVTT, v);
 	}
 }
 
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 9e819eb..7c5729d 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -764,9 +764,9 @@
 	int	idled = 0;
 	int	polling;
 
-	polling = test_thread_flag(TIF_POLLING_NRFLAG);
+	polling = !!(current_thread_info()->status & TS_POLLING);
 	if (polling) {
-		clear_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status &= ~TS_POLLING;
 		smp_mb__after_clear_bit();
 	}
 	if (!need_resched()) {
@@ -774,7 +774,7 @@
 		ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax);
 	}
 	if (polling)
-		set_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status |= TS_POLLING;
 
 	if (!idled)
 		return 0;
diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
index 36d66e2..1c3a809 100644
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -4,6 +4,7 @@
  * to extract and format the required data.
  */
 
+#include <linux/crypto.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
@@ -69,4 +70,6 @@
 
 	DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
 	DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL));
+
+	OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
 }
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 786d1a5..fd0457c 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -224,15 +224,17 @@
 
 #ifdef CONFIG_X86_HT
 	/*
-	 * On a AMD dual core setup the lower bits of the APIC id
-	 * distingush the cores.  Assumes number of cores is a power
-	 * of two.
+	 * On a AMD multi core setup the lower bits of the APIC id
+	 * distingush the cores.
 	 */
 	if (c->x86_max_cores > 1) {
 		int cpu = smp_processor_id();
-		unsigned bits = 0;
-		while ((1 << bits) < c->x86_max_cores)
-			bits++;
+		unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
+
+		if (bits == 0) {
+			while ((1 << bits) < c->x86_max_cores)
+				bits++;
+		}
 		cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
 		phys_proc_id[cpu] >>= bits;
 		printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
@@ -240,6 +242,8 @@
 	}
 #endif
 
+	if (cpuid_eax(0x80000000) >= 0x80000006)
+		num_cache_leaves = 3;
 }
 
 static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index 05668e3..5fd6532 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -371,11 +371,11 @@
 
 	dprintk("acpi_cpufreq_early_init\n");
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		data = kzalloc(sizeof(struct acpi_processor_performance), 
 			GFP_KERNEL);
 		if (!data) {
-			for_each_cpu(j) {
+			for_each_possible_cpu(j) {
 				kfree(acpi_perf_data[j]);
 				acpi_perf_data[j] = NULL;
 			}
@@ -584,7 +584,7 @@
 
 	cpufreq_unregister_driver(&acpi_cpufreq_driver);
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		kfree(acpi_perf_data[i]);
 		acpi_perf_data[i] = NULL;
 	}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index 31c3a5b..f7e4356 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -361,11 +361,11 @@
 	unsigned int	i, j;
 	struct acpi_processor_performance	*data;
 
-	for_each_cpu(i) {
+	for_each_possible_cpu(i) {
 		data = kzalloc(sizeof(struct acpi_processor_performance), 
 				GFP_KERNEL);
 		if (!data) {
-			for_each_cpu(j) {
+			for_each_possible_cpu(j) {
 				kfree(acpi_perf_data[j]);
 				acpi_perf_data[j] = NULL;
 			}
@@ -805,7 +805,7 @@
 	cpufreq_unregister_driver(&centrino_driver);
 
 #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
-	for_each_cpu(j) {
+	for_each_possible_cpu(j) {
 		kfree(acpi_perf_data[j]);
 		acpi_perf_data[j] = NULL;
 	}
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index fc32c80..f03b7f9 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -354,7 +354,7 @@
 	 * This function only handles the GX processor, and kicks every
 	 * thing else to the Cyrix init function above - that should
 	 * cover any processors that might have been branded differently
-	 * after NSC aquired Cyrix.
+	 * after NSC acquired Cyrix.
 	 *
 	 * If this breaks your GX1 horribly, please e-mail
 	 * info-linux@ldcmail.amd.com to tell us.
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 5386b29..10afc64 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -122,6 +122,12 @@
 
 	select_idle_routine(c);
 	l2 = init_intel_cacheinfo(c);
+	if (c->cpuid_level > 9 ) {
+		unsigned eax = cpuid_eax(10);
+		/* Check for version and the number of counters */
+		if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
+			set_bit(X86_FEATURE_ARCH_PERFMON, c->x86_capability);
+	}
 
 	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it until model 3 mask 3 */
 	if ((c->x86<<8 | c->x86_model<<4 | c->x86_mask) < 0x633)
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index c8547a6..6c37b4f 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -4,6 +4,7 @@
  *      Changes:
  *      Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
  *		Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
+ *	Andi Kleen		: CPUID4 emulation on AMD.
  */
 
 #include <linux/init.h>
@@ -130,25 +131,111 @@
 	cpumask_t shared_cpu_map;
 };
 
-static unsigned short			num_cache_leaves;
+unsigned short			num_cache_leaves;
+
+/* AMD doesn't have CPUID4. Emulate it here to report the same
+   information to the user.  This makes some assumptions about the machine:
+   No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs.
+
+   In theory the TLBs could be reported as fake type (they are in "dummy").
+   Maybe later */
+union l1_cache {
+	struct {
+		unsigned line_size : 8;
+		unsigned lines_per_tag : 8;
+		unsigned assoc : 8;
+		unsigned size_in_kb : 8;
+	};
+	unsigned val;
+};
+
+union l2_cache {
+	struct {
+		unsigned line_size : 8;
+		unsigned lines_per_tag : 4;
+		unsigned assoc : 4;
+		unsigned size_in_kb : 16;
+	};
+	unsigned val;
+};
+
+static unsigned short assocs[] = {
+	[1] = 1, [2] = 2, [4] = 4, [6] = 8,
+	[8] = 16,
+	[0xf] = 0xffff // ??
+	};
+static unsigned char levels[] = { 1, 1, 2 };
+static unsigned char types[] = { 1, 2, 3 };
+
+static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
+		       union _cpuid4_leaf_ebx *ebx,
+		       union _cpuid4_leaf_ecx *ecx)
+{
+	unsigned dummy;
+	unsigned line_size, lines_per_tag, assoc, size_in_kb;
+	union l1_cache l1i, l1d;
+	union l2_cache l2;
+
+	eax->full = 0;
+	ebx->full = 0;
+	ecx->full = 0;
+
+	cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
+	cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy);
+
+	if (leaf > 2 || !l1d.val || !l1i.val || !l2.val)
+		return;
+
+	eax->split.is_self_initializing = 1;
+	eax->split.type = types[leaf];
+	eax->split.level = levels[leaf];
+	eax->split.num_threads_sharing = 0;
+	eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
+
+	if (leaf <= 1) {
+		union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
+		assoc = l1->assoc;
+		line_size = l1->line_size;
+		lines_per_tag = l1->lines_per_tag;
+		size_in_kb = l1->size_in_kb;
+	} else {
+		assoc = l2.assoc;
+		line_size = l2.line_size;
+		lines_per_tag = l2.lines_per_tag;
+		/* cpu_data has errata corrections for K7 applied */
+		size_in_kb = current_cpu_data.x86_cache_size;
+	}
+
+	if (assoc == 0xf)
+		eax->split.is_fully_associative = 1;
+	ebx->split.coherency_line_size = line_size - 1;
+	ebx->split.ways_of_associativity = assocs[assoc] - 1;
+	ebx->split.physical_line_partition = lines_per_tag - 1;
+	ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
+		(ebx->split.ways_of_associativity + 1) - 1;
+}
 
 static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
 {
-	unsigned int		eax, ebx, ecx, edx;
-	union _cpuid4_leaf_eax	cache_eax;
+	union _cpuid4_leaf_eax 	eax;
+	union _cpuid4_leaf_ebx 	ebx;
+	union _cpuid4_leaf_ecx 	ecx;
+	unsigned		edx;
 
-	cpuid_count(4, index, &eax, &ebx, &ecx, &edx);
-	cache_eax.full = eax;
-	if (cache_eax.split.type == CACHE_TYPE_NULL)
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+		amd_cpuid4(index, &eax, &ebx, &ecx);
+	else
+		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full,  &edx);
+	if (eax.split.type == CACHE_TYPE_NULL)
 		return -EIO; /* better error ? */
 
-	this_leaf->eax.full = eax;
-	this_leaf->ebx.full = ebx;
-	this_leaf->ecx.full = ecx;
-	this_leaf->size = (this_leaf->ecx.split.number_of_sets + 1) *
-		(this_leaf->ebx.split.coherency_line_size + 1) *
-		(this_leaf->ebx.split.physical_line_partition + 1) *
-		(this_leaf->ebx.split.ways_of_associativity + 1);
+	this_leaf->eax = eax;
+	this_leaf->ebx = ebx;
+	this_leaf->ecx = ecx;
+	this_leaf->size = (ecx.split.number_of_sets + 1) *
+		(ebx.split.coherency_line_size + 1) *
+		(ebx.split.physical_line_partition + 1) *
+		(ebx.split.ways_of_associativity + 1);
 	return 0;
 }
 
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index 2b0cfce..48f0f62 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -114,19 +114,15 @@
 	atomic_dec(&waiting_for_crash_ipi);
 	/* Assume hlt works */
 	halt();
-	for(;;);
+	for (;;)
+		cpu_relax();
 
 	return 1;
 }
 
-/*
- * By using the NMI code instead of a vector we just sneak thru the
- * word generator coming out with just what we want.  AND it does
- * not matter if clustered_apic_mode is set or not.
- */
 static void smp_send_nmi_allbutself(void)
 {
-	send_IPI_allbutself(APIC_DM_NMI);
+	send_IPI_allbutself(NMI_VECTOR);
 }
 
 static void nmi_shootdown_cpus(void)
@@ -162,7 +158,7 @@
 void machine_crash_shutdown(struct pt_regs *regs)
 {
 	/* This function is only called after the system
-	 * has paniced or is otherwise in a critical state.
+	 * has panicked or is otherwise in a critical state.
 	 * The minimum amount of code to allow a kexec'd kernel
 	 * to run successfully needs to happen here.
 	 *
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index 5edb1d3..b4d14c2 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -44,7 +44,8 @@
 		}
 	}
 
-	for (;;) /* nothing */;
+	for (;;)
+		cpu_relax();
 }
 
 struct tss_struct doublefault_tss __cacheline_aligned = {
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index cfc683f..e6e4506 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -48,6 +48,7 @@
 #include <asm/smp.h>
 #include <asm/page.h>
 #include <asm/desc.h>
+#include <asm/dwarf2.h>
 #include "irq_vectors.h"
 
 #define nr_syscalls ((syscall_table_size)/4)
@@ -85,31 +86,67 @@
 #define SAVE_ALL \
 	cld; \
 	pushl %es; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	/*CFI_REL_OFFSET es, 0;*/\
 	pushl %ds; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	/*CFI_REL_OFFSET ds, 0;*/\
 	pushl %eax; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET eax, 0;\
 	pushl %ebp; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET ebp, 0;\
 	pushl %edi; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET edi, 0;\
 	pushl %esi; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET esi, 0;\
 	pushl %edx; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET edx, 0;\
 	pushl %ecx; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET ecx, 0;\
 	pushl %ebx; \
+	CFI_ADJUST_CFA_OFFSET 4;\
+	CFI_REL_OFFSET ebx, 0;\
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
 	movl %edx, %es;
 
 #define RESTORE_INT_REGS \
 	popl %ebx;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE ebx;\
 	popl %ecx;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE ecx;\
 	popl %edx;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE edx;\
 	popl %esi;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE esi;\
 	popl %edi;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE edi;\
 	popl %ebp;	\
-	popl %eax
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE ebp;\
+	popl %eax;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	CFI_RESTORE eax
 
 #define RESTORE_REGS	\
 	RESTORE_INT_REGS; \
 1:	popl %ds;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	/*CFI_RESTORE ds;*/\
 2:	popl %es;	\
+	CFI_ADJUST_CFA_OFFSET -4;\
+	/*CFI_RESTORE es;*/\
 .section .fixup,"ax";	\
 3:	movl $0,(%esp);	\
 	jmp 1b;		\
@@ -122,13 +159,43 @@
 	.long 2b,4b;	\
 .previous
 
+#define RING0_INT_FRAME \
+	CFI_STARTPROC simple;\
+	CFI_DEF_CFA esp, 3*4;\
+	/*CFI_OFFSET cs, -2*4;*/\
+	CFI_OFFSET eip, -3*4
+
+#define RING0_EC_FRAME \
+	CFI_STARTPROC simple;\
+	CFI_DEF_CFA esp, 4*4;\
+	/*CFI_OFFSET cs, -2*4;*/\
+	CFI_OFFSET eip, -3*4
+
+#define RING0_PTREGS_FRAME \
+	CFI_STARTPROC simple;\
+	CFI_DEF_CFA esp, OLDESP-EBX;\
+	/*CFI_OFFSET cs, CS-OLDESP;*/\
+	CFI_OFFSET eip, EIP-OLDESP;\
+	/*CFI_OFFSET es, ES-OLDESP;*/\
+	/*CFI_OFFSET ds, DS-OLDESP;*/\
+	CFI_OFFSET eax, EAX-OLDESP;\
+	CFI_OFFSET ebp, EBP-OLDESP;\
+	CFI_OFFSET edi, EDI-OLDESP;\
+	CFI_OFFSET esi, ESI-OLDESP;\
+	CFI_OFFSET edx, EDX-OLDESP;\
+	CFI_OFFSET ecx, ECX-OLDESP;\
+	CFI_OFFSET ebx, EBX-OLDESP
 
 ENTRY(ret_from_fork)
+	CFI_STARTPROC
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET -4
 	call schedule_tail
 	GET_THREAD_INFO(%ebp)
 	popl %eax
+	CFI_ADJUST_CFA_OFFSET -4
 	jmp syscall_exit
+	CFI_ENDPROC
 
 /*
  * Return to user mode is not as complex as all this looks,
@@ -139,6 +206,7 @@
 
 	# userspace resumption stub bypassing syscall exit tracing
 	ALIGN
+	RING0_PTREGS_FRAME
 ret_from_exception:
 	preempt_stop
 ret_from_intr:
@@ -171,20 +239,33 @@
 	call preempt_schedule_irq
 	jmp need_resched
 #endif
+	CFI_ENDPROC
 
 /* SYSENTER_RETURN points to after the "sysenter" instruction in
    the vsyscall page.  See vsyscall-sysentry.S, which defines the symbol.  */
 
 	# sysenter call handler stub
 ENTRY(sysenter_entry)
+	CFI_STARTPROC simple
+	CFI_DEF_CFA esp, 0
+	CFI_REGISTER esp, ebp
 	movl TSS_sysenter_esp0(%esp),%esp
 sysenter_past_esp:
 	sti
 	pushl $(__USER_DS)
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET ss, 0*/
 	pushl %ebp
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET esp, 0
 	pushfl
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $(__USER_CS)
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET cs, 0*/
 	pushl $SYSENTER_RETURN
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET eip, 0
 
 /*
  * Load the potential sixth argument from user stack.
@@ -199,6 +280,7 @@
 .previous
 
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 
@@ -219,11 +301,14 @@
 	xorl %ebp,%ebp
 	sti
 	sysexit
+	CFI_ENDPROC
 
 
 	# system call handler stub
 ENTRY(system_call)
+	RING0_INT_FRAME			# can't unwind into user space anyway
 	pushl %eax			# save orig_eax
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 	testl $TF_MASK,EFLAGS(%esp)
@@ -256,10 +341,12 @@
 	movb CS(%esp), %al
 	andl $(VM_MASK | (4 << 8) | 3), %eax
 	cmpl $((4 << 8) | 3), %eax
+	CFI_REMEMBER_STATE
 	je ldt_ss			# returning to user-space with LDT SS
 restore_nocheck:
 	RESTORE_REGS
 	addl $4, %esp
+	CFI_ADJUST_CFA_OFFSET -4
 1:	iret
 .section .fixup,"ax"
 iret_exc:
@@ -273,6 +360,7 @@
 	.long 1b,iret_exc
 .previous
 
+	CFI_RESTORE_STATE
 ldt_ss:
 	larl OLDSS(%esp), %eax
 	jnz restore_nocheck
@@ -285,11 +373,13 @@
 	 * CPUs, which we can try to work around to make
 	 * dosemu and wine happy. */
 	subl $8, %esp		# reserve space for switch16 pointer
+	CFI_ADJUST_CFA_OFFSET 8
 	cli
 	movl %esp, %eax
 	/* Set up the 16bit stack frame with switch32 pointer on top,
 	 * and a switch16 pointer on top of the current frame. */
 	call setup_x86_bogus_stack
+	CFI_ADJUST_CFA_OFFSET -8	# frame has moved
 	RESTORE_REGS
 	lss 20+4(%esp), %esp	# switch to 16bit stack
 1:	iret
@@ -297,9 +387,11 @@
 	.align 4
 	.long 1b,iret_exc
 .previous
+	CFI_ENDPROC
 
 	# perform work that needs to be done immediately before resumption
 	ALIGN
+	RING0_PTREGS_FRAME		# can't unwind into user space anyway
 work_pending:
 	testb $_TIF_NEED_RESCHED, %cl
 	jz work_notifysig
@@ -329,8 +421,10 @@
 work_notifysig_v86:
 #ifdef CONFIG_VM86
 	pushl %ecx			# save ti_flags for do_notify_resume
+	CFI_ADJUST_CFA_OFFSET 4
 	call save_v86_state		# %eax contains pt_regs pointer
 	popl %ecx
+	CFI_ADJUST_CFA_OFFSET -4
 	movl %eax, %esp
 	xorl %edx, %edx
 	call do_notify_resume
@@ -363,19 +457,21 @@
 	movl $1, %edx
 	call do_syscall_trace
 	jmp resume_userspace
+	CFI_ENDPROC
 
-	ALIGN
+	RING0_INT_FRAME			# can't unwind into user space anyway
 syscall_fault:
 	pushl %eax			# save orig_eax
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 	movl $-EFAULT,EAX(%esp)
 	jmp resume_userspace
 
-	ALIGN
 syscall_badsys:
 	movl $-ENOSYS,EAX(%esp)
 	jmp resume_userspace
+	CFI_ENDPROC
 
 #define FIXUP_ESPFIX_STACK \
 	movl %esp, %eax; \
@@ -387,16 +483,21 @@
 	movl %eax, %esp;
 #define UNWIND_ESPFIX_STACK \
 	pushl %eax; \
+	CFI_ADJUST_CFA_OFFSET 4; \
 	movl %ss, %eax; \
 	/* see if on 16bit stack */ \
 	cmpw $__ESPFIX_SS, %ax; \
-	jne 28f; \
-	movl $__KERNEL_DS, %edx; \
-	movl %edx, %ds; \
-	movl %edx, %es; \
+	je 28f; \
+27:	popl %eax; \
+	CFI_ADJUST_CFA_OFFSET -4; \
+.section .fixup,"ax"; \
+28:	movl $__KERNEL_DS, %eax; \
+	movl %eax, %ds; \
+	movl %eax, %es; \
 	/* switch to 32bit stack */ \
-	FIXUP_ESPFIX_STACK \
-28:	popl %eax;
+	FIXUP_ESPFIX_STACK; \
+	jmp 27b; \
+.previous
 
 /*
  * Build the entry stubs and pointer table with
@@ -408,9 +509,14 @@
 
 vector=0
 ENTRY(irq_entries_start)
+	RING0_INT_FRAME
 .rept NR_IRQS
 	ALIGN
+ .if vector
+	CFI_ADJUST_CFA_OFFSET -4
+ .endif
 1:	pushl $vector-256
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp common_interrupt
 .data
 	.long 1b
@@ -424,60 +530,99 @@
 	movl %esp,%eax
 	call do_IRQ
 	jmp ret_from_intr
+	CFI_ENDPROC
 
 #define BUILD_INTERRUPT(name, nr)	\
 ENTRY(name)				\
+	RING0_INT_FRAME;		\
 	pushl $nr-256;			\
-	SAVE_ALL			\
+	CFI_ADJUST_CFA_OFFSET 4;	\
+	SAVE_ALL;			\
 	movl %esp,%eax;			\
 	call smp_/**/name;		\
-	jmp ret_from_intr;
+	jmp ret_from_intr;	\
+	CFI_ENDPROC
 
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
 ENTRY(divide_error)
+	RING0_INT_FRAME
 	pushl $0			# no error code
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_divide_error
+	CFI_ADJUST_CFA_OFFSET 4
 	ALIGN
 error_code:
 	pushl %ds
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET ds, 0*/
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET eax, 0
 	xorl %eax, %eax
 	pushl %ebp
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebp, 0
 	pushl %edi
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET edi, 0
 	pushl %esi
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET esi, 0
 	pushl %edx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET edx, 0
 	decl %eax			# eax = -1
 	pushl %ecx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ecx, 0
 	pushl %ebx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebx, 0
 	cld
 	pushl %es
+	CFI_ADJUST_CFA_OFFSET 4
+	/*CFI_REL_OFFSET es, 0*/
 	UNWIND_ESPFIX_STACK
 	popl %ecx
+	CFI_ADJUST_CFA_OFFSET -4
+	/*CFI_REGISTER es, ecx*/
 	movl ES(%esp), %edi		# get the function address
 	movl ORIG_EAX(%esp), %edx	# get the error code
 	movl %eax, ORIG_EAX(%esp)
 	movl %ecx, ES(%esp)
+	/*CFI_REL_OFFSET es, ES*/
 	movl $(__USER_DS), %ecx
 	movl %ecx, %ds
 	movl %ecx, %es
 	movl %esp,%eax			# pt_regs pointer
 	call *%edi
 	jmp ret_from_exception
+	CFI_ENDPROC
 
 ENTRY(coprocessor_error)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_coprocessor_error
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(simd_coprocessor_error)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_simd_coprocessor_error
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(device_not_available)
+	RING0_INT_FRAME
 	pushl $-1			# mark this as an int
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	movl %cr0, %eax
 	testl $0x4, %eax		# EM (math emulation bit)
@@ -487,9 +632,12 @@
 	jmp ret_from_exception
 device_not_available_emulate:
 	pushl $0			# temporary storage for ORIG_EIP
+	CFI_ADJUST_CFA_OFFSET 4
 	call math_emulate
 	addl $4, %esp
+	CFI_ADJUST_CFA_OFFSET -4
 	jmp ret_from_exception
+	CFI_ENDPROC
 
 /*
  * Debug traps and NMI can happen at the one SYSENTER instruction
@@ -514,16 +662,19 @@
 	pushl $sysenter_past_esp
 
 KPROBE_ENTRY(debug)
+	RING0_INT_FRAME
 	cmpl $sysenter_entry,(%esp)
 	jne debug_stack_correct
 	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
 debug_stack_correct:
 	pushl $-1			# mark this as an int
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	xorl %edx,%edx			# error code 0
 	movl %esp,%eax			# pt_regs pointer
 	call do_debug
 	jmp ret_from_exception
+	CFI_ENDPROC
 	.previous .text
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
@@ -534,14 +685,18 @@
  * fault happened on the sysenter path.
  */
 ENTRY(nmi)
+	RING0_INT_FRAME
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
 	movl %ss, %eax
 	cmpw $__ESPFIX_SS, %ax
 	popl %eax
+	CFI_ADJUST_CFA_OFFSET -4
 	je nmi_16bit_stack
 	cmpl $sysenter_entry,(%esp)
 	je nmi_stack_fixup
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
 	movl %esp,%eax
 	/* Do not access memory above the end of our stack page,
 	 * it might not exist.
@@ -549,16 +704,19 @@
 	andl $(THREAD_SIZE-1),%eax
 	cmpl $(THREAD_SIZE-20),%eax
 	popl %eax
+	CFI_ADJUST_CFA_OFFSET -4
 	jae nmi_stack_correct
 	cmpl $sysenter_entry,12(%esp)
 	je nmi_debug_stack_check
 nmi_stack_correct:
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_nmi
 	jmp restore_all
+	CFI_ENDPROC
 
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
@@ -574,94 +732,177 @@
 	jmp nmi_stack_correct
 
 nmi_16bit_stack:
+	RING0_INT_FRAME
 	/* create the pointer to lss back */
 	pushl %ss
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl %esp
+	CFI_ADJUST_CFA_OFFSET 4
 	movzwl %sp, %esp
 	addw $4, (%esp)
 	/* copy the iret frame of 12 bytes */
 	.rept 3
 	pushl 16(%esp)
+	CFI_ADJUST_CFA_OFFSET 4
 	.endr
 	pushl %eax
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	FIXUP_ESPFIX_STACK		# %eax == %esp
+	CFI_ADJUST_CFA_OFFSET -20	# the frame has now moved
 	xorl %edx,%edx			# zero error code
 	call do_nmi
 	RESTORE_REGS
 	lss 12+4(%esp), %esp		# back to 16bit stack
 1:	iret
+	CFI_ENDPROC
 .section __ex_table,"a"
 	.align 4
 	.long 1b,iret_exc
 .previous
 
 KPROBE_ENTRY(int3)
+	RING0_INT_FRAME
 	pushl $-1			# mark this as an int
+	CFI_ADJUST_CFA_OFFSET 4
 	SAVE_ALL
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
 	call do_int3
 	jmp ret_from_exception
+	CFI_ENDPROC
 	.previous .text
 
 ENTRY(overflow)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_overflow
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(bounds)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_bounds
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(invalid_op)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_invalid_op
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(coprocessor_segment_overrun)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_coprocessor_segment_overrun
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(invalid_TSS)
+	RING0_EC_FRAME
 	pushl $do_invalid_TSS
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(segment_not_present)
+	RING0_EC_FRAME
 	pushl $do_segment_not_present
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 ENTRY(stack_segment)
+	RING0_EC_FRAME
 	pushl $do_stack_segment
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 KPROBE_ENTRY(general_protection)
+	RING0_EC_FRAME
 	pushl $do_general_protection
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 	.previous .text
 
 ENTRY(alignment_check)
+	RING0_EC_FRAME
 	pushl $do_alignment_check
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 
 KPROBE_ENTRY(page_fault)
+	RING0_EC_FRAME
 	pushl $do_page_fault
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 	.previous .text
 
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl machine_check_vector
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
 #endif
 
 ENTRY(spurious_interrupt_bug)
+	RING0_INT_FRAME
 	pushl $0
+	CFI_ADJUST_CFA_OFFSET 4
 	pushl $do_spurious_interrupt_bug
+	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
+	CFI_ENDPROC
+
+#ifdef CONFIG_STACK_UNWIND
+ENTRY(arch_unwind_init_running)
+	CFI_STARTPROC
+	movl	4(%esp), %edx
+	movl	(%esp), %ecx
+	leal	4(%esp), %eax
+	movl	%ebx, EBX(%edx)
+	xorl	%ebx, %ebx
+	movl	%ebx, ECX(%edx)
+	movl	%ebx, EDX(%edx)
+	movl	%esi, ESI(%edx)
+	movl	%edi, EDI(%edx)
+	movl	%ebp, EBP(%edx)
+	movl	%ebx, EAX(%edx)
+	movl	$__USER_DS, DS(%edx)
+	movl	$__USER_DS, ES(%edx)
+	movl	%ebx, ORIG_EAX(%edx)
+	movl	%ecx, EIP(%edx)
+	movl	12(%esp), %ecx
+	movl	$__KERNEL_CS, CS(%edx)
+	movl	%ebx, EFLAGS(%edx)
+	movl	%eax, OLDESP(%edx)
+	movl	8(%esp), %eax
+	movl	%ecx, 8(%esp)
+	movl	EBX(%edx), %ebx
+	movl	$__KERNEL_DS, OLDSS(%edx)
+	jmpl	*%eax
+	CFI_ENDPROC
+ENDPROC(arch_unwind_init_running)
+#endif
 
 .section .rodata,"a"
 #include "syscall_table.S"
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
new file mode 100644
index 0000000..c6737c3
--- /dev/null
+++ b/arch/i386/kernel/hpet.c
@@ -0,0 +1,67 @@
+#include <linux/clocksource.h>
+#include <linux/errno.h>
+#include <linux/hpet.h>
+#include <linux/init.h>
+
+#include <asm/hpet.h>
+#include <asm/io.h>
+
+#define HPET_MASK	CLOCKSOURCE_MASK(32)
+#define HPET_SHIFT	22
+
+/* FSEC = 10^-15 NSEC = 10^-9 */
+#define FSEC_PER_NSEC	1000000
+
+static void *hpet_ptr;
+
+static cycle_t read_hpet(void)
+{
+	return (cycle_t)readl(hpet_ptr);
+}
+
+static struct clocksource clocksource_hpet = {
+	.name		= "hpet",
+	.rating		= 250,
+	.read		= read_hpet,
+	.mask		= HPET_MASK,
+	.mult		= 0, /* set below */
+	.shift		= HPET_SHIFT,
+	.is_continuous	= 1,
+};
+
+static int __init init_hpet_clocksource(void)
+{
+	unsigned long hpet_period;
+	void __iomem* hpet_base;
+	u64 tmp;
+
+	if (!hpet_address)
+		return -ENODEV;
+
+	/* calculate the hpet address: */
+	hpet_base =
+		(void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+	hpet_ptr = hpet_base + HPET_COUNTER;
+
+	/* calculate the frequency: */
+	hpet_period = readl(hpet_base + HPET_PERIOD);
+
+	/*
+	 * hpet period is in femto seconds per cycle
+	 * so we need to convert this to ns/cyc units
+	 * aproximated by mult/2^shift
+	 *
+	 *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
+	 *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
+	 *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
+	 *  (fsec/cyc << shift)/1000000 = mult
+	 *  (hpet_period << shift)/FSEC_PER_NSEC = mult
+	 */
+	tmp = (u64)hpet_period << HPET_SHIFT;
+	do_div(tmp, FSEC_PER_NSEC);
+	clocksource_hpet.mult = (u32)tmp;
+
+	return clocksource_register(&clocksource_hpet);
+}
+
+module_init(init_hpet_clocksource);
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
new file mode 100644
index 0000000..477b24d
--- /dev/null
+++ b/arch/i386/kernel/i8253.c
@@ -0,0 +1,118 @@
+/*
+ * i8253.c  8253/PIT functions
+ *
+ */
+#include <linux/clocksource.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+#include <linux/sysdev.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/smp.h>
+#include <asm/delay.h>
+#include <asm/i8253.h>
+#include <asm/io.h>
+
+#include "io_ports.h"
+
+DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
+
+void setup_pit_timer(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	outb_p(0x34,PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
+	udelay(10);
+	outb_p(LATCH & 0xff , PIT_CH0);	/* LSB */
+	udelay(10);
+	outb(LATCH >> 8 , PIT_CH0);	/* MSB */
+	spin_unlock_irqrestore(&i8253_lock, flags);
+}
+
+/*
+ * Since the PIT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static cycle_t pit_read(void)
+{
+	unsigned long flags;
+	int count;
+	u32 jifs;
+	static int old_count;
+	static u32 old_jifs;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+        /*
+	 * Although our caller may have the read side of xtime_lock,
+	 * this is now a seqlock, and we are cheating in this routine
+	 * by having side effects on state that we cannot undo if
+	 * there is a collision on the seqlock and our caller has to
+	 * retry.  (Namely, old_jifs and old_count.)  So we must treat
+	 * jiffies as volatile despite the lock.  We read jiffies
+	 * before latching the timer count to guarantee that although
+	 * the jiffies value might be older than the count (that is,
+	 * the counter may underflow between the last point where
+	 * jiffies was incremented and the point where we latch the
+	 * count), it cannot be newer.
+	 */
+	jifs = jiffies;
+	outb_p(0x00, PIT_MODE);	/* latch the count ASAP */
+	count = inb_p(PIT_CH0);	/* read the latched count */
+	count |= inb_p(PIT_CH0) << 8;
+
+	/* VIA686a test code... reset the latch if count > max + 1 */
+	if (count > LATCH) {
+		outb_p(0x34, PIT_MODE);
+		outb_p(LATCH & 0xff, PIT_CH0);
+		outb(LATCH >> 8, PIT_CH0);
+		count = LATCH - 1;
+	}
+
+	/*
+	 * It's possible for count to appear to go the wrong way for a
+	 * couple of reasons:
+	 *
+	 *  1. The timer counter underflows, but we haven't handled the
+	 *     resulting interrupt and incremented jiffies yet.
+	 *  2. Hardware problem with the timer, not giving us continuous time,
+	 *     the counter does small "jumps" upwards on some Pentium systems,
+	 *     (see c't 95/10 page 335 for Neptun bug.)
+	 *
+	 * Previous attempts to handle these cases intelligently were
+	 * buggy, so we just do the simple thing now.
+	 */
+	if (count > old_count && jifs == old_jifs) {
+		count = old_count;
+	}
+	old_count = count;
+	old_jifs = jifs;
+
+	spin_unlock_irqrestore(&i8253_lock, flags);
+
+	count = (LATCH - 1) - count;
+
+	return (cycle_t)(jifs * LATCH) + count;
+}
+
+static struct clocksource clocksource_pit = {
+	.name	= "pit",
+	.rating = 110,
+	.read	= pit_read,
+	.mask	= CLOCKSOURCE_MASK(32),
+	.mult	= 0,
+	.shift	= 20,
+};
+
+static int __init init_pit_clocksource(void)
+{
+	if (num_possible_cpus() > 4) /* PIT does not scale! */
+		return 0;
+
+	clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
+	return clocksource_register(&clocksource_pit);
+}
+module_init(init_pit_clocksource);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index b7636b9..c1a42fe 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -175,7 +175,7 @@
 	 * Lightweight spurious IRQ detection. We do not want
 	 * to overdo spurious IRQ handling - it's usually a sign
 	 * of hardware problems, so we only do the checks we can
-	 * do without slowing down good hardware unnecesserily.
+	 * do without slowing down good hardware unnecessarily.
 	 *
 	 * Note that IRQ7 and IRQ15 (the two spurious IRQs
 	 * usually resulting from the 8259A-1|2 PICs) occur
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index a62df3e..72ae414 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -38,6 +38,7 @@
 #include <asm/desc.h>
 #include <asm/timer.h>
 #include <asm/i8259.h>
+#include <asm/nmi.h>
 
 #include <mach_apic.h>
 
@@ -50,6 +51,7 @@
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
 
 static DEFINE_SPINLOCK(ioapic_lock);
+static DEFINE_SPINLOCK(vector_lock);
 
 int timer_over_8254 __initdata = 1;
 
@@ -1161,10 +1163,17 @@
 int assign_irq_vector(int irq)
 {
 	static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+	unsigned long flags;
+	int vector;
 
-	BUG_ON(irq >= NR_IRQ_VECTORS);
-	if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
+	BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+
+	spin_lock_irqsave(&vector_lock, flags);
+
+	if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+		spin_unlock_irqrestore(&vector_lock, flags);
 		return IO_APIC_VECTOR(irq);
+	}
 next:
 	current_vector += 8;
 	if (current_vector == SYSCALL_VECTOR)
@@ -1172,16 +1181,21 @@
 
 	if (current_vector >= FIRST_SYSTEM_VECTOR) {
 		offset++;
-		if (!(offset%8))
+		if (!(offset%8)) {
+			spin_unlock_irqrestore(&vector_lock, flags);
 			return -ENOSPC;
+		}
 		current_vector = FIRST_DEVICE_VECTOR + offset;
 	}
 
-	vector_irq[current_vector] = irq;
+	vector = current_vector;
+	vector_irq[vector] = irq;
 	if (irq != AUTO_ASSIGN)
-		IO_APIC_VECTOR(irq) = current_vector;
+		IO_APIC_VECTOR(irq) = vector;
 
-	return current_vector;
+	spin_unlock_irqrestore(&vector_lock, flags);
+
+	return vector;
 }
 
 static struct hw_interrupt_type ioapic_level_type;
@@ -1193,21 +1207,14 @@
 
 static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-	if (use_pci_vector() && !platform_legacy_irq(irq)) {
-		if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-				trigger == IOAPIC_LEVEL)
-			irq_desc[vector].handler = &ioapic_level_type;
-		else
-			irq_desc[vector].handler = &ioapic_edge_type;
-		set_intr_gate(vector, interrupt[vector]);
-	} else	{
-		if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-				trigger == IOAPIC_LEVEL)
-			irq_desc[irq].handler = &ioapic_level_type;
-		else
-			irq_desc[irq].handler = &ioapic_edge_type;
-		set_intr_gate(vector, interrupt[irq]);
-	}
+	unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+
+	if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
+			trigger == IOAPIC_LEVEL)
+		irq_desc[idx].handler = &ioapic_level_type;
+	else
+		irq_desc[idx].handler = &ioapic_edge_type;
+	set_intr_gate(vector, interrupt[idx]);
 }
 
 static void __init setup_IO_APIC_irqs(void)
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 248e922..061533e 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -95,6 +95,14 @@
 		irqctx->tinfo.task = curctx->tinfo.task;
 		irqctx->tinfo.previous_esp = current_stack_pointer;
 
+		/*
+		 * Copy the softirq bits in preempt_count so that the
+		 * softirq checks work in the hardirq context.
+		 */
+		irqctx->tinfo.preempt_count =
+			irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK |
+			curctx->tinfo.preempt_count & SOFTIRQ_MASK;
+
 		asm volatile(
 			"       xchgl   %%ebx,%%esp      \n"
 			"       call    __do_IRQ         \n"
@@ -219,7 +227,7 @@
 	if (i == 0) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
-			seq_printf(p, "CPU%d       ",j);
+			seq_printf(p, "CPU%-8d",j);
 		seq_putc(p, '\n');
 	}
 
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 395a9a6..727e419 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -57,34 +57,85 @@
 /*
  * returns non-zero if opcodes can be boosted.
  */
-static __always_inline int can_boost(kprobe_opcode_t opcode)
+static __always_inline int can_boost(kprobe_opcode_t *opcodes)
 {
-	switch (opcode & 0xf0 ) {
+#define W(row,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf)		      \
+	(((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) |   \
+	  (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) |   \
+	  (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) |   \
+	  (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf))    \
+	 << (row % 32))
+	/*
+	 * Undefined/reserved opcodes, conditional jump, Opcode Extension
+	 * Groups, and some special opcodes can not be boost.
+	 */
+	static const unsigned long twobyte_is_boostable[256 / 32] = {
+		/*      0 1 2 3 4 5 6 7 8 9 a b c d e f         */
+		/*      -------------------------------         */
+		W(0x00, 0,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0)| /* 00 */
+		W(0x10, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 10 */
+		W(0x20, 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0)| /* 20 */
+		W(0x30, 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 30 */
+		W(0x40, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 40 */
+		W(0x50, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 50 */
+		W(0x60, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1)| /* 60 */
+		W(0x70, 0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1), /* 70 */
+		W(0x80, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 80 */
+		W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 90 */
+		W(0xa0, 1,1,0,1,1,1,0,0,1,1,0,1,1,1,0,1)| /* a0 */
+		W(0xb0, 1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1), /* b0 */
+		W(0xc0, 1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1)| /* c0 */
+		W(0xd0, 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1), /* d0 */
+		W(0xe0, 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1)| /* e0 */
+		W(0xf0, 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0)  /* f0 */
+		/*      -------------------------------         */
+		/*      0 1 2 3 4 5 6 7 8 9 a b c d e f         */
+	};
+#undef W
+	kprobe_opcode_t opcode;
+	kprobe_opcode_t *orig_opcodes = opcodes;
+retry:
+	if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
+		return 0;
+	opcode = *(opcodes++);
+
+	/* 2nd-byte opcode */
+	if (opcode == 0x0f) {
+		if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1)
+			return 0;
+		return test_bit(*opcodes, twobyte_is_boostable);
+	}
+
+	switch (opcode & 0xf0) {
+	case 0x60:
+		if (0x63 < opcode && opcode < 0x67)
+			goto retry; /* prefixes */
+		/* can't boost Address-size override and bound */
+		return (opcode != 0x62 && opcode != 0x67);
 	case 0x70:
 		return 0; /* can't boost conditional jump */
-	case 0x90:
-		/* can't boost call and pushf */
-		return opcode != 0x9a && opcode != 0x9c;
 	case 0xc0:
-		/* can't boost undefined opcodes and soft-interruptions */
-		return (0xc1 < opcode && opcode < 0xc6) ||
-			(0xc7 < opcode && opcode < 0xcc) || opcode == 0xcf;
+		/* can't boost software-interruptions */
+		return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf;
 	case 0xd0:
 		/* can boost AA* and XLAT */
 		return (opcode == 0xd4 || opcode == 0xd5 || opcode == 0xd7);
 	case 0xe0:
-		/* can boost in/out and (may be) jmps */
-		return (0xe3 < opcode && opcode != 0xe8);
+		/* can boost in/out and absolute jmps */
+		return ((opcode & 0x04) || opcode == 0xea);
 	case 0xf0:
+		if ((opcode & 0x0c) == 0 && opcode != 0xf1)
+			goto retry; /* lock/rep(ne) prefix */
 		/* clear and set flags can be boost */
 		return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe));
 	default:
-		/* currently, can't boost 2 bytes opcodes */
-		return opcode != 0x0f;
+		if (opcode == 0x26 || opcode == 0x36 || opcode == 0x3e)
+			goto retry; /* prefixes */
+		/* can't boost CS override and call */
+		return (opcode != 0x2e && opcode != 0x9a);
 	}
 }
 
-
 /*
  * returns non-zero if opcode modifies the interrupt flag.
  */
@@ -109,7 +160,7 @@
 
 	memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
 	p->opcode = *p->addr;
-	if (can_boost(p->opcode)) {
+	if (can_boost(p->addr)) {
 		p->ainsn.boostable = 0;
 	} else {
 		p->ainsn.boostable = -1;
@@ -208,7 +259,9 @@
 	struct kprobe_ctlblk *kcb;
 #ifdef CONFIG_PREEMPT
 	unsigned pre_preempt_count = preempt_count();
-#endif /* CONFIG_PREEMPT */
+#else
+	unsigned pre_preempt_count = 1;
+#endif
 
 	addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
 
@@ -285,22 +338,14 @@
 		/* handler has already set things up, so skip ss setup */
 		return 1;
 
-	if (p->ainsn.boostable == 1 &&
-#ifdef CONFIG_PREEMPT
-	    !(pre_preempt_count) && /*
-				       * This enables booster when the direct
-				       * execution path aren't preempted.
-				       */
-#endif /* CONFIG_PREEMPT */
-	    !p->post_handler && !p->break_handler ) {
+ss_probe:
+	if (pre_preempt_count && p->ainsn.boostable == 1 && !p->post_handler){
 		/* Boost up -- we can execute copied instructions directly */
 		reset_current_kprobe();
 		regs->eip = (unsigned long)p->ainsn.insn;
 		preempt_enable_no_resched();
 		return 1;
 	}
-
-ss_probe:
 	prepare_singlestep(p, regs);
 	kcb->kprobe_status = KPROBE_HIT_SS;
 	return 1;
diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c
index f73d737..511abe5 100644
--- a/arch/i386/kernel/machine_kexec.c
+++ b/arch/i386/kernel/machine_kexec.c
@@ -133,9 +133,9 @@
 					unsigned long start_address,
 					unsigned int has_pae) ATTRIB_NORET;
 
-const extern unsigned char relocate_new_kernel[];
+extern const unsigned char relocate_new_kernel[];
 extern void relocate_new_kernel_end(void);
-const extern unsigned int relocate_new_kernel_size;
+extern const unsigned int relocate_new_kernel_size;
 
 /*
  * A architecture hook called to validate the
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index d43b498..a76e931 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -14,21 +14,17 @@
  */
 
 #include <linux/config.h>
-#include <linux/mm.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
-#include <linux/mc146818rtc.h>
-#include <linux/kernel_stat.h>
 #include <linux/module.h>
 #include <linux/nmi.h>
 #include <linux/sysdev.h>
 #include <linux/sysctl.h>
+#include <linux/percpu.h>
 
 #include <asm/smp.h>
-#include <asm/div64.h>
 #include <asm/nmi.h>
+#include <asm/intel_arch_perfmon.h>
 
 #include "mach_traps.h"
 
@@ -100,6 +96,9 @@
 	(P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
 	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
 
+#define ARCH_PERFMON_NMI_EVENT_SEL	ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
+#define ARCH_PERFMON_NMI_EVENT_UMASK	ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
+
 #ifdef CONFIG_SMP
 /* The performance counters used by NMI_LOCAL_APIC don't trigger when
  * the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -212,6 +211,8 @@
 
 __setup("nmi_watchdog=", setup_nmi_watchdog);
 
+static void disable_intel_arch_watchdog(void);
+
 static void disable_lapic_nmi_watchdog(void)
 {
 	if (nmi_active <= 0)
@@ -221,6 +222,10 @@
 		wrmsr(MSR_K7_EVNTSEL0, 0, 0);
 		break;
 	case X86_VENDOR_INTEL:
+		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+			disable_intel_arch_watchdog();
+			break;
+		}
 		switch (boot_cpu_data.x86) {
 		case 6:
 			if (boot_cpu_data.x86_model > 0xd)
@@ -449,6 +454,53 @@
 	return 1;
 }
 
+static void disable_intel_arch_watchdog(void)
+{
+	unsigned ebx;
+
+	/*
+	 * Check whether the Architectural PerfMon supports
+	 * Unhalted Core Cycles Event or not.
+	 * NOTE: Corresponding bit = 0 in ebp indicates event present.
+	 */
+	ebx = cpuid_ebx(10);
+	if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+		wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
+}
+
+static int setup_intel_arch_watchdog(void)
+{
+	unsigned int evntsel;
+	unsigned ebx;
+
+	/*
+	 * Check whether the Architectural PerfMon supports
+	 * Unhalted Core Cycles Event or not.
+	 * NOTE: Corresponding bit = 0 in ebp indicates event present.
+	 */
+	ebx = cpuid_ebx(10);
+	if ((ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+		return 0;
+
+	nmi_perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
+
+	clear_msr_range(MSR_ARCH_PERFMON_EVENTSEL0, 2);
+	clear_msr_range(MSR_ARCH_PERFMON_PERFCTR0, 2);
+
+	evntsel = ARCH_PERFMON_EVENTSEL_INT
+		| ARCH_PERFMON_EVENTSEL_OS
+		| ARCH_PERFMON_EVENTSEL_USR
+		| ARCH_PERFMON_NMI_EVENT_SEL
+		| ARCH_PERFMON_NMI_EVENT_UMASK;
+
+	wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
+	write_watchdog_counter("INTEL_ARCH_PERFCTR0");
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+	wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
+	return 1;
+}
+
 void setup_apic_nmi_watchdog (void)
 {
 	switch (boot_cpu_data.x86_vendor) {
@@ -458,6 +510,11 @@
 		setup_k7_watchdog();
 		break;
 	case X86_VENDOR_INTEL:
+		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+			if (!setup_intel_arch_watchdog())
+				return;
+			break;
+		}
 		switch (boot_cpu_data.x86) {
 		case 6:
 			if (boot_cpu_data.x86_model > 0xd)
@@ -561,7 +618,8 @@
 			wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
 			apic_write(APIC_LVTPC, APIC_DM_NMI);
 		}
-		else if (nmi_perfctr_msr == MSR_P6_PERFCTR0) {
+		else if (nmi_perfctr_msr == MSR_P6_PERFCTR0 ||
+		         nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
 			/* Only P6 based Pentium M need to re-unmask
 			 * the apic vector but it doesn't hurt
 			 * other P6 variant */
diff --git a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c
index 5f5b075..0caf146 100644
--- a/arch/i386/kernel/numaq.c
+++ b/arch/i386/kernel/numaq.c
@@ -79,10 +79,12 @@
 	return 1;
 }
 
-static int __init numaq_dsc_disable(void)
+static int __init numaq_tsc_disable(void)
 {
-	printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
-	tsc_disable = 1;
+	if (num_online_nodes() > 1) {
+		printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
+		tsc_disable = 1;
+	}
 	return 0;
 }
-core_initcall(numaq_dsc_disable);
+arch_initcall(numaq_tsc_disable);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 6259afe..6946b06e 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -102,7 +102,7 @@
 	local_irq_enable();
 
 	if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
-		clear_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status &= ~TS_POLLING;
 		smp_mb__after_clear_bit();
 		while (!need_resched()) {
 			local_irq_disable();
@@ -111,7 +111,7 @@
 			else
 				local_irq_enable();
 		}
-		set_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status |= TS_POLLING;
 	} else {
 		while (!need_resched())
 			cpu_relax();
@@ -174,7 +174,7 @@
 {
 	int cpu = smp_processor_id();
 
-	set_thread_flag(TIF_POLLING_NRFLAG);
+	current_thread_info()->status |= TS_POLLING;
 
 	/* endless idle loop with no priority at all */
 	while (1) {
@@ -312,7 +312,7 @@
 	cr3 = read_cr3();
 	cr4 = read_cr4_safe();
 	printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
-	show_trace(NULL, &regs->esp);
+	show_trace(NULL, regs, &regs->esp);
 }
 
 /*
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index e602397..4a65040 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -48,7 +48,6 @@
 #include <linux/crash_dump.h>
 #include <linux/dmi.h>
 #include <linux/pfn.h>
-#include <linux/suspend.h>
 
 #include <video/edid.h>
 
@@ -61,7 +60,7 @@
 #include <asm/io_apic.h>
 #include <asm/ist.h>
 #include <asm/io.h>
-#include "setup_arch_pre.h"
+#include <setup_arch.h>
 #include <bios_ebda.h>
 
 /* Forward Declaration. */
@@ -411,8 +410,8 @@
 	}
 }
 
-static void __init add_memory_region(unsigned long long start,
-                                  unsigned long long size, int type)
+void __init add_memory_region(unsigned long long start,
+			      unsigned long long size, int type)
 {
 	int x;
 
@@ -475,7 +474,7 @@
 static struct e820entry *overlap_list[E820MAX] __initdata;
 static struct e820entry new_bios[E820MAX] __initdata;
 
-static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
 {
 	struct change_member *change_tmp;
 	unsigned long current_type, last_type;
@@ -644,7 +643,7 @@
  * thinkpad 560x, for example, does not cooperate with the memory
  * detection code.)
  */
-static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
 {
 	/* Only one memory region (or negative)? Ignore it */
 	if (nr_map < 2)
@@ -702,12 +701,6 @@
 }
 #endif
 
-/*
- * Do NOT EVER look at the BIOS memory size location.
- * It does not work on many machines.
- */
-#define LOWMEMSIZE()	(0x9f000)
-
 static void __init parse_cmdline_early (char ** cmdline_p)
 {
 	char c = ' ', *to = command_line, *from = saved_command_line;
@@ -1424,8 +1417,6 @@
 		pci_mem_start, gapstart, gapsize);
 }
 
-static char * __init machine_specific_memory_setup(void);
-
 #ifdef CONFIG_MCA
 static void set_mca_bus(int x)
 {
@@ -1435,111 +1426,6 @@
 static void set_mca_bus(int x) { }
 #endif
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
-static void __init mark_nosave_page_range(unsigned long start, unsigned long end)
-{
-	struct page *page;
-	while (start <= end) {
-		page = pfn_to_page(start);
-		SetPageNosave(page);
-		start++;
-	}
-}
-
-static void __init e820_nosave_reserved_pages(void)
-{
-	int i;
-	unsigned long r_start = 0, r_end = 0;
-
-	/* Assume e820 map is sorted */
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		unsigned long start, end;
-
-		start = PFN_DOWN(ei->addr);
-		end = PFN_UP(ei->addr + ei->size);
-		if (start >= end)
-			continue;
-		if (ei->type == E820_RESERVED)
-			continue;
-		r_end = start;
-		/*
-		 * Highmem 'Reserved' pages are marked as reserved, swsusp
-		 * will not save/restore them, so we ignore these pages here.
-		 */
-		if (r_end > max_low_pfn)
-			r_end = max_low_pfn;
-		if (r_end > r_start)
-			mark_nosave_page_range(r_start, r_end-1);
-		if (r_end >= max_low_pfn)
-			break;
-		r_start = end;
-	}
-}
-
-static void __init e820_save_acpi_pages(void)
-{
-	int i;
-
-	/* Assume e820 map is sorted */
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		unsigned long start, end;
-
-		start = ei->addr;
-		end = ei->addr + ei->size;
-		if (start >= end)
-			continue;
-		if (ei->type != E820_ACPI && ei->type != E820_NVS)
-			continue;
-		/*
-		 * If the region is below max_low_pfn, it will be
-		 * saved/restored by swsusp follow 'RAM' type.
-		 */
-		if (start < (max_low_pfn << PAGE_SHIFT))
-			start = max_low_pfn << PAGE_SHIFT;
-		/*
-		 * Highmem pages (ACPI NVS/Data) are reserved, but swsusp
-		 * highmem save/restore will not save/restore them. We marked
-		 * them as arch saveable pages here
-		 */
-		if (end > start)
-			swsusp_add_arch_pages(start, end);
-	}
-}
-
-extern char __start_rodata, __end_rodata;
-/*
- * BIOS reserved region/hole - no save/restore
- * ACPI NVS - save/restore
- * ACPI Data - this is a little tricky, the mem could be used by OS after OS
- * reads tables from the region, but anyway save/restore the memory hasn't any
- * side effect and Linux runtime module load/unload might use it.
- * kernel rodata - no save/restore (kernel rodata isn't changed)
- */
-static int __init mark_nosave_pages(void)
-{
-	unsigned long pfn_start, pfn_end;
-
-	/* FIXME: provide a version for efi BIOS */
-	if (efi_enabled)
-		return 0;
-	/* BIOS reserved regions & holes */
-	e820_nosave_reserved_pages();
-
-	/* kernel rodata */
-	pfn_start = PFN_UP(virt_to_phys(&__start_rodata));
-	pfn_end = PFN_DOWN(virt_to_phys(&__end_rodata));
-	mark_nosave_page_range(pfn_start, pfn_end-1);
-
-	/* record ACPI Data/NVS as saveable */
-	e820_save_acpi_pages();
-
-	return 0;
-}
-core_initcall(mark_nosave_pages);
-#endif
-
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -1689,6 +1575,7 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
+	tsc_init();
 }
 
 static __init int add_pcspkr(void)
@@ -1708,7 +1595,6 @@
 }
 device_initcall(add_pcspkr);
 
-#include "setup_arch_post.h"
 /*
  * Local Variables:
  * mode:c
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index d134e96..c10789d 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -114,7 +114,17 @@
 
 static inline int __prepare_ICR (unsigned int shortcut, int vector)
 {
-	return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+	unsigned int icr = shortcut | APIC_DEST_LOGICAL;
+
+	switch (vector) {
+	default:
+		icr |= APIC_DM_FIXED | vector;
+		break;
+	case NMI_VECTOR:
+		icr |= APIC_DM_NMI;
+		break;
+	}
+	return icr;
 }
 
 static inline int __prepare_ICR2 (unsigned int mask)
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 825b2b4..bce5470 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -52,6 +52,7 @@
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
+#include <asm/nmi.h>
 
 #include <mach_apic.h>
 #include <mach_wakecpu.h>
@@ -257,7 +258,7 @@
 		 * all APs synchronize but they loop on '== num_cpus'
 		 */
 		while (atomic_read(&tsc_count_start) != num_booting_cpus()-1)
-			mb();
+			cpu_relax();
 		atomic_set(&tsc_count_stop, 0);
 		wmb();
 		/*
@@ -276,7 +277,7 @@
 		 * Wait for all APs to leave the synchronization point:
 		 */
 		while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1)
-			mb();
+			cpu_relax();
 		atomic_set(&tsc_count_start, 0);
 		wmb();
 		atomic_inc(&tsc_count_stop);
@@ -333,19 +334,21 @@
 	 * this gets called, so we first wait for the BP to
 	 * finish SMP initialization:
 	 */
-	while (!atomic_read(&tsc_start_flag)) mb();
+	while (!atomic_read(&tsc_start_flag))
+		cpu_relax();
 
 	for (i = 0; i < NR_LOOPS; i++) {
 		atomic_inc(&tsc_count_start);
 		while (atomic_read(&tsc_count_start) != num_booting_cpus())
-			mb();
+			cpu_relax();
 
 		rdtscll(tsc_values[smp_processor_id()]);
 		if (i == NR_LOOPS-1)
 			write_tsc(0, 0);
 
 		atomic_inc(&tsc_count_stop);
-		while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
+		while (atomic_read(&tsc_count_stop) != num_booting_cpus())
+			cpu_relax();
 	}
 }
 #undef NR_LOOPS
@@ -1433,7 +1436,7 @@
 	/* Unleash the CPU! */
 	cpu_set(cpu, smp_commenced_mask);
 	while (!cpu_isset(cpu, cpu_online_map))
-		mb();
+		cpu_relax();
 	return 0;
 }
 
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 9d30747..5f43d04 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -82,13 +82,6 @@
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
-#include <asm/i8253.h>
-
-DEFINE_SPINLOCK(i8253_lock);
-EXPORT_SYMBOL(i8253_lock);
-
-struct timer_opts *cur_timer __read_mostly = &timer_none;
-
 /*
  * This is a special lock that is owned by the CPU and holds the index
  * register we are working with.  It is required for NMI access to the
@@ -118,99 +111,19 @@
 }
 EXPORT_SYMBOL(rtc_cmos_write);
 
-/*
- * This version of gettimeofday has microsecond resolution
- * and better than microsecond precision on fast x86 machines with TSC.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long seq;
-	unsigned long usec, sec;
-	unsigned long max_ntp_tick;
-
-	do {
-		unsigned long lost;
-
-		seq = read_seqbegin(&xtime_lock);
-
-		usec = cur_timer->get_offset();
-		lost = jiffies - wall_jiffies;
-
-		/*
-		 * If time_adjust is negative then NTP is slowing the clock
-		 * so make sure not to go into next possible interval.
-		 * Better to lose some accuracy than have time go backwards..
-		 */
-		if (unlikely(time_adjust < 0)) {
-			max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;
-			usec = min(usec, max_ntp_tick);
-
-			if (lost)
-				usec += lost * max_ntp_tick;
-		}
-		else if (unlikely(lost))
-			usec += lost * (USEC_PER_SEC / HZ);
-
-		sec = xtime.tv_sec;
-		usec += (xtime.tv_nsec / 1000);
-	} while (read_seqretry(&xtime_lock, seq));
-
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-	time_t wtm_sec, sec = tv->tv_sec;
-	long wtm_nsec, nsec = tv->tv_nsec;
-
-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-		return -EINVAL;
-
-	write_seqlock_irq(&xtime_lock);
-	/*
-	 * This is revolting. We need to set "xtime" correctly. However, the
-	 * value in this location is the value at the most recent update of
-	 * wall time.  Discover what correction gettimeofday() would have
-	 * made, and then undo it!
-	 */
-	nsec -= cur_timer->get_offset() * NSEC_PER_USEC;
-	nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
-
-	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-	set_normalized_timespec(&xtime, sec, nsec);
-	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-	ntp_clear();
-	write_sequnlock_irq(&xtime_lock);
-	clock_was_set();
-	return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
 static int set_rtc_mmss(unsigned long nowtime)
 {
 	int retval;
-
-	WARN_ON(irqs_disabled());
+	unsigned long flags;
 
 	/* gets recalled with irq locally disabled */
-	spin_lock_irq(&rtc_lock);
+	/* XXX - does irqsave resolve this? -johnstul */
+	spin_lock_irqsave(&rtc_lock, flags);
 	if (efi_enabled)
 		retval = efi_set_rtc_mmss(nowtime);
 	else
 		retval = mach_set_rtc_mmss(nowtime);
-	spin_unlock_irq(&rtc_lock);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	return retval;
 }
@@ -218,16 +131,6 @@
 
 int timer_ack;
 
-/* monotonic_clock(): returns # of nanoseconds passed since time_init()
- *		Note: This function is required to return accurate
- *		time even in the absence of multiple timer ticks.
- */
-unsigned long long monotonic_clock(void)
-{
-	return cur_timer->monotonic_clock();
-}
-EXPORT_SYMBOL(monotonic_clock);
-
 #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
 unsigned long profile_pc(struct pt_regs *regs)
 {
@@ -242,11 +145,21 @@
 #endif
 
 /*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * This is the same as the above, except we _also_ save the current
+ * Time Stamp Counter value at the time of the timer interrupt, so that
+ * we later on can estimate the time of day more exactly.
  */
-static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	/*
+	 * Here we are in the timer irq handler. We just have irqs locally
+	 * disabled but we don't know if the timer_bh is running on the other
+	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+	 * the irq version of write_lock because as just said we have irq
+	 * locally disabled. -arca
+	 */
+	write_seqlock(&xtime_lock);
+
 #ifdef CONFIG_X86_IO_APIC
 	if (timer_ack) {
 		/*
@@ -279,27 +192,6 @@
 		irq = inb_p( 0x61 );	/* read the current state */
 		outb_p( irq|0x80, 0x61 );	/* reset the IRQ */
 	}
-}
-
-/*
- * This is the same as the above, except we _also_ save the current
- * Time Stamp Counter value at the time of the timer interrupt, so that
- * we later on can estimate the time of day more exactly.
- */
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	/*
-	 * Here we are in the timer irq handler. We just have irqs locally
-	 * disabled but we don't know if the timer_bh is running on the other
-	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
-	 * the irq version of write_lock because as just said we have irq
-	 * locally disabled. -arca
-	 */
-	write_seqlock(&xtime_lock);
-
-	cur_timer->mark_offset();
- 
-	do_timer_interrupt(irq, regs);
 
 	write_sequnlock(&xtime_lock);
 
@@ -380,7 +272,6 @@
 
 static long clock_cmos_diff, sleep_start;
 
-static struct timer_opts *last_timer;
 static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
 	/*
@@ -389,10 +280,6 @@
 	clock_cmos_diff = -get_cmos_time();
 	clock_cmos_diff += get_seconds();
 	sleep_start = get_cmos_time();
-	last_timer = cur_timer;
-	cur_timer = &timer_none;
-	if (last_timer->suspend)
-		last_timer->suspend(state);
 	return 0;
 }
 
@@ -415,10 +302,6 @@
 	jiffies_64 += sleep_length;
 	wall_jiffies += sleep_length;
 	write_sequnlock_irqrestore(&xtime_lock, flags);
-	if (last_timer->resume)
-		last_timer->resume();
-	cur_timer = last_timer;
-	last_timer = NULL;
 	touch_softlockup_watchdog();
 	return 0;
 }
@@ -460,9 +343,6 @@
 		printk("Using HPET for base-timer\n");
 	}
 
-	cur_timer = select_timer();
-	printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
-
 	time_init_hook();
 }
 #endif
@@ -484,8 +364,5 @@
 	set_normalized_timespec(&wall_to_monotonic,
 		-xtime.tv_sec, -xtime.tv_nsec);
 
-	cur_timer = select_timer();
-	printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
-
 	time_init_hook();
 }
diff --git a/arch/i386/kernel/timers/Makefile b/arch/i386/kernel/timers/Makefile
deleted file mode 100644
index 8fa12be..0000000
--- a/arch/i386/kernel/timers/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for x86 timers
-#
-
-obj-y := timer.o timer_none.o timer_tsc.o timer_pit.o common.o
-
-obj-$(CONFIG_X86_CYCLONE_TIMER)	+= timer_cyclone.o
-obj-$(CONFIG_HPET_TIMER)	+= timer_hpet.o
-obj-$(CONFIG_X86_PM_TIMER)	+= timer_pm.o
diff --git a/arch/i386/kernel/timers/common.c b/arch/i386/kernel/timers/common.c
deleted file mode 100644
index 8163fe0..0000000
--- a/arch/i386/kernel/timers/common.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *	Common functions used across the timers go here
- */
-
-#include <linux/init.h>
-#include <linux/timex.h>
-#include <linux/errno.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-#include <asm/timer.h>
-#include <asm/hpet.h>
-
-#include "mach_timer.h"
-
-/* ------ Calibrate the TSC -------
- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
- * Too much 64-bit arithmetic here to do this cleanly in C, and for
- * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
- * output busy loop as low as possible. We avoid reading the CTC registers
- * directly because of the awkward 8-bit access mechanism of the 82C54
- * device.
- */
-
-#define CALIBRATE_TIME	(5 * 1000020/HZ)
-
-unsigned long calibrate_tsc(void)
-{
-	mach_prepare_counter();
-
-	{
-		unsigned long startlow, starthigh;
-		unsigned long endlow, endhigh;
-		unsigned long count;
-
-		rdtsc(startlow,starthigh);
-		mach_countup(&count);
-		rdtsc(endlow,endhigh);
-
-
-		/* Error: ECTCNEVERSET */
-		if (count <= 1)
-			goto bad_ctc;
-
-		/* 64-bit subtract - gcc just messes up with long longs */
-		__asm__("subl %2,%0\n\t"
-			"sbbl %3,%1"
-			:"=a" (endlow), "=d" (endhigh)
-			:"g" (startlow), "g" (starthigh),
-			 "0" (endlow), "1" (endhigh));
-
-		/* Error: ECPUTOOFAST */
-		if (endhigh)
-			goto bad_ctc;
-
-		/* Error: ECPUTOOSLOW */
-		if (endlow <= CALIBRATE_TIME)
-			goto bad_ctc;
-
-		__asm__("divl %2"
-			:"=a" (endlow), "=d" (endhigh)
-			:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
-
-		return endlow;
-	}
-
-	/*
-	 * The CTC wasn't reliable: we got a hit on the very first read,
-	 * or the CPU was so fast/slow that the quotient wouldn't fit in
-	 * 32 bits..
-	 */
-bad_ctc:
-	return 0;
-}
-
-#ifdef CONFIG_HPET_TIMER
-/* ------ Calibrate the TSC using HPET -------
- * Return 2^32 * (1 / (TSC clocks per usec)) for getting the CPU freq.
- * Second output is parameter 1 (when non NULL)
- * Set 2^32 * (1 / (tsc per HPET clk)) for delay_hpet().
- * calibrate_tsc() calibrates the processor TSC by comparing
- * it to the HPET timer of known frequency.
- * Too much 64-bit arithmetic here to do this cleanly in C
- */
-#define CALIBRATE_CNT_HPET 	(5 * hpet_tick)
-#define CALIBRATE_TIME_HPET 	(5 * KERNEL_TICK_USEC)
-
-unsigned long __devinit calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
-{
-	unsigned long tsc_startlow, tsc_starthigh;
-	unsigned long tsc_endlow, tsc_endhigh;
-	unsigned long hpet_start, hpet_end;
-	unsigned long result, remain;
-
-	hpet_start = hpet_readl(HPET_COUNTER);
-	rdtsc(tsc_startlow, tsc_starthigh);
-	do {
-		hpet_end = hpet_readl(HPET_COUNTER);
-	} while ((hpet_end - hpet_start) < CALIBRATE_CNT_HPET);
-	rdtsc(tsc_endlow, tsc_endhigh);
-
-	/* 64-bit subtract - gcc just messes up with long longs */
-	__asm__("subl %2,%0\n\t"
-		"sbbl %3,%1"
-		:"=a" (tsc_endlow), "=d" (tsc_endhigh)
-		:"g" (tsc_startlow), "g" (tsc_starthigh),
-		 "0" (tsc_endlow), "1" (tsc_endhigh));
-
-	/* Error: ECPUTOOFAST */
-	if (tsc_endhigh)
-		goto bad_calibration;
-
-	/* Error: ECPUTOOSLOW */
-	if (tsc_endlow <= CALIBRATE_TIME_HPET)
-		goto bad_calibration;
-
-	ASM_DIV64_REG(result, remain, tsc_endlow, 0, CALIBRATE_TIME_HPET);
-	if (remain > (tsc_endlow >> 1))
-		result++; /* rounding the result */
-
-	if (tsc_hpet_quotient_ptr) {
-		unsigned long tsc_hpet_quotient;
-
-		ASM_DIV64_REG(tsc_hpet_quotient, remain, tsc_endlow, 0,
-			CALIBRATE_CNT_HPET);
-		if (remain > (tsc_endlow >> 1))
-			tsc_hpet_quotient++; /* rounding the result */
-		*tsc_hpet_quotient_ptr = tsc_hpet_quotient;
-	}
-
-	return result;
-bad_calibration:
-	/*
-	 * the CPU was so fast/slow that the quotient wouldn't fit in
-	 * 32 bits..
-	 */
-	return 0;
-}
-#endif
-
-
-unsigned long read_timer_tsc(void)
-{
-	unsigned long retval;
-	rdtscl(retval);
-	return retval;
-}
-
-
-/* calculate cpu_khz */
-void init_cpu_khz(void)
-{
-	if (cpu_has_tsc) {
-		unsigned long tsc_quotient = calibrate_tsc();
-		if (tsc_quotient) {
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned long eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %u.%03u MHz processor.\n",
-					cpu_khz / 1000, cpu_khz % 1000);
-			}
-		}
-	}
-}
-
diff --git a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c
deleted file mode 100644
index 7e39ed8..0000000
--- a/arch/i386/kernel/timers/timer.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/timer.h>
-
-#ifdef CONFIG_HPET_TIMER
-/*
- * HPET memory read is slower than tsc reads, but is more dependable as it
- * always runs at constant frequency and reduces complexity due to
- * cpufreq. So, we prefer HPET timer to tsc based one. Also, we cannot use
- * timer_pit when HPET is active. So, we default to timer_tsc.
- */
-#endif
-/* list of timers, ordered by preference, NULL terminated */
-static struct init_timer_opts* __initdata timers[] = {
-#ifdef CONFIG_X86_CYCLONE_TIMER
-	&timer_cyclone_init,
-#endif
-#ifdef CONFIG_HPET_TIMER
-	&timer_hpet_init,
-#endif
-#ifdef CONFIG_X86_PM_TIMER
-	&timer_pmtmr_init,
-#endif
-	&timer_tsc_init,
-	&timer_pit_init,
-	NULL,
-};
-
-static char clock_override[10] __initdata;
-
-static int __init clock_setup(char* str)
-{
-	if (str)
-		strlcpy(clock_override, str, sizeof(clock_override));
-	return 1;
-}
-__setup("clock=", clock_setup);
-
-
-/* The chosen timesource has been found to be bad.
- * Fall back to a known good timesource (the PIT)
- */
-void clock_fallback(void)
-{
-	cur_timer = &timer_pit;
-}
-
-/* iterates through the list of timers, returning the first 
- * one that initializes successfully.
- */
-struct timer_opts* __init select_timer(void)
-{
-	int i = 0;
-	
-	/* find most preferred working timer */
-	while (timers[i]) {
-		if (timers[i]->init)
-			if (timers[i]->init(clock_override) == 0)
-				return timers[i]->opts;
-		++i;
-	}
-		
-	panic("select_timer: Cannot find a suitable timer\n");
-	return NULL;
-}
-
-int read_current_timer(unsigned long *timer_val)
-{
-	if (cur_timer->read_timer) {
-		*timer_val = cur_timer->read_timer();
-		return 0;
-	}
-	return -1;
-}
diff --git a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c
deleted file mode 100644
index 13892a6..0000000
--- a/arch/i386/kernel/timers/timer_cyclone.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*	Cyclone-timer: 
- *		This code implements timer_ops for the cyclone counter found
- *		on IBM x440, x360, and other Summit based systems.
- *
- *	Copyright (C) 2002 IBM, John Stultz (johnstul@us.ibm.com)
- */
-
-
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-
-#include <asm/timer.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/fixmap.h>
-#include <asm/i8253.h>
-
-#include "io_ports.h"
-
-/* Number of usecs that the last interrupt was delayed */
-static int delay_at_last_interrupt;
-
-#define CYCLONE_CBAR_ADDR 0xFEB00CD0
-#define CYCLONE_PMCC_OFFSET 0x51A0
-#define CYCLONE_MPMC_OFFSET 0x51D0
-#define CYCLONE_MPCS_OFFSET 0x51A8
-#define CYCLONE_TIMER_FREQ 100000000
-#define CYCLONE_TIMER_MASK (((u64)1<<40)-1) /* 40 bit mask */
-int use_cyclone = 0;
-
-static u32* volatile cyclone_timer;	/* Cyclone MPMC0 register */
-static u32 last_cyclone_low;
-static u32 last_cyclone_high;
-static unsigned long long monotonic_base;
-static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
-
-/* helper macro to atomically read both cyclone counter registers */
-#define read_cyclone_counter(low,high) \
-	do{ \
-		high = cyclone_timer[1]; low = cyclone_timer[0]; \
-	} while (high != cyclone_timer[1]);
-
-
-static void mark_offset_cyclone(void)
-{
-	unsigned long lost, delay;
-	unsigned long delta = last_cyclone_low;
-	int count;
-	unsigned long long this_offset, last_offset;
-
-	write_seqlock(&monotonic_lock);
-	last_offset = ((unsigned long long)last_cyclone_high<<32)|last_cyclone_low;
-	
-	spin_lock(&i8253_lock);
-	read_cyclone_counter(last_cyclone_low,last_cyclone_high);
-
-	/* read values for delay_at_last_interrupt */
-	outb_p(0x00, 0x43);     /* latch the count ASAP */
-
-	count = inb_p(0x40);    /* read the latched count */
-	count |= inb(0x40) << 8;
-
-	/*
-	 * VIA686a test code... reset the latch if count > max + 1
-	 * from timer_pit.c - cjb
-	 */
-	if (count > LATCH) {
-		outb_p(0x34, PIT_MODE);
-		outb_p(LATCH & 0xff, PIT_CH0);
-		outb(LATCH >> 8, PIT_CH0);
-		count = LATCH - 1;
-	}
-	spin_unlock(&i8253_lock);
-
-	/* lost tick compensation */
-	delta = last_cyclone_low - delta;	
-	delta /= (CYCLONE_TIMER_FREQ/1000000);
-	delta += delay_at_last_interrupt;
-	lost = delta/(1000000/HZ);
-	delay = delta%(1000000/HZ);
-	if (lost >= 2)
-		jiffies_64 += lost-1;
-	
-	/* update the monotonic base value */
-	this_offset = ((unsigned long long)last_cyclone_high<<32)|last_cyclone_low;
-	monotonic_base += (this_offset - last_offset) & CYCLONE_TIMER_MASK;
-	write_sequnlock(&monotonic_lock);
-
-	/* calculate delay_at_last_interrupt */
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
-
-
-	/* catch corner case where tick rollover occured 
-	 * between cyclone and pit reads (as noted when 
-	 * usec delta is > 90% # of usecs/tick)
-	 */
-	if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ))
-		jiffies_64++;
-}
-
-static unsigned long get_offset_cyclone(void)
-{
-	u32 offset;
-
-	if(!cyclone_timer)
-		return delay_at_last_interrupt;
-
-	/* Read the cyclone timer */
-	offset = cyclone_timer[0];
-
-	/* .. relative to previous jiffy */
-	offset = offset - last_cyclone_low;
-
-	/* convert cyclone ticks to microseconds */	
-	/* XXX slow, can we speed this up? */
-	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
-
-	/* our adjusted time offset in microseconds */
-	return delay_at_last_interrupt + offset;
-}
-
-static unsigned long long monotonic_clock_cyclone(void)
-{
-	u32 now_low, now_high;
-	unsigned long long last_offset, this_offset, base;
-	unsigned long long ret;
-	unsigned seq;
-
-	/* atomically read monotonic base & last_offset */
-	do {
-		seq = read_seqbegin(&monotonic_lock);
-		last_offset = ((unsigned long long)last_cyclone_high<<32)|last_cyclone_low;
-		base = monotonic_base;
-	} while (read_seqretry(&monotonic_lock, seq));
-
-
-	/* Read the cyclone counter */
-	read_cyclone_counter(now_low,now_high);
-	this_offset = ((unsigned long long)now_high<<32)|now_low;
-
-	/* convert to nanoseconds */
-	ret = base + ((this_offset - last_offset)&CYCLONE_TIMER_MASK);
-	return ret * (1000000000 / CYCLONE_TIMER_FREQ);
-}
-
-static int __init init_cyclone(char* override)
-{
-	u32* reg;	
-	u32 base;		/* saved cyclone base address */
-	u32 pageaddr;	/* page that contains cyclone_timer register */
-	u32 offset;		/* offset from pageaddr to cyclone_timer register */
-	int i;
-	
-	/* check clock override */
-	if (override[0] && strncmp(override,"cyclone",7))
-			return -ENODEV;
-
-	/*make sure we're on a summit box*/
-	if(!use_cyclone) return -ENODEV; 
-	
-	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
-
-	/* find base address */
-	pageaddr = (CYCLONE_CBAR_ADDR)&PAGE_MASK;
-	offset = (CYCLONE_CBAR_ADDR)&(~PAGE_MASK);
-	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
-	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
-	if(!reg){
-		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
-		return -ENODEV;
-	}
-	base = *reg;	
-	if(!base){
-		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
-		return -ENODEV;
-	}
-	
-	/* setup PMCC */
-	pageaddr = (base + CYCLONE_PMCC_OFFSET)&PAGE_MASK;
-	offset = (base + CYCLONE_PMCC_OFFSET)&(~PAGE_MASK);
-	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
-	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
-	if(!reg){
-		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
-		return -ENODEV;
-	}
-	reg[0] = 0x00000001;
-
-	/* setup MPCS */
-	pageaddr = (base + CYCLONE_MPCS_OFFSET)&PAGE_MASK;
-	offset = (base + CYCLONE_MPCS_OFFSET)&(~PAGE_MASK);
-	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
-	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
-	if(!reg){
-		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
-		return -ENODEV;
-	}
-	reg[0] = 0x00000001;
-
-	/* map in cyclone_timer */
-	pageaddr = (base + CYCLONE_MPMC_OFFSET)&PAGE_MASK;
-	offset = (base + CYCLONE_MPMC_OFFSET)&(~PAGE_MASK);
-	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
-	cyclone_timer = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
-	if(!cyclone_timer){
-		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
-		return -ENODEV;
-	}
-
-	/*quick test to make sure its ticking*/
-	for(i=0; i<3; i++){
-		u32 old = cyclone_timer[0];
-		int stall = 100;
-		while(stall--) barrier();
-		if(cyclone_timer[0] == old){
-			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
-			cyclone_timer = 0;
-			return -ENODEV;
-		}
-	}
-
-	init_cpu_khz();
-
-	/* Everything looks good! */
-	return 0;
-}
-
-
-static void delay_cyclone(unsigned long loops)
-{
-	unsigned long bclock, now;
-	if(!cyclone_timer)
-		return;
-	bclock = cyclone_timer[0];
-	do {
-		rep_nop();
-		now = cyclone_timer[0];
-	} while ((now-bclock) < loops);
-}
-/************************************************************/
-
-/* cyclone timer_opts struct */
-static struct timer_opts timer_cyclone = {
-	.name = "cyclone",
-	.mark_offset = mark_offset_cyclone, 
-	.get_offset = get_offset_cyclone,
-	.monotonic_clock =	monotonic_clock_cyclone,
-	.delay = delay_cyclone,
-};
-
-struct init_timer_opts __initdata timer_cyclone_init = {
-	.init = init_cyclone,
-	.opts = &timer_cyclone,
-};
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
deleted file mode 100644
index 17a6fe7..0000000
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * This code largely moved from arch/i386/kernel/time.c.
- * See comments there for proper credits.
- */
-
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-
-#include <asm/timer.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-
-#include "io_ports.h"
-#include "mach_timer.h"
-#include <asm/hpet.h>
-
-static unsigned long hpet_usec_quotient __read_mostly;	/* convert hpet clks to usec */
-static unsigned long tsc_hpet_quotient __read_mostly;	/* convert tsc to hpet clks */
-static unsigned long hpet_last; 	/* hpet counter value at last tick*/
-static unsigned long last_tsc_low;	/* lsb 32 bits of Time Stamp Counter */
-static unsigned long last_tsc_high; 	/* msb 32 bits of Time Stamp Counter */
-static unsigned long long monotonic_base;
-static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
-
-/* convert from cycles(64bits) => nanoseconds (64bits)
- *  basic equation:
- *		ns = cycles / (freq / ns_per_sec)
- *		ns = cycles * (ns_per_sec / freq)
- *		ns = cycles * (10^9 / (cpu_khz * 10^3))
- *		ns = cycles * (10^6 / cpu_khz)
- *
- *	Then we use scaling math (suggested by george@mvista.com) to get:
- *		ns = cycles * (10^6 * SC / cpu_khz) / SC
- *		ns = cycles * cyc2ns_scale / SC
- *
- *	And since SC is a constant power of two, we can convert the div
- *  into a shift.
- *
- *  We can use khz divisor instead of mhz to keep a better percision, since
- *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- *  (mathieu.desnoyers@polymtl.ca)
- *
- *			-johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-static unsigned long cyc2ns_scale __read_mostly;
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
-
-static inline void set_cyc2ns_scale(unsigned long cpu_khz)
-{
-	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
-}
-
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
-	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
-static unsigned long long monotonic_clock_hpet(void)
-{
-	unsigned long long last_offset, this_offset, base;
-	unsigned seq;
-
-	/* atomically read monotonic base & last_offset */
-	do {
-		seq = read_seqbegin(&monotonic_lock);
-		last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-		base = monotonic_base;
-	} while (read_seqretry(&monotonic_lock, seq));
-
-	/* Read the Time Stamp Counter */
-	rdtscll(this_offset);
-
-	/* return the value in ns */
-	return base + cycles_2_ns(this_offset - last_offset);
-}
-
-static unsigned long get_offset_hpet(void)
-{
-	register unsigned long eax, edx;
-
-	eax = hpet_readl(HPET_COUNTER);
-	eax -= hpet_last;	/* hpet delta */
-	eax = min(hpet_tick, eax);
-	/*
-         * Time offset = (hpet delta) * ( usecs per HPET clock )
-	 *             = (hpet delta) * ( usecs per tick / HPET clocks per tick)
-	 *             = (hpet delta) * ( hpet_usec_quotient ) / (2^32)
-	 *
-	 * Where,
-	 * hpet_usec_quotient = (2^32 * usecs per tick)/HPET clocks per tick
-	 *
-	 * Using a mull instead of a divl saves some cycles in critical path.
-         */
-	ASM_MUL64_REG(eax, edx, hpet_usec_quotient, eax);
-
-	/* our adjusted time offset in microseconds */
-	return edx;
-}
-
-static void mark_offset_hpet(void)
-{
-	unsigned long long this_offset, last_offset;
-	unsigned long offset;
-
-	write_seqlock(&monotonic_lock);
-	last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-	rdtsc(last_tsc_low, last_tsc_high);
-
-	if (hpet_use_timer)
-		offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
-	else
-		offset = hpet_readl(HPET_COUNTER);
-	if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) {
-		int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1;
-		jiffies_64 += lost_ticks;
-	}
-	hpet_last = offset;
-
-	/* update the monotonic base value */
-	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-	monotonic_base += cycles_2_ns(this_offset - last_offset);
-	write_sequnlock(&monotonic_lock);
-}
-
-static void delay_hpet(unsigned long loops)
-{
-	unsigned long hpet_start, hpet_end;
-	unsigned long eax;
-
-	/* loops is the number of cpu cycles. Convert it to hpet clocks */
-	ASM_MUL64_REG(eax, loops, tsc_hpet_quotient, loops);
-
-	hpet_start = hpet_readl(HPET_COUNTER);
-	do {
-		rep_nop();
-		hpet_end = hpet_readl(HPET_COUNTER);
-	} while ((hpet_end - hpet_start) < (loops));
-}
-
-static struct timer_opts timer_hpet;
-
-static int __init init_hpet(char* override)
-{
-	unsigned long result, remain;
-
-	/* check clock override */
-	if (override[0] && strncmp(override,"hpet",4))
-		return -ENODEV;
-
-	if (!is_hpet_enabled())
-		return -ENODEV;
-
-	printk("Using HPET for gettimeofday\n");
-	if (cpu_has_tsc) {
-		unsigned long tsc_quotient = calibrate_tsc_hpet(&tsc_hpet_quotient);
-		if (tsc_quotient) {
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned long eax=0, edx=1000;
-				ASM_DIV64_REG(cpu_khz, edx, tsc_quotient,
-						eax, edx);
-				printk("Detected %u.%03u MHz processor.\n",
-					cpu_khz / 1000, cpu_khz % 1000);
-			}
-			set_cyc2ns_scale(cpu_khz);
-		}
-		/* set this only when cpu_has_tsc */
-		timer_hpet.read_timer = read_timer_tsc;
-	}
-
-	/*
-	 * Math to calculate hpet to usec multiplier
-	 * Look for the comments at get_offset_hpet()
-	 */
-	ASM_DIV64_REG(result, remain, hpet_tick, 0, KERNEL_TICK_USEC);
-	if (remain > (hpet_tick >> 1))
-		result++; /* rounding the result */
-	hpet_usec_quotient = result;
-
-	return 0;
-}
-
-static int hpet_resume(void)
-{
-	write_seqlock(&monotonic_lock);
-	/* Assume this is the last mark offset time */
-	rdtsc(last_tsc_low, last_tsc_high);
-
-	if (hpet_use_timer)
-		hpet_last = hpet_readl(HPET_T0_CMP) - hpet_tick;
-	else
-		hpet_last = hpet_readl(HPET_COUNTER);
-	write_sequnlock(&monotonic_lock);
-	return 0;
-}
-/************************************************************/
-
-/* tsc timer_opts struct */
-static struct timer_opts timer_hpet __read_mostly = {
-	.name = 		"hpet",
-	.mark_offset =		mark_offset_hpet,
-	.get_offset =		get_offset_hpet,
-	.monotonic_clock =	monotonic_clock_hpet,
-	.delay = 		delay_hpet,
-	.resume	=		hpet_resume,
-};
-
-struct init_timer_opts __initdata timer_hpet_init = {
-	.init =	init_hpet,
-	.opts = &timer_hpet,
-};
diff --git a/arch/i386/kernel/timers/timer_none.c b/arch/i386/kernel/timers/timer_none.c
deleted file mode 100644
index 4ea2f41..0000000
--- a/arch/i386/kernel/timers/timer_none.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <linux/init.h>
-#include <asm/timer.h>
-
-static void mark_offset_none(void)
-{
-	/* nothing needed */
-}
-
-static unsigned long get_offset_none(void)
-{
-	return 0;
-}
-
-static unsigned long long monotonic_clock_none(void)
-{
-	return 0;
-}
-
-static void delay_none(unsigned long loops)
-{
-	int d0;
-	__asm__ __volatile__(
-		"\tjmp 1f\n"
-		".align 16\n"
-		"1:\tjmp 2f\n"
-		".align 16\n"
-		"2:\tdecl %0\n\tjns 2b"
-		:"=&a" (d0)
-		:"0" (loops));
-}
-
-/* none timer_opts struct */
-struct timer_opts timer_none = {
-	.name = 	"none",
-	.mark_offset =	mark_offset_none, 
-	.get_offset =	get_offset_none,
-	.monotonic_clock =	monotonic_clock_none,
-	.delay = delay_none,
-};
diff --git a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
deleted file mode 100644
index b9b6bd5..0000000
--- a/arch/i386/kernel/timers/timer_pit.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * This code largely moved from arch/i386/kernel/time.c.
- * See comments there for proper credits.
- */
-
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/sysdev.h>
-#include <linux/timex.h>
-#include <asm/delay.h>
-#include <asm/mpspec.h>
-#include <asm/timer.h>
-#include <asm/smp.h>
-#include <asm/io.h>
-#include <asm/arch_hooks.h>
-#include <asm/i8253.h>
-
-#include "do_timer.h"
-#include "io_ports.h"
-
-static int count_p; /* counter in get_offset_pit() */
-
-static int __init init_pit(char* override)
-{
- 	/* check clock override */
- 	if (override[0] && strncmp(override,"pit",3))
- 		printk(KERN_ERR "Warning: clock= override failed. Defaulting "
-				"to PIT\n");
- 	init_cpu_khz();
-	count_p = LATCH;
-	return 0;
-}
-
-static void mark_offset_pit(void)
-{
-	/* nothing needed */
-}
-
-static unsigned long long monotonic_clock_pit(void)
-{
-	return 0;
-}
-
-static void delay_pit(unsigned long loops)
-{
-	int d0;
-	__asm__ __volatile__(
-		"\tjmp 1f\n"
-		".align 16\n"
-		"1:\tjmp 2f\n"
-		".align 16\n"
-		"2:\tdecl %0\n\tjns 2b"
-		:"=&a" (d0)
-		:"0" (loops));
-}
-
-
-/* This function must be called with xtime_lock held.
- * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought....		pjsg (1993-08-28)
- * 
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
- */
-
-static unsigned long get_offset_pit(void)
-{
-	int count;
-	unsigned long flags;
-	static unsigned long jiffies_p = 0;
-
-	/*
-	 * cache volatile jiffies temporarily; we have xtime_lock. 
-	 */
-	unsigned long jiffies_t;
-
-	spin_lock_irqsave(&i8253_lock, flags);
-	/* timer count may underflow right here */
-	outb_p(0x00, PIT_MODE);	/* latch the count ASAP */
-
-	count = inb_p(PIT_CH0);	/* read the latched count */
-
-	/*
-	 * We do this guaranteed double memory access instead of a _p 
-	 * postfix in the previous port access. Wheee, hackady hack
-	 */
- 	jiffies_t = jiffies;
-
-	count |= inb_p(PIT_CH0) << 8;
-	
-        /* VIA686a test code... reset the latch if count > max + 1 */
-        if (count > LATCH) {
-                outb_p(0x34, PIT_MODE);
-                outb_p(LATCH & 0xff, PIT_CH0);
-                outb(LATCH >> 8, PIT_CH0);
-                count = LATCH - 1;
-        }
-	
-	/*
-	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are two kinds of problems that must be avoided here:
-	 *  1. the timer counter underflows
-	 *  2. hardware problem with the timer, not giving us continuous time,
-	 *     the counter does small "jumps" upwards on some Pentium systems,
-	 *     (see c't 95/10 page 335 for Neptun bug.)
-	 */
-
-	if( jiffies_t == jiffies_p ) {
-		if( count > count_p ) {
-			/* the nutcase */
-			count = do_timer_overflow(count);
-		}
-	} else
-		jiffies_p = jiffies_t;
-
-	count_p = count;
-
-	spin_unlock_irqrestore(&i8253_lock, flags);
-
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	count = (count + LATCH/2) / LATCH;
-
-	return count;
-}
-
-
-/* tsc timer_opts struct */
-struct timer_opts timer_pit = {
-	.name = "pit",
-	.mark_offset = mark_offset_pit, 
-	.get_offset = get_offset_pit,
-	.monotonic_clock = monotonic_clock_pit,
-	.delay = delay_pit,
-};
-
-struct init_timer_opts __initdata timer_pit_init = {
-	.init = init_pit, 
-	.opts = &timer_pit,
-};
-
-void setup_pit_timer(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8253_lock, flags);
-	outb_p(0x34,PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
-	udelay(10);
-	outb_p(LATCH & 0xff , PIT_CH0);	/* LSB */
-	udelay(10);
-	outb(LATCH >> 8 , PIT_CH0);	/* MSB */
-	spin_unlock_irqrestore(&i8253_lock, flags);
-}
diff --git a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
deleted file mode 100644
index 144e94a..0000000
--- a/arch/i386/kernel/timers/timer_pm.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * (C) Dominik Brodowski <linux@brodo.de> 2003
- *
- * Driver to use the Power Management Timer (PMTMR) available in some
- * southbridges as primary timing source for the Linux kernel.
- *
- * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
- * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
- *
- * This file is licensed under the GPL v2.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/types.h>
-#include <asm/timer.h>
-#include <asm/smp.h>
-#include <asm/io.h>
-#include <asm/arch_hooks.h>
-
-#include <linux/timex.h>
-#include "mach_timer.h"
-
-/* Number of PMTMR ticks expected during calibration run */
-#define PMTMR_TICKS_PER_SEC 3579545
-#define PMTMR_EXPECTED_RATE \
-  ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (CLOCK_TICK_RATE>>10))
-
-
-/* The I/O port the PMTMR resides at.
- * The location is detected during setup_arch(),
- * in arch/i386/acpi/boot.c */
-u32 pmtmr_ioport = 0;
-
-
-/* value of the Power timer at last timer interrupt */
-static u32 offset_tick;
-static u32 offset_delay;
-
-static unsigned long long monotonic_base;
-static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
-
-#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
-
-static int pmtmr_need_workaround __read_mostly = 1;
-
-/*helper function to safely read acpi pm timesource*/
-static inline u32 read_pmtmr(void)
-{
-	if (pmtmr_need_workaround) {
-		u32 v1, v2, v3;
-
-		/* It has been reported that because of various broken
-		 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time
-		 * source is not latched, so you must read it multiple
-		 * times to insure a safe value is read.
-		 */
-		do {
-			v1 = inl(pmtmr_ioport);
-			v2 = inl(pmtmr_ioport);
-			v3 = inl(pmtmr_ioport);
-		} while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
-			 || (v3 > v1 && v3 < v2));
-
-		/* mask the output to 24 bits */
-		return v2 & ACPI_PM_MASK;
-	}
-
-	return inl(pmtmr_ioport) & ACPI_PM_MASK;
-}
-
-
-/*
- * Some boards have the PMTMR running way too fast. We check
- * the PMTMR rate against PIT channel 2 to catch these cases.
- */
-static int verify_pmtmr_rate(void)
-{
-	u32 value1, value2;
-	unsigned long count, delta;
-
-	mach_prepare_counter();
-	value1 = read_pmtmr();
-	mach_countup(&count);
-	value2 = read_pmtmr();
-	delta = (value2 - value1) & ACPI_PM_MASK;
-
-	/* Check that the PMTMR delta is within 5% of what we expect */
-	if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
-	    delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
-		printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% of normal - aborting.\n", 100UL * delta / PMTMR_EXPECTED_RATE);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int init_pmtmr(char* override)
-{
-	u32 value1, value2;
-	unsigned int i;
-
- 	if (override[0] && strncmp(override,"pmtmr",5))
-		return -ENODEV;
-
-	if (!pmtmr_ioport)
-		return -ENODEV;
-
-	/* we use the TSC for delay_pmtmr, so make sure it exists */
-	if (!cpu_has_tsc)
-		return -ENODEV;
-
-	/* "verify" this timing source */
-	value1 = read_pmtmr();
-	for (i = 0; i < 10000; i++) {
-		value2 = read_pmtmr();
-		if (value2 == value1)
-			continue;
-		if (value2 > value1)
-			goto pm_good;
-		if ((value2 < value1) && ((value2) < 0xFFF))
-			goto pm_good;
-		printk(KERN_INFO "PM-Timer had inconsistent results: 0x%#x, 0x%#x - aborting.\n", value1, value2);
-		return -EINVAL;
-	}
-	printk(KERN_INFO "PM-Timer had no reasonable result: 0x%#x - aborting.\n", value1);
-	return -ENODEV;
-
-pm_good:
-	if (verify_pmtmr_rate() != 0)
-		return -ENODEV;
-
-	init_cpu_khz();
-	return 0;
-}
-
-static inline u32 cyc2us(u32 cycles)
-{
-	/* The Power Management Timer ticks at 3.579545 ticks per microsecond.
-	 * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
-	 *
-	 * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
-	 * easily be multiplied with 286 (=0x11E) without having to fear
-	 * u32 overflows.
-	 */
-	cycles *= 286;
-	return (cycles >> 10);
-}
-
-/*
- * this gets called during each timer interrupt
- *   - Called while holding the writer xtime_lock
- */
-static void mark_offset_pmtmr(void)
-{
-	u32 lost, delta, last_offset;
-	static int first_run = 1;
-	last_offset = offset_tick;
-
-	write_seqlock(&monotonic_lock);
-
-	offset_tick = read_pmtmr();
-
-	/* calculate tick interval */
-	delta = (offset_tick - last_offset) & ACPI_PM_MASK;
-
-	/* convert to usecs */
-	delta = cyc2us(delta);
-
-	/* update the monotonic base value */
-	monotonic_base += delta * NSEC_PER_USEC;
-	write_sequnlock(&monotonic_lock);
-
-	/* convert to ticks */
-	delta += offset_delay;
-	lost = delta / (USEC_PER_SEC / HZ);
-	offset_delay = delta % (USEC_PER_SEC / HZ);
-
-
-	/* compensate for lost ticks */
-	if (lost >= 2)
-		jiffies_64 += lost - 1;
-
-	/* don't calculate delay for first run,
-	   or if we've got less then a tick */
-	if (first_run || (lost < 1)) {
-		first_run = 0;
-		offset_delay = 0;
-	}
-}
-
-static int pmtmr_resume(void)
-{
-	write_seqlock(&monotonic_lock);
-	/* Assume this is the last mark offset time */
-	offset_tick = read_pmtmr();
-	write_sequnlock(&monotonic_lock);
-	return 0;
-}
-
-static unsigned long long monotonic_clock_pmtmr(void)
-{
-	u32 last_offset, this_offset;
-	unsigned long long base, ret;
-	unsigned seq;
-
-
-	/* atomically read monotonic base & last_offset */
-	do {
-		seq = read_seqbegin(&monotonic_lock);
-		last_offset = offset_tick;
-		base = monotonic_base;
-	} while (read_seqretry(&monotonic_lock, seq));
-
-	/* Read the pmtmr */
-	this_offset =  read_pmtmr();
-
-	/* convert to nanoseconds */
-	ret = (this_offset - last_offset) & ACPI_PM_MASK;
-	ret = base + (cyc2us(ret) * NSEC_PER_USEC);
-	return ret;
-}
-
-static void delay_pmtmr(unsigned long loops)
-{
-	unsigned long bclock, now;
-
-	rdtscl(bclock);
-	do
-	{
-		rep_nop();
-		rdtscl(now);
-	} while ((now-bclock) < loops);
-}
-
-
-/*
- * get the offset (in microseconds) from the last call to mark_offset()
- *	- Called holding a reader xtime_lock
- */
-static unsigned long get_offset_pmtmr(void)
-{
-	u32 now, offset, delta = 0;
-
-	offset = offset_tick;
-	now = read_pmtmr();
-	delta = (now - offset)&ACPI_PM_MASK;
-
-	return (unsigned long) offset_delay + cyc2us(delta);
-}
-
-
-/* acpi timer_opts struct */
-static struct timer_opts timer_pmtmr = {
-	.name			= "pmtmr",
-	.mark_offset		= mark_offset_pmtmr,
-	.get_offset		= get_offset_pmtmr,
-	.monotonic_clock 	= monotonic_clock_pmtmr,
-	.delay 			= delay_pmtmr,
-	.read_timer 		= read_timer_tsc,
-	.resume			= pmtmr_resume,
-};
-
-struct init_timer_opts __initdata timer_pmtmr_init = {
-	.init = init_pmtmr,
-	.opts = &timer_pmtmr,
-};
-
-#ifdef CONFIG_PCI
-/*
- * PIIX4 Errata:
- *
- * The power management timer may return improper results when read.
- * Although the timer value settles properly after incrementing,
- * while incrementing there is a 3 ns window every 69.8 ns where the
- * timer value is indeterminate (a 4.2% chance that the data will be
- * incorrect when read). As a result, the ACPI free running count up
- * timer specification is violated due to erroneous reads.
- */
-static int __init pmtmr_bug_check(void)
-{
-	static struct pci_device_id gray_list[] __initdata = {
-		/* these chipsets may have bug. */
-		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82801DB_0) },
-		{ },
-	};
-	struct pci_dev *dev;
-	int pmtmr_has_bug = 0;
-	u8 rev;
-
-	if (cur_timer != &timer_pmtmr || !pmtmr_need_workaround)
-		return 0;
-
-	dev = pci_get_device(PCI_VENDOR_ID_INTEL,
-			     PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
-	if (dev) {
-		pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-		/* the bug has been fixed in PIIX4M */
-		if (rev < 3) {
-			printk(KERN_WARNING "* Found PM-Timer Bug on this "
-				"chipset. Due to workarounds for a bug,\n"
-				"* this time source is slow.  Consider trying "
-				"other time sources (clock=)\n");
-			pmtmr_has_bug = 1;
-		}
-		pci_dev_put(dev);
-	}
-
-	if (pci_dev_present(gray_list)) {
-		printk(KERN_WARNING "* This chipset may have PM-Timer Bug.  Due"
-			" to workarounds for a bug,\n"
-			"* this time source is slow. If you are sure your timer"
-			" does not have\n"
-			"* this bug, please use \"pmtmr_good\" to disable the "
-			"workaround\n");
-		pmtmr_has_bug = 1;
-	}
-
-	if (!pmtmr_has_bug)
-		pmtmr_need_workaround = 0;
-
-	return 0;
-}
-device_initcall(pmtmr_bug_check);
-#endif
-
-static int __init pmtr_good_setup(char *__str)
-{
-	pmtmr_need_workaround = 0;
-	return 1;
-}
-__setup("pmtmr_good", pmtr_good_setup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
-MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86");
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
deleted file mode 100644
index f1187dd..0000000
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * This code largely moved from arch/i386/kernel/time.c.
- * See comments there for proper credits.
- *
- * 2004-06-25    Jesper Juhl
- *      moved mark_offset_tsc below cpufreq_delayed_get to avoid gcc 3.4
- *      failing to inline.
- */
-
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-#include <linux/errno.h>
-#include <linux/cpufreq.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-
-#include <asm/timer.h>
-#include <asm/io.h>
-/* processor.h for distable_tsc flag */
-#include <asm/processor.h>
-
-#include "io_ports.h"
-#include "mach_timer.h"
-
-#include <asm/hpet.h>
-#include <asm/i8253.h>
-
-#ifdef CONFIG_HPET_TIMER
-static unsigned long hpet_usec_quotient;
-static unsigned long hpet_last;
-static struct timer_opts timer_tsc;
-#endif
-
-static inline void cpufreq_delayed_get(void);
-
-int tsc_disable __devinitdata = 0;
-
-static int use_tsc;
-/* Number of usecs that the last interrupt was delayed */
-static int delay_at_last_interrupt;
-
-static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
-static unsigned long last_tsc_high; /* msb 32 bits of Time Stamp Counter */
-static unsigned long long monotonic_base;
-static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
-
-/* Avoid compensating for lost ticks before TSCs are synched */
-static int detect_lost_ticks;
-static int __init start_lost_tick_compensation(void)
-{
-	detect_lost_ticks = 1;
-	return 0;
-}
-late_initcall(start_lost_tick_compensation);
-
-/* convert from cycles(64bits) => nanoseconds (64bits)
- *  basic equation:
- *		ns = cycles / (freq / ns_per_sec)
- *		ns = cycles * (ns_per_sec / freq)
- *		ns = cycles * (10^9 / (cpu_khz * 10^3))
- *		ns = cycles * (10^6 / cpu_khz)
- *
- *	Then we use scaling math (suggested by george@mvista.com) to get:
- *		ns = cycles * (10^6 * SC / cpu_khz) / SC
- *		ns = cycles * cyc2ns_scale / SC
- *
- *	And since SC is a constant power of two, we can convert the div
- *  into a shift.
- *
- *  We can use khz divisor instead of mhz to keep a better percision, since
- *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- *  (mathieu.desnoyers@polymtl.ca)
- *
- *			-johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-static unsigned long cyc2ns_scale __read_mostly;
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
-
-static inline void set_cyc2ns_scale(unsigned long cpu_khz)
-{
-	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
-}
-
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
-	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
-static int count2; /* counter for mark_offset_tsc() */
-
-/* Cached *multiplier* to convert TSC counts to microseconds.
- * (see the equation below).
- * Equal to 2^32 * (1 / (clocks per usec) ).
- * Initialized in time_init.
- */
-static unsigned long fast_gettimeoffset_quotient;
-
-static unsigned long get_offset_tsc(void)
-{
-	register unsigned long eax, edx;
-
-	/* Read the Time Stamp Counter */
-
-	rdtsc(eax,edx);
-
-	/* .. relative to previous jiffy (32 bits is enough) */
-	eax -= last_tsc_low;	/* tsc_low delta */
-
-	/*
-         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
-         *             = (tsc_low delta) * (usecs_per_clock)
-         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
-	 *
-	 * Using a mull instead of a divl saves up to 31 clock cycles
-	 * in the critical path.
-         */
-
-	__asm__("mull %2"
-		:"=a" (eax), "=d" (edx)
-		:"rm" (fast_gettimeoffset_quotient),
-		 "0" (eax));
-
-	/* our adjusted time offset in microseconds */
-	return delay_at_last_interrupt + edx;
-}
-
-static unsigned long long monotonic_clock_tsc(void)
-{
-	unsigned long long last_offset, this_offset, base;
-	unsigned seq;
-	
-	/* atomically read monotonic base & last_offset */
-	do {
-		seq = read_seqbegin(&monotonic_lock);
-		last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-		base = monotonic_base;
-	} while (read_seqretry(&monotonic_lock, seq));
-
-	/* Read the Time Stamp Counter */
-	rdtscll(this_offset);
-
-	/* return the value in ns */
-	return base + cycles_2_ns(this_offset - last_offset);
-}
-
-/*
- * Scheduler clock - returns current time in nanosec units.
- */
-unsigned long long sched_clock(void)
-{
-	unsigned long long this_offset;
-
-	/*
-	 * In the NUMA case we dont use the TSC as they are not
-	 * synchronized across all CPUs.
-	 */
-#ifndef CONFIG_NUMA
-	if (!use_tsc)
-#endif
-		/* no locking but a rare wrong value is not a big deal */
-		return jiffies_64 * (1000000000 / HZ);
-
-	/* Read the Time Stamp Counter */
-	rdtscll(this_offset);
-
-	/* return the value in ns */
-	return cycles_2_ns(this_offset);
-}
-
-static void delay_tsc(unsigned long loops)
-{
-	unsigned long bclock, now;
-	
-	rdtscl(bclock);
-	do
-	{
-		rep_nop();
-		rdtscl(now);
-	} while ((now-bclock) < loops);
-}
-
-#ifdef CONFIG_HPET_TIMER
-static void mark_offset_tsc_hpet(void)
-{
-	unsigned long long this_offset, last_offset;
- 	unsigned long offset, temp, hpet_current;
-
-	write_seqlock(&monotonic_lock);
-	last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-	/*
-	 * It is important that these two operations happen almost at
-	 * the same time. We do the RDTSC stuff first, since it's
-	 * faster. To avoid any inconsistencies, we need interrupts
-	 * disabled locally.
-	 */
-	/*
-	 * Interrupts are just disabled locally since the timer irq
-	 * has the SA_INTERRUPT flag set. -arca
-	 */
-	/* read Pentium cycle counter */
-
-	hpet_current = hpet_readl(HPET_COUNTER);
-	rdtsc(last_tsc_low, last_tsc_high);
-
-	/* lost tick compensation */
-	offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
-	if (unlikely(((offset - hpet_last) > hpet_tick) && (hpet_last != 0))
-					&& detect_lost_ticks) {
-		int lost_ticks = (offset - hpet_last) / hpet_tick;
-		jiffies_64 += lost_ticks;
-	}
-	hpet_last = hpet_current;
-
-	/* update the monotonic base value */
-	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-	monotonic_base += cycles_2_ns(this_offset - last_offset);
-	write_sequnlock(&monotonic_lock);
-
-	/* calculate delay_at_last_interrupt */
-	/*
-	 * Time offset = (hpet delta) * ( usecs per HPET clock )
-	 *             = (hpet delta) * ( usecs per tick / HPET clocks per tick)
-	 *             = (hpet delta) * ( hpet_usec_quotient ) / (2^32)
-	 * Where,
-	 * hpet_usec_quotient = (2^32 * usecs per tick)/HPET clocks per tick
-	 */
-	delay_at_last_interrupt = hpet_current - offset;
-	ASM_MUL64_REG(temp, delay_at_last_interrupt,
-			hpet_usec_quotient, delay_at_last_interrupt);
-}
-#endif
-
-
-#ifdef CONFIG_CPU_FREQ
-#include <linux/workqueue.h>
-
-static unsigned int cpufreq_delayed_issched = 0;
-static unsigned int cpufreq_init = 0;
-static struct work_struct cpufreq_delayed_get_work;
-
-static void handle_cpufreq_delayed_get(void *v)
-{
-	unsigned int cpu;
-	for_each_online_cpu(cpu) {
-		cpufreq_get(cpu);
-	}
-	cpufreq_delayed_issched = 0;
-}
-
-/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries
- * to verify the CPU frequency the timing core thinks the CPU is running
- * at is still correct.
- */
-static inline void cpufreq_delayed_get(void) 
-{
-	if (cpufreq_init && !cpufreq_delayed_issched) {
-		cpufreq_delayed_issched = 1;
-		printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n");
-		schedule_work(&cpufreq_delayed_get_work);
-	}
-}
-
-/* If the CPU frequency is scaled, TSC-based delays will need a different
- * loops_per_jiffy value to function properly.
- */
-
-static unsigned int  ref_freq = 0;
-static unsigned long loops_per_jiffy_ref = 0;
-
-#ifndef CONFIG_SMP
-static unsigned long fast_gettimeoffset_ref = 0;
-static unsigned int cpu_khz_ref = 0;
-#endif
-
-static int
-time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-		       void *data)
-{
-	struct cpufreq_freqs *freq = data;
-
-	if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
-		write_seqlock_irq(&xtime_lock);
-	if (!ref_freq) {
-		if (!freq->old){
-			ref_freq = freq->new;
-			goto end;
-		}
-		ref_freq = freq->old;
-		loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
-#ifndef CONFIG_SMP
-		fast_gettimeoffset_ref = fast_gettimeoffset_quotient;
-		cpu_khz_ref = cpu_khz;
-#endif
-	}
-
-	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
-	    (val == CPUFREQ_RESUMECHANGE)) {
-		if (!(freq->flags & CPUFREQ_CONST_LOOPS))
-			cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
-#ifndef CONFIG_SMP
-		if (cpu_khz)
-			cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
-		if (use_tsc) {
-			if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
-				fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
-				set_cyc2ns_scale(cpu_khz);
-			}
-		}
-#endif
-	}
-
-end:
-	if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
-		write_sequnlock_irq(&xtime_lock);
-
-	return 0;
-}
-
-static struct notifier_block time_cpufreq_notifier_block = {
-	.notifier_call	= time_cpufreq_notifier
-};
-
-
-static int __init cpufreq_tsc(void)
-{
-	int ret;
-	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
-	ret = cpufreq_register_notifier(&time_cpufreq_notifier_block,
-					CPUFREQ_TRANSITION_NOTIFIER);
-	if (!ret)
-		cpufreq_init = 1;
-	return ret;
-}
-core_initcall(cpufreq_tsc);
-
-#else /* CONFIG_CPU_FREQ */
-static inline void cpufreq_delayed_get(void) { return; }
-#endif 
-
-int recalibrate_cpu_khz(void)
-{
-#ifndef CONFIG_SMP
-	unsigned int cpu_khz_old = cpu_khz;
-
-	if (cpu_has_tsc) {
-		local_irq_disable();
-		init_cpu_khz();
-		local_irq_enable();
-		cpu_data[0].loops_per_jiffy =
-		    cpufreq_scale(cpu_data[0].loops_per_jiffy,
-			          cpu_khz_old,
-				  cpu_khz);
-		return 0;
-	} else
-		return -ENODEV;
-#else
-	return -ENODEV;
-#endif
-}
-EXPORT_SYMBOL(recalibrate_cpu_khz);
-
-static void mark_offset_tsc(void)
-{
-	unsigned long lost,delay;
-	unsigned long delta = last_tsc_low;
-	int count;
-	int countmp;
-	static int count1 = 0;
-	unsigned long long this_offset, last_offset;
-	static int lost_count = 0;
-
-	write_seqlock(&monotonic_lock);
-	last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-	/*
-	 * It is important that these two operations happen almost at
-	 * the same time. We do the RDTSC stuff first, since it's
-	 * faster. To avoid any inconsistencies, we need interrupts
-	 * disabled locally.
-	 */
-
-	/*
-	 * Interrupts are just disabled locally since the timer irq
-	 * has the SA_INTERRUPT flag set. -arca
-	 */
-
-	/* read Pentium cycle counter */
-
-	rdtsc(last_tsc_low, last_tsc_high);
-
-	spin_lock(&i8253_lock);
-	outb_p(0x00, PIT_MODE);     /* latch the count ASAP */
-
-	count = inb_p(PIT_CH0);    /* read the latched count */
-	count |= inb(PIT_CH0) << 8;
-
-	/*
-	 * VIA686a test code... reset the latch if count > max + 1
-	 * from timer_pit.c - cjb
-	 */
-	if (count > LATCH) {
-		outb_p(0x34, PIT_MODE);
-		outb_p(LATCH & 0xff, PIT_CH0);
-		outb(LATCH >> 8, PIT_CH0);
-		count = LATCH - 1;
-	}
-
-	spin_unlock(&i8253_lock);
-
-	if (pit_latch_buggy) {
-		/* get center value of last 3 time lutch */
-		if ((count2 >= count && count >= count1)
-		    || (count1 >= count && count >= count2)) {
-			count2 = count1; count1 = count;
-		} else if ((count1 >= count2 && count2 >= count)
-			   || (count >= count2 && count2 >= count1)) {
-			countmp = count;count = count2;
-			count2 = count1;count1 = countmp;
-		} else {
-			count2 = count1; count1 = count; count = count1;
-		}
-	}
-
-	/* lost tick compensation */
-	delta = last_tsc_low - delta;
-	{
-		register unsigned long eax, edx;
-		eax = delta;
-		__asm__("mull %2"
-		:"=a" (eax), "=d" (edx)
-		:"rm" (fast_gettimeoffset_quotient),
-		 "0" (eax));
-		delta = edx;
-	}
-	delta += delay_at_last_interrupt;
-	lost = delta/(1000000/HZ);
-	delay = delta%(1000000/HZ);
-	if (lost >= 2 && detect_lost_ticks) {
-		jiffies_64 += lost-1;
-
-		/* sanity check to ensure we're not always losing ticks */
-		if (lost_count++ > 100) {
-			printk(KERN_WARNING "Losing too many ticks!\n");
-			printk(KERN_WARNING "TSC cannot be used as a timesource.  \n");
-			printk(KERN_WARNING "Possible reasons for this are:\n");
-			printk(KERN_WARNING "  You're running with Speedstep,\n");
-			printk(KERN_WARNING "  You don't have DMA enabled for your hard disk (see hdparm),\n");
-			printk(KERN_WARNING "  Incorrect TSC synchronization on an SMP system (see dmesg).\n");
-			printk(KERN_WARNING "Falling back to a sane timesource now.\n");
-
-			clock_fallback();
-		}
-		/* ... but give the TSC a fair chance */
-		if (lost_count > 25)
-			cpufreq_delayed_get();
-	} else
-		lost_count = 0;
-	/* update the monotonic base value */
-	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;
-	monotonic_base += cycles_2_ns(this_offset - last_offset);
-	write_sequnlock(&monotonic_lock);
-
-	/* calculate delay_at_last_interrupt */
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
-
-	/* catch corner case where tick rollover occured
-	 * between tsc and pit reads (as noted when
-	 * usec delta is > 90% # of usecs/tick)
-	 */
-	if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ))
-		jiffies_64++;
-}
-
-static int __init init_tsc(char* override)
-{
-
-	/* check clock override */
-	if (override[0] && strncmp(override,"tsc",3)) {
-#ifdef CONFIG_HPET_TIMER
-		if (is_hpet_enabled()) {
-			printk(KERN_ERR "Warning: clock= override failed. Defaulting to tsc\n");
-		} else
-#endif
-		{
-			return -ENODEV;
-		}
-	}
-
-	/*
-	 * If we have APM enabled or the CPU clock speed is variable
-	 * (CPU stops clock on HLT or slows clock to save power)
-	 * then the TSC timestamps may diverge by up to 1 jiffy from
-	 * 'real time' but nothing will break.
-	 * The most frequent case is that the CPU is "woken" from a halt
-	 * state by the timer interrupt itself, so we get 0 error. In the
-	 * rare cases where a driver would "wake" the CPU and request a
-	 * timestamp, the maximum error is < 1 jiffy. But timestamps are
-	 * still perfectly ordered.
-	 * Note that the TSC counter will be reset if APM suspends
-	 * to disk; this won't break the kernel, though, 'cuz we're
-	 * smart.  See arch/i386/kernel/apm.c.
-	 */
- 	/*
- 	 *	Firstly we have to do a CPU check for chips with
- 	 * 	a potentially buggy TSC. At this point we haven't run
- 	 *	the ident/bugs checks so we must run this hook as it
- 	 *	may turn off the TSC flag.
- 	 *
- 	 *	NOTE: this doesn't yet handle SMP 486 machines where only
- 	 *	some CPU's have a TSC. Thats never worked and nobody has
- 	 *	moaned if you have the only one in the world - you fix it!
- 	 */
-
-	count2 = LATCH; /* initialize counter for mark_offset_tsc() */
-
-	if (cpu_has_tsc) {
-		unsigned long tsc_quotient;
-#ifdef CONFIG_HPET_TIMER
-		if (is_hpet_enabled() && hpet_use_timer) {
-			unsigned long result, remain;
-			printk("Using TSC for gettimeofday\n");
-			tsc_quotient = calibrate_tsc_hpet(NULL);
-			timer_tsc.mark_offset = &mark_offset_tsc_hpet;
-			/*
-			 * Math to calculate hpet to usec multiplier
-			 * Look for the comments at get_offset_tsc_hpet()
-			 */
-			ASM_DIV64_REG(result, remain, hpet_tick,
-					0, KERNEL_TICK_USEC);
-			if (remain > (hpet_tick >> 1))
-				result++; /* rounding the result */
-
-			hpet_usec_quotient = result;
-		} else
-#endif
-		{
-			tsc_quotient = calibrate_tsc();
-		}
-
-		if (tsc_quotient) {
-			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
-			 */
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned long eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %u.%03u MHz processor.\n",
-					cpu_khz / 1000, cpu_khz % 1000);
-			}
-			set_cyc2ns_scale(cpu_khz);
-			return 0;
-		}
-	}
-	return -ENODEV;
-}
-
-static int tsc_resume(void)
-{
-	write_seqlock(&monotonic_lock);
-	/* Assume this is the last mark offset time */
-	rdtsc(last_tsc_low, last_tsc_high);
-#ifdef CONFIG_HPET_TIMER
-	if (is_hpet_enabled() && hpet_use_timer)
-		hpet_last = hpet_readl(HPET_COUNTER);
-#endif
-	write_sequnlock(&monotonic_lock);
-	return 0;
-}
-
-#ifndef CONFIG_X86_TSC
-/* disable flag for tsc.  Takes effect by clearing the TSC cpu flag
- * in cpu/common.c */
-static int __init tsc_setup(char *str)
-{
-	tsc_disable = 1;
-	return 1;
-}
-#else
-static int __init tsc_setup(char *str)
-{
-	printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
-				"cannot disable TSC.\n");
-	return 1;
-}
-#endif
-__setup("notsc", tsc_setup);
-
-
-
-/************************************************************/
-
-/* tsc timer_opts struct */
-static struct timer_opts timer_tsc = {
-	.name = "tsc",
-	.mark_offset = mark_offset_tsc, 
-	.get_offset = get_offset_tsc,
-	.monotonic_clock = monotonic_clock_tsc,
-	.delay = delay_tsc,
-	.read_timer = read_timer_tsc,
-	.resume	= tsc_resume,
-};
-
-struct init_timer_opts __initdata timer_tsc_init = {
-	.init = init_tsc,
-	.opts = &timer_tsc,
-};
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index dcc1447..7846409 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -28,6 +28,7 @@
 #include <linux/utsname.h>
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
+#include <linux/unwind.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -47,7 +48,7 @@
 #include <asm/desc.h>
 #include <asm/i387.h>
 #include <asm/nmi.h>
-
+#include <asm/unwind.h>
 #include <asm/smp.h>
 #include <asm/arch_hooks.h>
 #include <asm/kdebug.h>
@@ -92,6 +93,7 @@
 asmlinkage void machine_check(void);
 
 static int kstack_depth_to_print = 24;
+static int call_trace = 1;
 ATOMIC_NOTIFIER_HEAD(i386die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
@@ -170,7 +172,23 @@
 	return ebp;
 }
 
-static void show_trace_log_lvl(struct task_struct *task,
+static asmlinkage int show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
+{
+	int n = 0;
+	int printed = 0; /* nr of entries already printed on current line */
+
+	while (unwind(info) == 0 && UNW_PC(info)) {
+		++n;
+		printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed);
+		if (arch_unw_user_mode(info))
+			break;
+	}
+	if (printed)
+		printk("\n");
+	return n;
+}
+
+static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
 			       unsigned long *stack, char *log_lvl)
 {
 	unsigned long ebp;
@@ -178,6 +196,26 @@
 	if (!task)
 		task = current;
 
+	if (call_trace >= 0) {
+		int unw_ret = 0;
+		struct unwind_frame_info info;
+
+		if (regs) {
+			if (unwind_init_frame_info(&info, task, regs) == 0)
+				unw_ret = show_trace_unwind(&info, log_lvl);
+		} else if (task == current)
+			unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl);
+		else {
+			if (unwind_init_blocked(&info, task) == 0)
+				unw_ret = show_trace_unwind(&info, log_lvl);
+		}
+		if (unw_ret > 0) {
+			if (call_trace > 0)
+				return;
+			printk("%sLegacy call trace:\n", log_lvl);
+		}
+	}
+
 	if (task == current) {
 		/* Grab ebp right from our regs */
 		asm ("movl %%ebp, %0" : "=r" (ebp) : );
@@ -198,13 +236,13 @@
 	}
 }
 
-void show_trace(struct task_struct *task, unsigned long * stack)
+void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long * stack)
 {
-	show_trace_log_lvl(task, stack, "");
+	show_trace_log_lvl(task, regs, stack, "");
 }
 
-static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp,
-			       char *log_lvl)
+static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+			       unsigned long *esp, char *log_lvl)
 {
 	unsigned long *stack;
 	int i;
@@ -225,13 +263,13 @@
 		printk("%08lx ", *stack++);
 	}
 	printk("\n%sCall Trace:\n", log_lvl);
-	show_trace_log_lvl(task, esp, log_lvl);
+	show_trace_log_lvl(task, regs, esp, log_lvl);
 }
 
 void show_stack(struct task_struct *task, unsigned long *esp)
 {
 	printk("       ");
-	show_stack_log_lvl(task, esp, "");
+	show_stack_log_lvl(task, NULL, esp, "");
 }
 
 /*
@@ -241,7 +279,7 @@
 {
 	unsigned long stack;
 
-	show_trace(current, &stack);
+	show_trace(current, NULL, &stack);
 }
 
 EXPORT_SYMBOL(dump_stack);
@@ -285,7 +323,7 @@
 		u8 __user *eip;
 
 		printk("\n" KERN_EMERG "Stack: ");
-		show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG);
+		show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG);
 
 		printk(KERN_EMERG "Code: ");
 
@@ -1215,3 +1253,15 @@
 	return 1;
 }
 __setup("kstack=", kstack_setup);
+
+static int __init call_trace_setup(char *s)
+{
+	if (strcmp(s, "old") == 0)
+		call_trace = -1;
+	else if (strcmp(s, "both") == 0)
+		call_trace = 0;
+	else if (strcmp(s, "new") == 0)
+		call_trace = 1;
+	return 1;
+}
+__setup("call_trace=", call_trace_setup);
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
new file mode 100644
index 0000000..7e0d8da
--- /dev/null
+++ b/arch/i386/kernel/tsc.c
@@ -0,0 +1,478 @@
+/*
+ * This code largely moved from arch/i386/kernel/timer/timer_tsc.c
+ * which was originally moved from arch/i386/kernel/time.c.
+ * See comments there for proper credits.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/workqueue.h>
+#include <linux/cpufreq.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+
+#include <asm/delay.h>
+#include <asm/tsc.h>
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#include "mach_timer.h"
+
+/*
+ * On some systems the TSC frequency does not
+ * change with the cpu frequency. So we need
+ * an extra value to store the TSC freq
+ */
+unsigned int tsc_khz;
+
+int tsc_disable __cpuinitdata = 0;
+
+#ifdef CONFIG_X86_TSC
+static int __init tsc_setup(char *str)
+{
+	printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
+				"cannot disable TSC.\n");
+	return 1;
+}
+#else
+/*
+ * disable flag for tsc. Takes effect by clearing the TSC cpu flag
+ * in cpu/common.c
+ */
+static int __init tsc_setup(char *str)
+{
+	tsc_disable = 1;
+
+	return 1;
+}
+#endif
+
+__setup("notsc", tsc_setup);
+
+/*
+ * code to mark and check if the TSC is unstable
+ * due to cpufreq or due to unsynced TSCs
+ */
+static int tsc_unstable;
+
+static inline int check_tsc_unstable(void)
+{
+	return tsc_unstable;
+}
+
+void mark_tsc_unstable(void)
+{
+	tsc_unstable = 1;
+}
+EXPORT_SYMBOL_GPL(mark_tsc_unstable);
+
+/* Accellerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ *  basic equation:
+ *		ns = cycles / (freq / ns_per_sec)
+ *		ns = cycles * (ns_per_sec / freq)
+ *		ns = cycles * (10^9 / (cpu_khz * 10^3))
+ *		ns = cycles * (10^6 / cpu_khz)
+ *
+ *	Then we use scaling math (suggested by george@mvista.com) to get:
+ *		ns = cycles * (10^6 * SC / cpu_khz) / SC
+ *		ns = cycles * cyc2ns_scale / SC
+ *
+ *	And since SC is a constant power of two, we can convert the div
+ *  into a shift.
+ *
+ *  We can use khz divisor instead of mhz to keep a better percision, since
+ *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ *  (mathieu.desnoyers@polymtl.ca)
+ *
+ *			-johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+static unsigned long cyc2ns_scale __read_mostly;
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline void set_cyc2ns_scale(unsigned long cpu_khz)
+{
+	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
+}
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	unsigned long long this_offset;
+
+	/*
+	 * in the NUMA case we dont use the TSC as they are not
+	 * synchronized across all CPUs.
+	 */
+#ifndef CONFIG_NUMA
+	if (!cpu_khz || check_tsc_unstable())
+#endif
+		/* no locking but a rare wrong value is not a big deal */
+		return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
+
+	/* read the Time Stamp Counter: */
+	rdtscll(this_offset);
+
+	/* return the value in ns */
+	return cycles_2_ns(this_offset);
+}
+
+static unsigned long calculate_cpu_khz(void)
+{
+	unsigned long long start, end;
+	unsigned long count;
+	u64 delta64;
+	int i;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/* run 3 times to ensure the cache is warm */
+	for (i = 0; i < 3; i++) {
+		mach_prepare_counter();
+		rdtscll(start);
+		mach_countup(&count);
+		rdtscll(end);
+	}
+	/*
+	 * Error: ECTCNEVERSET
+	 * The CTC wasn't reliable: we got a hit on the very first read,
+	 * or the CPU was so fast/slow that the quotient wouldn't fit in
+	 * 32 bits..
+	 */
+	if (count <= 1)
+		goto err;
+
+	delta64 = end - start;
+
+	/* cpu freq too fast: */
+	if (delta64 > (1ULL<<32))
+		goto err;
+
+	/* cpu freq too slow: */
+	if (delta64 <= CALIBRATE_TIME_MSEC)
+		goto err;
+
+	delta64 += CALIBRATE_TIME_MSEC/2; /* round for do_div */
+	do_div(delta64,CALIBRATE_TIME_MSEC);
+
+	local_irq_restore(flags);
+	return (unsigned long)delta64;
+err:
+	local_irq_restore(flags);
+	return 0;
+}
+
+int recalibrate_cpu_khz(void)
+{
+#ifndef CONFIG_SMP
+	unsigned long cpu_khz_old = cpu_khz;
+
+	if (cpu_has_tsc) {
+		cpu_khz = calculate_cpu_khz();
+		tsc_khz = cpu_khz;
+		cpu_data[0].loops_per_jiffy =
+			cpufreq_scale(cpu_data[0].loops_per_jiffy,
+					cpu_khz_old, cpu_khz);
+		return 0;
+	} else
+		return -ENODEV;
+#else
+	return -ENODEV;
+#endif
+}
+
+EXPORT_SYMBOL(recalibrate_cpu_khz);
+
+void tsc_init(void)
+{
+	if (!cpu_has_tsc || tsc_disable)
+		return;
+
+	cpu_khz = calculate_cpu_khz();
+	tsc_khz = cpu_khz;
+
+	if (!cpu_khz)
+		return;
+
+	printk("Detected %lu.%03lu MHz processor.\n",
+				(unsigned long)cpu_khz / 1000,
+				(unsigned long)cpu_khz % 1000);
+
+	set_cyc2ns_scale(cpu_khz);
+	use_tsc_delay();
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+static unsigned int cpufreq_delayed_issched = 0;
+static unsigned int cpufreq_init = 0;
+static struct work_struct cpufreq_delayed_get_work;
+
+static void handle_cpufreq_delayed_get(void *v)
+{
+	unsigned int cpu;
+
+	for_each_online_cpu(cpu)
+		cpufreq_get(cpu);
+
+	cpufreq_delayed_issched = 0;
+}
+
+/*
+ * if we notice cpufreq oddness, schedule a call to cpufreq_get() as it tries
+ * to verify the CPU frequency the timing core thinks the CPU is running
+ * at is still correct.
+ */
+static inline void cpufreq_delayed_get(void)
+{
+	if (cpufreq_init && !cpufreq_delayed_issched) {
+		cpufreq_delayed_issched = 1;
+		printk(KERN_DEBUG "Checking if CPU frequency changed.\n");
+		schedule_work(&cpufreq_delayed_get_work);
+	}
+}
+
+/*
+ * if the CPU frequency is scaled, TSC-based delays will need a different
+ * loops_per_jiffy value to function properly.
+ */
+static unsigned int ref_freq = 0;
+static unsigned long loops_per_jiffy_ref = 0;
+static unsigned long cpu_khz_ref = 0;
+
+static int
+time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct cpufreq_freqs *freq = data;
+
+	if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
+		write_seqlock_irq(&xtime_lock);
+
+	if (!ref_freq) {
+		if (!freq->old){
+			ref_freq = freq->new;
+			goto end;
+		}
+		ref_freq = freq->old;
+		loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
+		cpu_khz_ref = cpu_khz;
+	}
+
+	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE)) {
+		if (!(freq->flags & CPUFREQ_CONST_LOOPS))
+			cpu_data[freq->cpu].loops_per_jiffy =
+				cpufreq_scale(loops_per_jiffy_ref,
+						ref_freq, freq->new);
+
+		if (cpu_khz) {
+
+			if (num_online_cpus() == 1)
+				cpu_khz = cpufreq_scale(cpu_khz_ref,
+						ref_freq, freq->new);
+			if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
+				tsc_khz = cpu_khz;
+				set_cyc2ns_scale(cpu_khz);
+				/*
+				 * TSC based sched_clock turns
+				 * to junk w/ cpufreq
+				 */
+				mark_tsc_unstable();
+			}
+		}
+	}
+end:
+	if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
+		write_sequnlock_irq(&xtime_lock);
+
+	return 0;
+}
+
+static struct notifier_block time_cpufreq_notifier_block = {
+	.notifier_call	= time_cpufreq_notifier
+};
+
+static int __init cpufreq_tsc(void)
+{
+	int ret;
+
+	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
+	ret = cpufreq_register_notifier(&time_cpufreq_notifier_block,
+					CPUFREQ_TRANSITION_NOTIFIER);
+	if (!ret)
+		cpufreq_init = 1;
+
+	return ret;
+}
+
+core_initcall(cpufreq_tsc);
+
+#endif
+
+/* clock source code */
+
+static unsigned long current_tsc_khz = 0;
+static int tsc_update_callback(void);
+
+static cycle_t read_tsc(void)
+{
+	cycle_t ret;
+
+	rdtscll(ret);
+
+	return ret;
+}
+
+static struct clocksource clocksource_tsc = {
+	.name			= "tsc",
+	.rating			= 300,
+	.read			= read_tsc,
+	.mask			= CLOCKSOURCE_MASK(64),
+	.mult			= 0, /* to be set */
+	.shift			= 22,
+	.update_callback	= tsc_update_callback,
+	.is_continuous		= 1,
+};
+
+static int tsc_update_callback(void)
+{
+	int change = 0;
+
+	/* check to see if we should switch to the safe clocksource: */
+	if (clocksource_tsc.rating != 50 && check_tsc_unstable()) {
+		clocksource_tsc.rating = 50;
+		clocksource_reselect();
+		change = 1;
+	}
+
+	/* only update if tsc_khz has changed: */
+	if (current_tsc_khz != tsc_khz) {
+		current_tsc_khz = tsc_khz;
+		clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
+							clocksource_tsc.shift);
+		change = 1;
+	}
+
+	return change;
+}
+
+static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d)
+{
+	printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
+		       d->ident);
+	mark_tsc_unstable();
+	return 0;
+}
+
+/* List of systems that have known TSC problems */
+static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
+	{
+	 .callback = dmi_mark_tsc_unstable,
+	 .ident = "IBM Thinkpad 380XD",
+	 .matches = {
+		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+		     DMI_MATCH(DMI_BOARD_NAME, "2635FA0"),
+		     },
+	 },
+	 {}
+};
+
+#define TSC_FREQ_CHECK_INTERVAL (10*MSEC_PER_SEC) /* 10sec in MS */
+static struct timer_list verify_tsc_freq_timer;
+
+/* XXX - Probably should add locking */
+static void verify_tsc_freq(unsigned long unused)
+{
+	static u64 last_tsc;
+	static unsigned long last_jiffies;
+
+	u64 now_tsc, interval_tsc;
+	unsigned long now_jiffies, interval_jiffies;
+
+
+	if (check_tsc_unstable())
+		return;
+
+	rdtscll(now_tsc);
+	now_jiffies = jiffies;
+
+	if (!last_jiffies) {
+		goto out;
+	}
+
+	interval_jiffies = now_jiffies - last_jiffies;
+	interval_tsc = now_tsc - last_tsc;
+	interval_tsc *= HZ;
+	do_div(interval_tsc, cpu_khz*1000);
+
+	if (interval_tsc < (interval_jiffies * 3 / 4)) {
+		printk("TSC appears to be running slowly. "
+			"Marking it as unstable\n");
+		mark_tsc_unstable();
+		return;
+	}
+
+out:
+	last_tsc = now_tsc;
+	last_jiffies = now_jiffies;
+	/* set us up to go off on the next interval: */
+	mod_timer(&verify_tsc_freq_timer,
+		jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL));
+}
+
+/*
+ * Make an educated guess if the TSC is trustworthy and synchronized
+ * over all CPUs.
+ */
+static __init int unsynchronized_tsc(void)
+{
+	/*
+	 * Intel systems are normally all synchronized.
+	 * Exceptions must mark TSC as unstable:
+	 */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ 		return 0;
+
+	/* assume multi socket systems are not synchronized: */
+ 	return num_possible_cpus() > 1;
+}
+
+static int __init init_tsc_clocksource(void)
+{
+
+	if (cpu_has_tsc && tsc_khz && !tsc_disable) {
+		/* check blacklist */
+		dmi_check_system(bad_tsc_dmi_table);
+
+		if (unsynchronized_tsc()) /* mark unstable if unsynced */
+			mark_tsc_unstable();
+		current_tsc_khz = tsc_khz;
+		clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
+							clocksource_tsc.shift);
+		/* lower the rating if we already know its unstable: */
+		if (check_tsc_unstable())
+			clocksource_tsc.rating = 50;
+
+		init_timer(&verify_tsc_freq_timer);
+		verify_tsc_freq_timer.function = verify_tsc_freq;
+		verify_tsc_freq_timer.expires =
+			jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL);
+		add_timer(&verify_tsc_freq_timer);
+
+		return clocksource_register(&clocksource_tsc);
+	}
+
+	return 0;
+}
+
+module_init(init_tsc_clocksource);
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 7512f39..2d4f138 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -71,6 +71,15 @@
   .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
   _edata = .;			/* End of data section */
 
+#ifdef CONFIG_STACK_UNWIND
+  . = ALIGN(4);
+  .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) {
+	__start_unwind = .;
+  	*(.eh_frame)
+	__end_unwind = .;
+  }
+#endif
+
   . = ALIGN(THREAD_SIZE);	/* init_task */
   .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
 	*(.data.init_task)
diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c
index c49a6ac..3c0714c 100644
--- a/arch/i386/lib/delay.c
+++ b/arch/i386/lib/delay.c
@@ -10,43 +10,92 @@
  *	we have to worry about.
  */
 
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
-#include <linux/module.h>
+
 #include <asm/processor.h>
 #include <asm/delay.h>
 #include <asm/timer.h>
 
 #ifdef CONFIG_SMP
-#include <asm/smp.h>
+# include <asm/smp.h>
 #endif
 
-extern struct timer_opts* timer;
+/* simple loop based delay: */
+static void delay_loop(unsigned long loops)
+{
+	int d0;
+
+	__asm__ __volatile__(
+		"\tjmp 1f\n"
+		".align 16\n"
+		"1:\tjmp 2f\n"
+		".align 16\n"
+		"2:\tdecl %0\n\tjns 2b"
+		:"=&a" (d0)
+		:"0" (loops));
+}
+
+/* TSC based delay: */
+static void delay_tsc(unsigned long loops)
+{
+	unsigned long bclock, now;
+
+	rdtscl(bclock);
+	do {
+		rep_nop();
+		rdtscl(now);
+	} while ((now-bclock) < loops);
+}
+
+/*
+ * Since we calibrate only once at boot, this
+ * function should be set once at boot and not changed
+ */
+static void (*delay_fn)(unsigned long) = delay_loop;
+
+void use_tsc_delay(void)
+{
+	delay_fn = delay_tsc;
+}
+
+int read_current_timer(unsigned long *timer_val)
+{
+	if (delay_fn == delay_tsc) {
+		rdtscl(*timer_val);
+		return 0;
+	}
+	return -1;
+}
 
 void __delay(unsigned long loops)
 {
-	cur_timer->delay(loops);
+	delay_fn(loops);
 }
 
 inline void __const_udelay(unsigned long xloops)
 {
 	int d0;
+
 	xloops *= 4;
 	__asm__("mull %0"
 		:"=d" (xloops), "=&a" (d0)
-		:"1" (xloops),"0" (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (HZ/4)));
-        __delay(++xloops);
+		:"1" (xloops), "0"
+		(cpu_data[raw_smp_processor_id()].loops_per_jiffy * (HZ/4)));
+
+	__delay(++xloops);
 }
 
 void __udelay(unsigned long usecs)
 {
-	__const_udelay(usecs * 0x000010c7);  /* 2**32 / 1000000 (rounded up) */
+	__const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
 }
 
 void __ndelay(unsigned long nsecs)
 {
-	__const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+	__const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
 }
 
 EXPORT_SYMBOL(__delay);
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index 6979297..c5aa65f 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -528,6 +528,97 @@
 	return size;
 }
 
+static unsigned long __copy_user_intel_nocache(void *to,
+				const void __user *from, unsigned long size)
+{
+        int d0, d1;
+
+	__asm__ __volatile__(
+	       "        .align 2,0x90\n"
+	       "0:      movl 32(%4), %%eax\n"
+	       "        cmpl $67, %0\n"
+	       "        jbe 2f\n"
+	       "1:      movl 64(%4), %%eax\n"
+	       "        .align 2,0x90\n"
+	       "2:      movl 0(%4), %%eax\n"
+	       "21:     movl 4(%4), %%edx\n"
+	       "        movnti %%eax, 0(%3)\n"
+	       "        movnti %%edx, 4(%3)\n"
+	       "3:      movl 8(%4), %%eax\n"
+	       "31:     movl 12(%4),%%edx\n"
+	       "        movnti %%eax, 8(%3)\n"
+	       "        movnti %%edx, 12(%3)\n"
+	       "4:      movl 16(%4), %%eax\n"
+	       "41:     movl 20(%4), %%edx\n"
+	       "        movnti %%eax, 16(%3)\n"
+	       "        movnti %%edx, 20(%3)\n"
+	       "10:     movl 24(%4), %%eax\n"
+	       "51:     movl 28(%4), %%edx\n"
+	       "        movnti %%eax, 24(%3)\n"
+	       "        movnti %%edx, 28(%3)\n"
+	       "11:     movl 32(%4), %%eax\n"
+	       "61:     movl 36(%4), %%edx\n"
+	       "        movnti %%eax, 32(%3)\n"
+	       "        movnti %%edx, 36(%3)\n"
+	       "12:     movl 40(%4), %%eax\n"
+	       "71:     movl 44(%4), %%edx\n"
+	       "        movnti %%eax, 40(%3)\n"
+	       "        movnti %%edx, 44(%3)\n"
+	       "13:     movl 48(%4), %%eax\n"
+	       "81:     movl 52(%4), %%edx\n"
+	       "        movnti %%eax, 48(%3)\n"
+	       "        movnti %%edx, 52(%3)\n"
+	       "14:     movl 56(%4), %%eax\n"
+	       "91:     movl 60(%4), %%edx\n"
+	       "        movnti %%eax, 56(%3)\n"
+	       "        movnti %%edx, 60(%3)\n"
+	       "        addl $-64, %0\n"
+	       "        addl $64, %4\n"
+	       "        addl $64, %3\n"
+	       "        cmpl $63, %0\n"
+	       "        ja  0b\n"
+	       "        sfence \n"
+	       "5:      movl  %0, %%eax\n"
+	       "        shrl  $2, %0\n"
+	       "        andl $3, %%eax\n"
+	       "        cld\n"
+	       "6:      rep; movsl\n"
+	       "        movl %%eax,%0\n"
+	       "7:      rep; movsb\n"
+	       "8:\n"
+	       ".section .fixup,\"ax\"\n"
+	       "9:      lea 0(%%eax,%0,4),%0\n"
+	       "16:     jmp 8b\n"
+	       ".previous\n"
+	       ".section __ex_table,\"a\"\n"
+	       "	.align 4\n"
+	       "	.long 0b,16b\n"
+	       "	.long 1b,16b\n"
+	       "	.long 2b,16b\n"
+	       "	.long 21b,16b\n"
+	       "	.long 3b,16b\n"
+	       "	.long 31b,16b\n"
+	       "	.long 4b,16b\n"
+	       "	.long 41b,16b\n"
+	       "	.long 10b,16b\n"
+	       "	.long 51b,16b\n"
+	       "	.long 11b,16b\n"
+	       "	.long 61b,16b\n"
+	       "	.long 12b,16b\n"
+	       "	.long 71b,16b\n"
+	       "	.long 13b,16b\n"
+	       "	.long 81b,16b\n"
+	       "	.long 14b,16b\n"
+	       "	.long 91b,16b\n"
+	       "	.long 6b,9b\n"
+	       "        .long 7b,16b\n"
+	       ".previous"
+	       : "=&c"(size), "=&D" (d0), "=&S" (d1)
+	       :  "1"(to), "2"(from), "0"(size)
+	       : "eax", "edx", "memory");
+	return size;
+}
+
 #else
 
 /*
@@ -694,6 +785,19 @@
 }
 EXPORT_SYMBOL(__copy_from_user_ll);
 
+unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
+					 unsigned long n)
+{
+	BUG_ON((long)n < 0);
+	if (movsl_is_ok(to, from, n))
+		__copy_user(to, from, n);
+	else
+		n = __copy_user_intel((void __user *)to,
+				      (const void *)from, n);
+	return n;
+}
+EXPORT_SYMBOL(__copy_from_user_ll_nozero);
+
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 					unsigned long n)
 {
@@ -709,6 +813,21 @@
 	return n;
 }
 
+unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
+					unsigned long n)
+{
+	BUG_ON((long)n < 0);
+#ifdef CONFIG_X86_INTEL_USERCOPY
+	if ( n > 64 && cpu_has_xmm2)
+                n = __copy_user_intel_nocache(to, from, n);
+	else
+		__copy_user(to, from, n);
+#else
+        __copy_user(to, from, n);
+#endif
+	return n;
+}
+
 /**
  * copy_to_user: - Copy a block of data into user space.
  * @to:   Destination address, in user space.
diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
index b4a7455..004837c 100644
--- a/arch/i386/mach-default/setup.c
+++ b/arch/i386/mach-default/setup.c
@@ -8,6 +8,8 @@
 #include <linux/interrupt.h>
 #include <asm/acpi.h>
 #include <asm/arch_hooks.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
 #define DEFAULT_SEND_IPI	(1)
@@ -130,3 +132,44 @@
 }
 
 late_initcall(print_ipi_mode);
+
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ *
+ * Description:
+ *	This is included late in kernel/setup.c so that it can make
+ *	use of all of the static functions.
+ **/
+
+char * __init machine_specific_memory_setup(void)
+{
+	char *who;
+
+
+	who = "BIOS-e820";
+
+	/*
+	 * Try to copy the BIOS-supplied E820-map.
+	 *
+	 * Otherwise fake a memory map; one section from 0k->640k,
+	 * the next section from 1mb->appropriate_mem_k
+	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+		unsigned long mem_size;
+
+		/* compare results from other methods and take the greater */
+		if (ALT_MEM_K < EXT_MEM_K) {
+			mem_size = EXT_MEM_K;
+			who = "BIOS-88";
+		} else {
+			mem_size = ALT_MEM_K;
+			who = "BIOS-e801";
+		}
+
+		e820.nr_map = 0;
+		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+  	}
+	return who;
+}
diff --git a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c
index 07fac7e..8a9e1a6 100644
--- a/arch/i386/mach-visws/setup.c
+++ b/arch/i386/mach-visws/setup.c
@@ -10,6 +10,8 @@
 #include <asm/fixmap.h>
 #include <asm/arch_hooks.h>
 #include <asm/io.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
 #include "cobalt.h"
 #include "piix4.h"
 
@@ -133,3 +135,50 @@
 	/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
 	setup_irq(0, &irq0);
 }
+
+/* Hook for machine specific memory setup. */
+
+#define MB (1024 * 1024)
+
+static unsigned long sgivwfb_mem_phys;
+static unsigned long sgivwfb_mem_size;
+
+long long mem_size __initdata = 0;
+
+char * __init machine_specific_memory_setup(void)
+{
+	long long gfx_mem_size = 8 * MB;
+
+	mem_size = ALT_MEM_K;
+
+	if (!mem_size) {
+		printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
+		mem_size = 128 * MB;
+	}
+
+	/*
+	 * this hardcodes the graphics memory to 8 MB
+	 * it really should be sized dynamically (or at least
+	 * set as a boot param)
+	 */
+	if (!sgivwfb_mem_size) {
+		printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
+		sgivwfb_mem_size = 8 * MB;
+	}
+
+	/*
+	 * Trim to nearest MB
+	 */
+	sgivwfb_mem_size &= ~((1 << 20) - 1);
+	sgivwfb_mem_phys = mem_size - gfx_mem_size;
+
+	add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+	add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
+	add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
+
+	return "PROM";
+
+	/* Remove gcc warnings */
+	(void) sanitize_e820_map(NULL, NULL);
+	(void) copy_e820_map(NULL, 0);
+}
diff --git a/arch/i386/mach-voyager/setup.c b/arch/i386/mach-voyager/setup.c
index 7d8a3ac..0e22505 100644
--- a/arch/i386/mach-voyager/setup.c
+++ b/arch/i386/mach-voyager/setup.c
@@ -7,6 +7,9 @@
 #include <linux/interrupt.h>
 #include <asm/acpi.h>
 #include <asm/arch_hooks.h>
+#include <asm/voyager.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
 
 void __init pre_intr_init_hook(void)
 {
@@ -45,3 +48,74 @@
 {
 	setup_irq(0, &irq0);
 }
+
+/* Hook for machine specific memory setup. */
+
+char * __init machine_specific_memory_setup(void)
+{
+	char *who;
+
+	who = "NOT VOYAGER";
+
+	if(voyager_level == 5) {
+		__u32 addr, length;
+		int i;
+
+		who = "Voyager-SUS";
+
+		e820.nr_map = 0;
+		for(i=0; voyager_memory_detect(i, &addr, &length); i++) {
+			add_memory_region(addr, length, E820_RAM);
+		}
+		return who;
+	} else if(voyager_level == 4) {
+		__u32 tom;
+		__u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8;
+		/* select the DINO config space */
+		outb(VOYAGER_DINO, VOYAGER_CAT_CONFIG_PORT);
+		/* Read DINO top of memory register */
+		tom = ((inb(catbase + 0x4) & 0xf0) << 16)
+			+ ((inb(catbase + 0x5) & 0x7f) << 24);
+
+		if(inb(catbase) != VOYAGER_DINO) {
+			printk(KERN_ERR "Voyager: Failed to get DINO for L4, setting tom to EXT_MEM_K\n");
+			tom = (EXT_MEM_K)<<10;
+		}
+		who = "Voyager-TOM";
+		add_memory_region(0, 0x9f000, E820_RAM);
+		/* map from 1M to top of memory */
+		add_memory_region(1*1024*1024, tom - 1*1024*1024, E820_RAM);
+		/* FIXME: Should check the ASICs to see if I need to
+		 * take out the 8M window.  Just do it at the moment
+		 * */
+		add_memory_region(8*1024*1024, 8*1024*1024, E820_RESERVED);
+		return who;
+	}
+
+	who = "BIOS-e820";
+
+	/*
+	 * Try to copy the BIOS-supplied E820-map.
+	 *
+	 * Otherwise fake a memory map; one section from 0k->640k,
+	 * the next section from 1mb->appropriate_mem_k
+	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+		unsigned long mem_size;
+
+		/* compare results from other methods and take the greater */
+		if (ALT_MEM_K < EXT_MEM_K) {
+			mem_size = EXT_MEM_K;
+			who = "BIOS-88";
+		} else {
+			mem_size = ALT_MEM_K;
+			who = "BIOS-e801";
+		}
+
+		e820.nr_map = 0;
+		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+  	}
+	return who;
+}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index bd6fe96..6ee7faa 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -30,6 +30,40 @@
 
 extern void die(const char *,struct pt_regs *,long);
 
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+	vmalloc_sync_all();
+	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	struct die_args args = {
+		.regs = regs,
+		.str = str,
+		.err = err,
+		.trapnr = trap,
+		.signr = sig
+	};
+	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	return NOTIFY_DONE;
+}
+#endif
+
+
 /*
  * Unlock any spinlocks which will prevent us from getting the
  * message out 
@@ -324,7 +358,7 @@
 	if (unlikely(address >= TASK_SIZE)) {
 		if (!(error_code & 0x0000000d) && vmalloc_fault(address) >= 0)
 			return;
-		if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
+		if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 						SIGSEGV) == NOTIFY_STOP)
 			return;
 		/*
@@ -334,7 +368,7 @@
 		goto bad_area_nosemaphore;
 	}
 
-	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
+	if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 					SIGSEGV) == NOTIFY_STOP)
 		return;
 
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index ec0fd3c..fa8a37b 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -281,9 +281,9 @@
 
 	for (i = 0; i < model->num_counters; ++i) {
 		struct dentry * dir;
-		char buf[2];
+		char buf[4];
  
-		snprintf(buf, 2, "%d", i);
+		snprintf(buf,  sizeof(buf), "%d", i);
 		dir = oprofilefs_mkdir(sb, root, buf);
 		oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); 
 		oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); 
diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c
index 3ad9a72..693bdea 100644
--- a/arch/i386/oprofile/op_model_athlon.c
+++ b/arch/i386/oprofile/op_model_athlon.c
@@ -13,6 +13,7 @@
 #include <linux/oprofile.h>
 #include <asm/ptrace.h>
 #include <asm/msr.h>
+#include <asm/nmi.h>
  
 #include "op_x86_model.h"
 #include "op_counter.h"
diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c
index ac8a066..7c61d35 100644
--- a/arch/i386/oprofile/op_model_p4.c
+++ b/arch/i386/oprofile/op_model_p4.c
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/fixmap.h>
 #include <asm/apic.h>
+#include <asm/nmi.h>
 
 #include "op_x86_model.h"
 #include "op_counter.h"
diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
index d719015..5c3ab4b 100644
--- a/arch/i386/oprofile/op_model_ppro.c
+++ b/arch/i386/oprofile/op_model_ppro.c
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/msr.h>
 #include <asm/apic.h>
+#include <asm/nmi.h>
  
 #include "op_x86_model.h"
 #include "op_counter.h"
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index 7852827..a151f7a 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -285,8 +285,6 @@
 	/* Leave vm_pgoff as-is, the PCI space address is the physical
 	 * address on this platform.
 	 */
-	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
 	prot = pgprot_val(vma->vm_page_prot);
 	if (boot_cpu_data.x86 > 3)
 		prot |= _PAGE_PCD | _PAGE_PWT;
diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c
index 1eec086..ed1512a 100644
--- a/arch/i386/pci/pcbios.c
+++ b/arch/i386/pci/pcbios.c
@@ -371,8 +371,7 @@
 			list_for_each(ln, &pci_devices) {
 				d = pci_dev_g(ln);
 				if (d->bus->number == bus && d->devfn == devfn) {
-					list_del(&d->global_list);
-					list_add_tail(&d->global_list, &sorted_devices);
+					list_move_tail(&d->global_list, &sorted_devices);
 					if (d == dev)
 						found = 1;
 					break;
@@ -390,8 +389,7 @@
 		if (!found) {
 			printk(KERN_WARNING "PCI: Device %s not found by BIOS\n",
 				pci_name(dev));
-			list_del(&dev->global_list);
-			list_add_tail(&dev->global_list, &sorted_devices);
+			list_move_tail(&dev->global_list, &sorted_devices);
 		}
 	}
 	list_splice(&sorted_devices, &pci_devices);
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 355d579..b045c27 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -272,9 +272,9 @@
 	/* endless idle loop with no priority at all */
 	while (1) {
 		if (can_do_pal_halt)
-			clear_thread_flag(TIF_POLLING_NRFLAG);
+			current_thread_info()->status &= ~TS_POLLING;
 		else
-			set_thread_flag(TIF_POLLING_NRFLAG);
+			current_thread_info()->status |= TS_POLLING;
 
 		if (!need_resched()) {
 			void (*idle)(void);
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 4f3a16b..879edb5 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -166,7 +166,7 @@
 
 	num_shared = (int) csi.num_shared;
 	do {
-		for_each_cpu(j)
+		for_each_possible_cpu(j)
 			if (cpu_data(cpu)->socket_id == cpu_data(j)->socket_id
 				&& cpu_data(j)->core_id == csi.log1_cid
 				&& cpu_data(j)->thread_id == csi.log1_tid)
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index d98ec49..14ef7cc 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -19,6 +19,40 @@
 
 extern void die (char *, struct pt_regs *, long);
 
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+/* Hook to register for page fault notifications */
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	struct die_args args = {
+		.regs = regs,
+		.str = str,
+		.err = err,
+		.trapnr = trap,
+		.signr = sig
+	};
+	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	return NOTIFY_DONE;
+}
+#endif
+
 /*
  * Return TRUE if ADDRESS points at a page in the kernel's mapped segment
  * (inside region 5, on ia64) and that page is present.
@@ -84,7 +118,7 @@
 	/*
 	 * This is to handle the kprobes on user space access instructions
 	 */
-	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, code, TRAP_BRKPT,
+	if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, code, TRAP_BRKPT,
 					SIGSEGV) == NOTIFY_STOP)
 		return;
 
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 61dd860..77375a5 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -602,8 +602,6 @@
 	 * Leave vm_pgoff as-is, the PCI space address is the physical
 	 * address on this platform.
 	 */
-	vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
-
 	if (write_combine && efi_range_is_wc(vma->vm_start,
 					     vma->vm_end - vma->vm_start))
 		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
@@ -666,7 +664,6 @@
 
 	vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT;
 	vma->vm_page_prot = prot;
-	vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
 
 	if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
 			    size, vma->vm_page_prot))
diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c
index b7bd84c..8f2e058 100644
--- a/arch/m68k/amiga/amiga_ksyms.c
+++ b/arch/m68k/amiga/amiga_ksyms.c
@@ -23,8 +23,6 @@
 EXPORT_SYMBOL(amiga_chip_size);
 EXPORT_SYMBOL(amiga_audio_period);
 EXPORT_SYMBOL(amiga_audio_min_period);
-EXPORT_SYMBOL(amiga_do_irq);
-EXPORT_SYMBOL(amiga_do_irq_list);
 
 #ifdef CONFIG_AMIGA_PCMCIA
   EXPORT_SYMBOL(pcmcia_reset);
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index b0aa61b..f9403f4 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -35,60 +35,29 @@
  *           /Jes
  */
 
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/errno.h>
-#include <linux/seq_file.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/amipcmcia.h>
 
-extern int cia_request_irq(struct ciabase *base,int irq,
-                           irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                           unsigned long flags, const char *devname, void *dev_id);
-extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id);
-extern void cia_init_IRQ(struct ciabase *base);
-extern int cia_get_irq_list(struct ciabase *base, struct seq_file *p);
+static void amiga_enable_irq(unsigned int irq);
+static void amiga_disable_irq(unsigned int irq);
+static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp);
 
-/* irq node variables for amiga interrupt sources */
-static irq_node_t *ami_irq_list[AMI_STD_IRQS];
-
-static unsigned short amiga_intena_vals[AMI_STD_IRQS] = {
-	[IRQ_AMIGA_VERTB]	= IF_VERTB,
-	[IRQ_AMIGA_COPPER]	= IF_COPER,
-	[IRQ_AMIGA_AUD0]	= IF_AUD0,
-	[IRQ_AMIGA_AUD1]	= IF_AUD1,
-	[IRQ_AMIGA_AUD2]	= IF_AUD2,
-	[IRQ_AMIGA_AUD3]	= IF_AUD3,
-	[IRQ_AMIGA_BLIT]	= IF_BLIT,
-	[IRQ_AMIGA_DSKSYN]	= IF_DSKSYN,
-	[IRQ_AMIGA_DSKBLK]	= IF_DSKBLK,
-	[IRQ_AMIGA_RBF]		= IF_RBF,
-	[IRQ_AMIGA_TBE]		= IF_TBE,
-	[IRQ_AMIGA_SOFT]	= IF_SOFT,
-	[IRQ_AMIGA_PORTS]	= IF_PORTS,
-	[IRQ_AMIGA_EXTER]	= IF_EXTER
+static struct irq_controller amiga_irq_controller = {
+	.name		= "amiga",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.enable		= amiga_enable_irq,
+	.disable	= amiga_disable_irq,
 };
-static const unsigned char ami_servers[AMI_STD_IRQS] = {
-	[IRQ_AMIGA_VERTB]	= 1,
-	[IRQ_AMIGA_PORTS]	= 1,
-	[IRQ_AMIGA_EXTER]	= 1
-};
-
-static short ami_ablecount[AMI_IRQS];
-
-static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
-	num_spurious += 1;
-	return IRQ_NONE;
-}
 
 /*
  * void amiga_init_IRQ(void)
@@ -103,23 +72,12 @@
 
 void __init amiga_init_IRQ(void)
 {
-	int i;
+	request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL);
+	request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL);
+	request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL);
+	request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL);
 
-	/* initialize handlers */
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (ami_servers[i]) {
-			ami_irq_list[i] = NULL;
-		} else {
-			ami_irq_list[i] = new_irq_node();
-			ami_irq_list[i]->handler = ami_badint;
-			ami_irq_list[i]->flags   = 0;
-			ami_irq_list[i]->dev_id  = NULL;
-			ami_irq_list[i]->devname = NULL;
-			ami_irq_list[i]->next    = NULL;
-		}
-	}
-	for (i = 0; i < AMI_IRQS; i++)
-		ami_ablecount[i] = 0;
+	m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);
 
 	/* turn off PCMCIA interrupts */
 	if (AMIGAHW_PRESENT(PCMCIA))
@@ -134,249 +92,21 @@
 	cia_init_IRQ(&ciab_base);
 }
 
-static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-	unsigned long flags;
-	irq_node_t *cur;
-
-	if (!node->dev_id)
-		printk("%s: Warning: dev_id of %s is zero\n",
-		       __FUNCTION__, node->devname);
-
-	local_irq_save(flags);
-
-	cur = *list;
-
-	if (node->flags & SA_INTERRUPT) {
-		if (node->flags & SA_SHIRQ)
-			return -EBUSY;
-		/*
-		 * There should never be more than one
-		 */
-		while (cur && cur->flags & SA_INTERRUPT) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else {
-		while (cur) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	}
-
-	node->next = cur;
-	*list = node;
-
-	local_irq_restore(flags);
-	return 0;
-}
-
-static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
-{
-	unsigned long flags;
-	irq_node_t *node;
-
-	local_irq_save(flags);
-
-	for (node = *list; node; list = &node->next, node = *list) {
-		if (node->dev_id == dev_id) {
-			*list = node->next;
-			/* Mark it as free. */
-			node->handler = NULL;
-			local_irq_restore(flags);
-			return;
-		}
-	}
-	local_irq_restore(flags);
-	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * amiga_request_irq : add an interrupt service routine for a particular
- *                     machine specific interrupt source.
- *                     If the addition was successful, it returns 0.
- */
-
-int amiga_request_irq(unsigned int irq,
-		      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-	irq_node_t *node;
-	int error = 0;
-
-	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
-			irq, devname);
-		return -ENXIO;
-	}
-
-	if (irq >= IRQ_AMIGA_AUTO)
-		return cpu_request_irq(irq - IRQ_AMIGA_AUTO, handler,
-		                       flags, devname, dev_id);
-
-	if (irq >= IRQ_AMIGA_CIAB)
-		return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB,
-		                       handler, flags, devname, dev_id);
-
-	if (irq >= IRQ_AMIGA_CIAA)
-		return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
-		                       handler, flags, devname, dev_id);
-
-	/*
-	 * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
-	 * we could add a check here for the SA_SHIRQ flag but all drivers
-	 * should be aware of sharing anyway.
-	 */
-	if (ami_servers[irq]) {
-		if (!(node = new_irq_node()))
-			return -ENOMEM;
-		node->handler = handler;
-		node->flags   = flags;
-		node->dev_id  = dev_id;
-		node->devname = devname;
-		node->next    = NULL;
-		error = amiga_insert_irq(&ami_irq_list[irq], node);
-	} else {
-		ami_irq_list[irq]->handler = handler;
-		ami_irq_list[irq]->flags   = flags;
-		ami_irq_list[irq]->dev_id  = dev_id;
-		ami_irq_list[irq]->devname = devname;
-	}
-
-	/* enable the interrupt */
-	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
-		amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq];
-
-	return error;
-}
-
-void amiga_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq >= AMI_IRQS) {
-		printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_AUTO)
-		cpu_free_irq(irq - IRQ_AMIGA_AUTO, dev_id);
-
-	if (irq >= IRQ_AMIGA_CIAB) {
-		cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id);
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_CIAA) {
-		cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id);
-		return;
-	}
-
-	if (ami_servers[irq]) {
-		amiga_delete_irq(&ami_irq_list[irq], dev_id);
-		/* if server list empty, disable the interrupt */
-		if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS)
-			amiga_custom.intena = amiga_intena_vals[irq];
-	} else {
-		if (ami_irq_list[irq]->dev_id != dev_id)
-			printk("%s: removing probably wrong IRQ %d from %s\n",
-			       __FUNCTION__, irq, ami_irq_list[irq]->devname);
-		ami_irq_list[irq]->handler = ami_badint;
-		ami_irq_list[irq]->flags   = 0;
-		ami_irq_list[irq]->dev_id  = NULL;
-		ami_irq_list[irq]->devname = NULL;
-		amiga_custom.intena = amiga_intena_vals[irq];
-	}
-}
-
 /*
  * Enable/disable a particular machine specific interrupt source.
  * Note that this may affect other interrupts in case of a shared interrupt.
  * This function should only be called for a _very_ short time to change some
  * internal data, that may not be changed by the interrupt at the same time.
- * ami_(enable|disable)_irq calls may also be nested.
  */
 
-void amiga_enable_irq(unsigned int irq)
+static void amiga_enable_irq(unsigned int irq)
 {
-	if (irq >= AMI_IRQS) {
-		printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (--ami_ablecount[irq])
-		return;
-
-	/* No action for auto-vector interrupts */
-	if (irq >= IRQ_AMIGA_AUTO){
-		printk("%s: Trying to enable auto-vector IRQ %i\n",
-		       __FUNCTION__, irq - IRQ_AMIGA_AUTO);
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_CIAB) {
-		cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB)));
-		cia_able_irq(&ciab_base, CIA_ICR_SETCLR |
-		             (1 << (irq - IRQ_AMIGA_CIAB)));
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_CIAA) {
-		cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA)));
-		cia_able_irq(&ciaa_base, CIA_ICR_SETCLR |
-		             (1 << (irq - IRQ_AMIGA_CIAA)));
-		return;
-	}
-
-	/* enable the interrupt */
-	amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq];
+	amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER));
 }
 
-void amiga_disable_irq(unsigned int irq)
+static void amiga_disable_irq(unsigned int irq)
 {
-	if (irq >= AMI_IRQS) {
-		printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (ami_ablecount[irq]++)
-		return;
-
-	/* No action for auto-vector interrupts */
-	if (irq >= IRQ_AMIGA_AUTO) {
-		printk("%s: Trying to disable auto-vector IRQ %i\n",
-		       __FUNCTION__, irq - IRQ_AMIGA_AUTO);
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_CIAB) {
-		cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
-		return;
-	}
-
-	if (irq >= IRQ_AMIGA_CIAA) {
-		cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
-		return;
-	}
-
-	/* disable the interrupt */
-	amiga_custom.intena = amiga_intena_vals[irq];
-}
-
-inline void amiga_do_irq(int irq, struct pt_regs *fp)
-{
-	kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-	ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
-}
-
-void amiga_do_irq_list(int irq, struct pt_regs *fp)
-{
-	irq_node_t *node;
-
-	kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-
-	amiga_custom.intreq = amiga_intena_vals[irq];
-
-	for (node = ami_irq_list[irq]; node; node = node->next)
-		node->handler(irq, node->dev_id, fp);
+	amiga_custom.intena = 1 << (irq - IRQ_USER);
 }
 
 /*
@@ -390,19 +120,19 @@
 	/* if serial transmit buffer empty, interrupt */
 	if (ints & IF_TBE) {
 		amiga_custom.intreq = IF_TBE;
-		amiga_do_irq(IRQ_AMIGA_TBE, fp);
+		m68k_handle_int(IRQ_AMIGA_TBE, fp);
 	}
 
 	/* if floppy disk transfer complete, interrupt */
 	if (ints & IF_DSKBLK) {
 		amiga_custom.intreq = IF_DSKBLK;
-		amiga_do_irq(IRQ_AMIGA_DSKBLK, fp);
+		m68k_handle_int(IRQ_AMIGA_DSKBLK, fp);
 	}
 
 	/* if software interrupt set, interrupt */
 	if (ints & IF_SOFT) {
 		amiga_custom.intreq = IF_SOFT;
-		amiga_do_irq(IRQ_AMIGA_SOFT, fp);
+		m68k_handle_int(IRQ_AMIGA_SOFT, fp);
 	}
 	return IRQ_HANDLED;
 }
@@ -414,18 +144,20 @@
 	/* if a blitter interrupt */
 	if (ints & IF_BLIT) {
 		amiga_custom.intreq = IF_BLIT;
-		amiga_do_irq(IRQ_AMIGA_BLIT, fp);
+		m68k_handle_int(IRQ_AMIGA_BLIT, fp);
 	}
 
 	/* if a copper interrupt */
 	if (ints & IF_COPER) {
 		amiga_custom.intreq = IF_COPER;
-		amiga_do_irq(IRQ_AMIGA_COPPER, fp);
+		m68k_handle_int(IRQ_AMIGA_COPPER, fp);
 	}
 
 	/* if a vertical blank interrupt */
-	if (ints & IF_VERTB)
-		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
+	if (ints & IF_VERTB) {
+		amiga_custom.intreq = IF_VERTB;
+		m68k_handle_int(IRQ_AMIGA_VERTB, fp);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -436,25 +168,25 @@
 	/* if audio 0 interrupt */
 	if (ints & IF_AUD0) {
 		amiga_custom.intreq = IF_AUD0;
-		amiga_do_irq(IRQ_AMIGA_AUD0, fp);
+		m68k_handle_int(IRQ_AMIGA_AUD0, fp);
 	}
 
 	/* if audio 1 interrupt */
 	if (ints & IF_AUD1) {
 		amiga_custom.intreq = IF_AUD1;
-		amiga_do_irq(IRQ_AMIGA_AUD1, fp);
+		m68k_handle_int(IRQ_AMIGA_AUD1, fp);
 	}
 
 	/* if audio 2 interrupt */
 	if (ints & IF_AUD2) {
 		amiga_custom.intreq = IF_AUD2;
-		amiga_do_irq(IRQ_AMIGA_AUD2, fp);
+		m68k_handle_int(IRQ_AMIGA_AUD2, fp);
 	}
 
 	/* if audio 3 interrupt */
 	if (ints & IF_AUD3) {
 		amiga_custom.intreq = IF_AUD3;
-		amiga_do_irq(IRQ_AMIGA_AUD3, fp);
+		m68k_handle_int(IRQ_AMIGA_AUD3, fp);
 	}
 	return IRQ_HANDLED;
 }
@@ -466,55 +198,13 @@
 	/* if serial receive buffer full interrupt */
 	if (ints & IF_RBF) {
 		/* acknowledge of IF_RBF must be done by the serial interrupt */
-		amiga_do_irq(IRQ_AMIGA_RBF, fp);
+		m68k_handle_int(IRQ_AMIGA_RBF, fp);
 	}
 
 	/* if a disk sync interrupt */
 	if (ints & IF_DSKSYN) {
 		amiga_custom.intreq = IF_DSKSYN;
-		amiga_do_irq(IRQ_AMIGA_DSKSYN, fp);
+		m68k_handle_int(IRQ_AMIGA_DSKSYN, fp);
 	}
 	return IRQ_HANDLED;
 }
-
-static irqreturn_t ami_int7(int irq, void *dev_id, struct pt_regs *fp)
-{
-	panic ("level 7 interrupt received\n");
-}
-
-irqreturn_t (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	[0] = ami_badint,
-	[1] = ami_int1,
-	[2] = ami_badint,
-	[3] = ami_int3,
-	[4] = ami_int4,
-	[5] = ami_int5,
-	[6] = ami_badint,
-	[7] = ami_int7
-};
-
-int show_amiga_interrupts(struct seq_file *p, void *v)
-{
-	int i;
-	irq_node_t *node;
-
-	for (i = 0; i < AMI_STD_IRQS; i++) {
-		if (!(node = ami_irq_list[i]))
-			continue;
-		seq_printf(p, "ami  %2d: %10u ", i,
-		               kstat_cpu(0).irqs[SYS_IRQS + i]);
-		do {
-			if (node->flags & SA_INTERRUPT)
-				seq_puts(p, "F ");
-			else
-				seq_puts(p, "  ");
-			seq_printf(p, "%s\n", node->devname);
-			if ((node = node->next))
-				seq_puts(p, "                    ");
-		} while (node);
-	}
-
-	cia_get_irq_list(&ciaa_base, p);
-	cia_get_irq_list(&ciab_base, p);
-	return 0;
-}
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 9476eb9..0956e45 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -29,21 +29,18 @@
 	unsigned short int_mask;
 	int handler_irq, cia_irq, server_irq;
 	char *name;
-	irq_handler_t irq_list[CIA_IRQS];
 } ciaa_base = {
 	.cia		= &ciaa,
 	.int_mask	= IF_PORTS,
-	.handler_irq	= IRQ_AMIGA_AUTO_2,
+	.handler_irq	= IRQ_AMIGA_PORTS,
 	.cia_irq	= IRQ_AMIGA_CIAA,
-	.server_irq	= IRQ_AMIGA_PORTS,
-	.name		= "CIAA handler"
+	.name		= "CIAA"
 }, ciab_base = {
 	.cia		= &ciab,
 	.int_mask	= IF_EXTER,
-	.handler_irq	= IRQ_AMIGA_AUTO_6,
+	.handler_irq	= IRQ_AMIGA_EXTER,
 	.cia_irq	= IRQ_AMIGA_CIAB,
-	.server_irq	= IRQ_AMIGA_EXTER,
-	.name		= "CIAB handler"
+	.name		= "CIAB"
 };
 
 /*
@@ -66,13 +63,11 @@
 
 /*
  *  Enable or disable CIA interrupts, return old interrupt mask,
- *  interrupts will only be enabled if a handler exists
  */
 
 unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
 {
-	unsigned char old, tmp;
-	int i;
+	unsigned char old;
 
 	old = base->icr_mask;
 	base->icr_data |= base->cia->icr;
@@ -82,99 +77,104 @@
 	else
 		base->icr_mask &= ~mask;
 	base->icr_mask &= CIA_ICR_ALL;
-	for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
-		if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
-			base->icr_mask &= ~tmp;
-			base->cia->icr = tmp;
-		}
-	}
 	if (base->icr_data & base->icr_mask)
 		amiga_custom.intreq = IF_SETCLR | base->int_mask;
 	return old;
 }
 
-int cia_request_irq(struct ciabase *base, unsigned int irq,
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-	unsigned char mask;
-
-	base->irq_list[irq].handler = handler;
-	base->irq_list[irq].flags   = flags;
-	base->irq_list[irq].dev_id  = dev_id;
-	base->irq_list[irq].devname = devname;
-
-	/* enable the interrupt */
-	mask = 1 << irq;
-	cia_set_irq(base, mask);
-	cia_able_irq(base, CIA_ICR_SETCLR | mask);
-	return 0;
-}
-
-void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
-{
-	if (base->irq_list[irq].dev_id != dev_id)
-		printk("%s: removing probably wrong IRQ %i from %s\n",
-		       __FUNCTION__, base->cia_irq + irq,
-		       base->irq_list[irq].devname);
-
-	base->irq_list[irq].handler = NULL;
-	base->irq_list[irq].flags   = 0;
-
-	cia_able_irq(base, 1 << irq);
-}
-
 static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
 {
 	struct ciabase *base = (struct ciabase *)dev_id;
-	int mach_irq, i;
+	int mach_irq;
 	unsigned char ints;
 
 	mach_irq = base->cia_irq;
-	irq = SYS_IRQS + mach_irq;
 	ints = cia_set_irq(base, CIA_ICR_ALL);
 	amiga_custom.intreq = base->int_mask;
-	for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
-		if (ints & 1) {
-			kstat_cpu(0).irqs[irq]++;
-			base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
-		}
-		ints >>= 1;
+	for (; ints; mach_irq++, ints >>= 1) {
+		if (ints & 1)
+			m68k_handle_int(mach_irq, fp);
 	}
-	amiga_do_irq_list(base->server_irq, fp);
 	return IRQ_HANDLED;
 }
 
+static void cia_enable_irq(unsigned int irq)
+{
+	unsigned char mask;
+
+	if (irq >= IRQ_AMIGA_CIAB) {
+		mask = 1 << (irq - IRQ_AMIGA_CIAB);
+		cia_set_irq(&ciab_base, mask);
+		cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
+	} else {
+		mask = 1 << (irq - IRQ_AMIGA_CIAA);
+		cia_set_irq(&ciaa_base, mask);
+		cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
+	}
+}
+
+static void cia_disable_irq(unsigned int irq)
+{
+	if (irq >= IRQ_AMIGA_CIAB)
+		cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
+	else
+		cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
+}
+
+static struct irq_controller cia_irq_controller = {
+	.name		= "cia",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.enable		= cia_enable_irq,
+	.disable	= cia_disable_irq,
+};
+
+/*
+ * Override auto irq 2 & 6 and use them as general chain
+ * for external interrupts, we link the CIA interrupt sources
+ * into this chain.
+ */
+
+static void auto_enable_irq(unsigned int irq)
+{
+	switch (irq) {
+	case IRQ_AUTO_2:
+		amiga_custom.intena = IF_SETCLR | IF_PORTS;
+		break;
+	case IRQ_AUTO_6:
+		amiga_custom.intena = IF_SETCLR | IF_EXTER;
+		break;
+	}
+}
+
+static void auto_disable_irq(unsigned int irq)
+{
+	switch (irq) {
+	case IRQ_AUTO_2:
+		amiga_custom.intena = IF_PORTS;
+		break;
+	case IRQ_AUTO_6:
+		amiga_custom.intena = IF_EXTER;
+		break;
+	}
+}
+
+static struct irq_controller auto_irq_controller = {
+	.name		= "auto",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.enable		= auto_enable_irq,
+	.disable	= auto_disable_irq,
+};
+
 void __init cia_init_IRQ(struct ciabase *base)
 {
-	int i;
-
-	/* init isr handlers */
-	for (i = 0; i < CIA_IRQS; i++) {
-		base->irq_list[i].handler = NULL;
-		base->irq_list[i].flags   = 0;
-	}
+	m68k_setup_irq_controller(&cia_irq_controller, base->cia_irq, CIA_IRQS);
 
 	/* clear any pending interrupt and turn off all interrupts */
 	cia_set_irq(base, CIA_ICR_ALL);
 	cia_able_irq(base, CIA_ICR_ALL);
 
-	/* install CIA handler */
-	request_irq(base->handler_irq, cia_handler, 0, base->name, base);
-
-	amiga_custom.intena = IF_SETCLR | base->int_mask;
-}
-
-int cia_get_irq_list(struct ciabase *base, struct seq_file *p)
-{
-	int i, j;
-
-	j = base->cia_irq;
-	for (i = 0; i < CIA_IRQS; i++) {
-		seq_printf(p, "cia  %2d: %10d ", j + i,
-			       kstat_cpu(0).irqs[SYS_IRQS + j + i]);
-		seq_puts(p, "  ");
-		seq_printf(p, "%s\n", base->irq_list[i].devname);
-	}
-	return 0;
+	/* override auto int and install CIA handler */
+	m68k_setup_irq_controller(&auto_irq_controller, base->handler_irq, 1);
+	m68k_irq_startup(base->handler_irq);
+	request_irq(base->handler_irq, cia_handler, SA_SHIRQ, base->name, base);
 }
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 12e3706..b5b8a41 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -87,17 +87,8 @@
 static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
-extern irqreturn_t (*amiga_default_handler[]) (int, void *, struct pt_regs *);
-extern int amiga_request_irq (unsigned int irq,
-			      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname,
-			      void *dev_id);
-extern void amiga_free_irq (unsigned int irq, void *dev_id);
-extern void amiga_enable_irq (unsigned int);
-extern void amiga_disable_irq (unsigned int);
 static void amiga_get_model(char *model);
 static int amiga_get_hardware_list(char *buffer);
-extern int show_amiga_interrupts (struct seq_file *, void *);
 /* amiga specific timer functions */
 static unsigned long amiga_gettimeoffset (void);
 static int a3000_hwclk (int, struct rtc_time *);
@@ -392,14 +383,8 @@
 
   mach_sched_init      = amiga_sched_init;
   mach_init_IRQ        = amiga_init_IRQ;
-  mach_default_handler = &amiga_default_handler;
-  mach_request_irq     = amiga_request_irq;
-  mach_free_irq        = amiga_free_irq;
-  enable_irq           = amiga_enable_irq;
-  disable_irq          = amiga_disable_irq;
   mach_get_model       = amiga_get_model;
   mach_get_hardware_list = amiga_get_hardware_list;
-  mach_get_irq_list    = show_amiga_interrupts;
   mach_gettimeoffset   = amiga_gettimeoffset;
   if (AMIGAHW_PRESENT(A3000_CLK)){
     mach_hwclk         = a3000_hwclk;
diff --git a/arch/m68k/apollo/Makefile b/arch/m68k/apollo/Makefile
index 39264f3..76a0579 100644
--- a/arch/m68k/apollo/Makefile
+++ b/arch/m68k/apollo/Makefile
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/amiga source directory
 #
 
-obj-y		:= config.o dn_ints.o dma.o
+obj-y		:= config.o dn_ints.o
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index d401962..99c7097 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -28,11 +28,6 @@
 
 extern void dn_sched_init(irqreturn_t (*handler)(int,void *,struct pt_regs *));
 extern void dn_init_IRQ(void);
-extern int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
-extern void dn_free_irq(unsigned int irq, void *dev_id);
-extern void dn_enable_irq(unsigned int);
-extern void dn_disable_irq(unsigned int);
-extern int show_dn_interrupts(struct seq_file *, void *);
 extern unsigned long dn_gettimeoffset(void);
 extern int dn_dummy_hwclk(int, struct rtc_time *);
 extern int dn_dummy_set_clock_mmss(unsigned long);
@@ -40,13 +35,11 @@
 extern void dn_dummy_waitbut(void);
 extern struct fb_info *dn_fb_init(long *);
 extern void dn_dummy_debug_init(void);
-extern void dn_dummy_video_setup(char *,int *);
 extern irqreturn_t dn_process_int(int irq, struct pt_regs *fp);
 #ifdef CONFIG_HEARTBEAT
 static void dn_heartbeat(int on);
 #endif
 static irqreturn_t dn_timer_int(int irq,void *, struct pt_regs *);
-static irqreturn_t (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
 static void dn_get_model(char *model);
 static const char *apollo_models[] = {
 	[APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)",
@@ -164,17 +157,10 @@
 
 	mach_sched_init=dn_sched_init; /* */
 	mach_init_IRQ=dn_init_IRQ;
-	mach_default_handler=NULL;
-	mach_request_irq     = dn_request_irq;
-	mach_free_irq        = dn_free_irq;
-	enable_irq      = dn_enable_irq;
-	disable_irq     = dn_disable_irq;
-	mach_get_irq_list    = show_dn_interrupts;
 	mach_gettimeoffset   = dn_gettimeoffset;
 	mach_max_dma_address = 0xffffffff;
 	mach_hwclk           = dn_dummy_hwclk; /* */
 	mach_set_clock_mmss  = dn_dummy_set_clock_mmss; /* */
-	mach_process_int     = dn_process_int;
 	mach_reset	     = dn_dummy_reset;  /* */
 #ifdef CONFIG_HEARTBEAT
 	mach_heartbeat = dn_heartbeat;
@@ -189,11 +175,13 @@
 
 }
 
-irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) {
+irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp)
+{
+	irqreturn_t (*timer_handler)(int, void *, struct pt_regs *) = dev_id;
 
 	volatile unsigned char x;
 
-	sched_timer_handler(irq,dev_id,fp);
+	timer_handler(irq, dev_id, fp);
 
 	x=*(volatile unsigned char *)(timer+3);
 	x=*(volatile unsigned char *)(timer+5);
@@ -217,9 +205,7 @@
 	printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
 #endif
 
-	sched_timer_handler=timer_routine;
-	request_irq(0,dn_timer_int,0,NULL,NULL);
-
+	request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine);
 }
 
 unsigned long dn_gettimeoffset(void) {
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index a312593..9fe0780 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -1,125 +1,44 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/kernel_stat.h>
-#include <linux/timer.h>
+#include <linux/interrupt.h>
 
-#include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/machdep.h>
 #include <asm/apollohw.h>
-#include <asm/errno.h>
 
-static irq_handler_t dn_irqs[16];
-
-irqreturn_t dn_process_int(int irq, struct pt_regs *fp)
+void dn_process_int(unsigned int irq, struct pt_regs *fp)
 {
-  irqreturn_t res = IRQ_NONE;
+	m68k_handle_int(irq, fp);
 
-  if(dn_irqs[irq-160].handler) {
-    res = dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
-  } else {
-    printk("spurious irq %d occurred\n",irq);
-  }
-
-  *(volatile unsigned char *)(pica)=0x20;
-  *(volatile unsigned char *)(picb)=0x20;
-
-  return res;
+	*(volatile unsigned char *)(pica)=0x20;
+	*(volatile unsigned char *)(picb)=0x20;
 }
 
-void dn_init_IRQ(void) {
-
-  int i;
-
-  for(i=0;i<16;i++) {
-    dn_irqs[i].handler=NULL;
-    dn_irqs[i].flags=IRQ_FLG_STD;
-    dn_irqs[i].dev_id=NULL;
-    dn_irqs[i].devname=NULL;
-  }
-
+int apollo_irq_startup(unsigned int irq)
+{
+	if (irq < 8)
+		*(volatile unsigned char *)(pica+1) &= ~(1 << irq);
+	else
+		*(volatile unsigned char *)(picb+1) &= ~(1 << (irq - 8));
+	return 0;
 }
 
-int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) {
-
-  if((irq<0) || (irq>15)) {
-    printk("Trying to request invalid IRQ\n");
-    return -ENXIO;
-  }
-
-  if(!dn_irqs[irq].handler) {
-    dn_irqs[irq].handler=handler;
-    dn_irqs[irq].flags=IRQ_FLG_STD;
-    dn_irqs[irq].dev_id=dev_id;
-    dn_irqs[irq].devname=devname;
-    if(irq<8)
-      *(volatile unsigned char *)(pica+1)&=~(1<<irq);
-    else
-      *(volatile unsigned char *)(picb+1)&=~(1<<(irq-8));
-
-    return 0;
-  }
-  else {
-    printk("Trying to request already assigned irq %d\n",irq);
-    return -ENXIO;
-  }
-
+void apollo_irq_shutdown(unsigned int irq)
+{
+	if (irq < 8)
+		*(volatile unsigned char *)(pica+1) |= (1 << irq);
+	else
+		*(volatile unsigned char *)(picb+1) |= (1 << (irq - 8));
 }
 
-void dn_free_irq(unsigned int irq, void *dev_id) {
+static struct irq_controller apollo_irq_controller = {
+	.name           = "apollo",
+	.lock           = SPIN_LOCK_UNLOCKED,
+	.startup        = apollo_irq_startup,
+	.shutdown       = apollo_irq_shutdown,
+};
 
-  if((irq<0) || (irq>15)) {
-    printk("Trying to free invalid IRQ\n");
-    return ;
-  }
 
-  if(irq<8)
-    *(volatile unsigned char *)(pica+1)|=(1<<irq);
-  else
-    *(volatile unsigned char *)(picb+1)|=(1<<(irq-8));
-
-  dn_irqs[irq].handler=NULL;
-  dn_irqs[irq].flags=IRQ_FLG_STD;
-  dn_irqs[irq].dev_id=NULL;
-  dn_irqs[irq].devname=NULL;
-
-  return ;
-
-}
-
-void dn_enable_irq(unsigned int irq) {
-
-  printk("dn enable irq\n");
-
-}
-
-void dn_disable_irq(unsigned int irq) {
-
-  printk("dn disable irq\n");
-
-}
-
-int show_dn_interrupts(struct seq_file *p, void *v) {
-
-  printk("dn get irq list\n");
-
-  return 0;
-
-}
-
-struct fb_info *dn_dummy_fb_init(long *mem_start) {
-
-  printk("fb init\n");
-
-  return NULL;
-
-}
-
-void dn_dummy_video_setup(char *options,int *ints) {
-
-  printk("no video yet\n");
-
+void dn_init_IRQ(void)
+{
+	m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
+	m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
 }
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 076f479..ece13cb 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -104,6 +104,7 @@
  * the sr copy in the frame.
  */
 
+#if 0
 
 #define	NUM_INT_SOURCES	(8 + NUM_ATARI_SOURCES)
 
@@ -133,13 +134,6 @@
  */
 static struct irqparam irq_param[NUM_INT_SOURCES];
 
-/*
- * Bitmap for free interrupt vector numbers
- * (new vectors starting from 0x70 can be allocated by
- * atari_register_vme_int())
- */
-static int free_vme_vec_bitmap;
-
 /* check for valid int number (complex, sigh...) */
 #define	IS_VALID_INTNO(n)											\
 	((n) > 0 &&														\
@@ -301,6 +295,14 @@
 );
 	for (;;);
 }
+#endif
+
+/*
+ * Bitmap for free interrupt vector numbers
+ * (new vectors starting from 0x70 can be allocated by
+ * atari_register_vme_int())
+ */
+static int free_vme_vec_bitmap;
 
 /* GK:
  * HBL IRQ handler for Falcon. Nobody needs it :-)
@@ -313,13 +315,34 @@
 	"orw	#0x200,%sp@\n\t"	/* set saved ipl to 2 */
 	"rte");
 
-/* Defined in entry.S; only increments 'num_spurious' */
-asmlinkage void bad_interrupt(void);
-
-extern void atari_microwire_cmd( int cmd );
+extern void atari_microwire_cmd(int cmd);
 
 extern int atari_SCC_reset_done;
 
+static int atari_startup_irq(unsigned int irq)
+{
+	m68k_irq_startup(irq);
+	atari_turnon_irq(irq);
+	atari_enable_irq(irq);
+	return 0;
+}
+
+static void atari_shutdown_irq(unsigned int irq)
+{
+	atari_disable_irq(irq);
+	atari_turnoff_irq(irq);
+	m68k_irq_shutdown(irq);
+}
+
+static struct irq_controller atari_irq_controller = {
+	.name		= "atari",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.startup	= atari_startup_irq,
+	.shutdown	= atari_shutdown_irq,
+	.enable		= atari_enable_irq,
+	.disable	= atari_disable_irq,
+};
+
 /*
  * void atari_init_IRQ (void)
  *
@@ -333,12 +356,8 @@
 
 void __init atari_init_IRQ(void)
 {
-	int i;
-
-	/* initialize the vector table */
-	for (i = 0; i < NUM_INT_SOURCES; ++i) {
-		vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt;
-	}
+	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+	m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
 
 	/* Initialize the MFP(s) */
 
@@ -378,8 +397,7 @@
 									 * enabled in VME mask
 									 */
 		tt_scu.vme_mask = 0x60;		/* enable MFP and SCC ints */
-	}
-	else {
+	} else {
 		/* If no SCU and no Hades, the HSYNC interrupt needs to be
 		 * disabled this way. (Else _inthandler in kernel/sys_call.S
 		 * gets overruns)
@@ -404,184 +422,6 @@
 }
 
 
-static irqreturn_t atari_call_irq_list( int irq, void *dev_id, struct pt_regs *fp )
-{
-	irq_node_t *node;
-
-	for (node = (irq_node_t *)dev_id; node; node = node->next)
-		node->handler(irq, node->dev_id, fp);
-	return IRQ_HANDLED;
-}
-
-
-/*
- * atari_request_irq : add an interrupt service routine for a particular
- *                     machine specific interrupt source.
- *                     If the addition was successful, it returns 0.
- */
-
-int atari_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-	int vector;
-	unsigned long oflags = flags;
-
-	/*
-	 * The following is a hack to make some PCI card drivers work,
-	 * which set the SA_SHIRQ flag.
-	 */
-
-	flags &= ~SA_SHIRQ;
-
-	if (flags == SA_INTERRUPT) {
-		printk ("%s: SA_INTERRUPT changed to IRQ_TYPE_SLOW for %s\n",
-			__FUNCTION__, devname);
-		flags = IRQ_TYPE_SLOW;
-	}
-	if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
-		printk ("%s: Bad irq type 0x%lx <0x%lx> requested from %s\n",
-		        __FUNCTION__, flags, oflags, devname);
-		return -EINVAL;
-	}
-	if (!IS_VALID_INTNO(irq)) {
-		printk ("%s: Unknown irq %d requested from %s\n",
-		        __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-	vector = IRQ_SOURCE_TO_VECTOR(irq);
-
-	/*
-	 * Check type/source combination: slow ints are (currently)
-	 * only possible for MFP-interrupts.
-	 */
-	if (flags == IRQ_TYPE_SLOW &&
-		(irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE)) {
-		printk ("%s: Slow irq requested for non-MFP source %d from %s\n",
-		        __FUNCTION__, irq, devname);
-		return -EINVAL;
-	}
-
-	if (vectors[vector] == bad_interrupt) {
-		/* int has no handler yet */
-		irq_handler[irq].handler = handler;
-		irq_handler[irq].dev_id  = dev_id;
-		irq_param[irq].flags   = flags;
-		irq_param[irq].devname = devname;
-		vectors[vector] =
-			(flags == IRQ_TYPE_SLOW) ? slow_handlers[irq-STMFP_SOURCE_BASE] :
-			(flags == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
-			                          atari_prio_irq_handler;
-		/* If MFP int, also enable and umask it */
-		atari_turnon_irq(irq);
-		atari_enable_irq(irq);
-
-		return 0;
-	}
-	else if (irq_param[irq].flags == flags) {
-		/* old handler is of same type -> handlers can be chained */
-		irq_node_t *node;
-		unsigned long flags;
-
-		local_irq_save(flags);
-
-		if (irq_handler[irq].handler != atari_call_irq_list) {
-			/* Only one handler yet, make a node for this first one */
-			if (!(node = new_irq_node()))
-				return -ENOMEM;
-			node->handler = irq_handler[irq].handler;
-			node->dev_id  = irq_handler[irq].dev_id;
-			node->devname = irq_param[irq].devname;
-			node->next = NULL;
-
-			irq_handler[irq].handler = atari_call_irq_list;
-			irq_handler[irq].dev_id  = node;
-			irq_param[irq].devname   = "chained";
-		}
-
-		if (!(node = new_irq_node()))
-			return -ENOMEM;
-		node->handler = handler;
-		node->dev_id  = dev_id;
-		node->devname = devname;
-		/* new handlers are put in front of the queue */
-		node->next = irq_handler[irq].dev_id;
-		irq_handler[irq].dev_id = node;
-
-		local_irq_restore(flags);
-		return 0;
-	} else {
-		printk ("%s: Irq %d allocated by other type int (call from %s)\n",
-		        __FUNCTION__, irq, devname);
-		return -EBUSY;
-	}
-}
-
-void atari_free_irq(unsigned int irq, void *dev_id)
-{
-	unsigned long flags;
-	int vector;
-	irq_node_t **list, *node;
-
-	if (!IS_VALID_INTNO(irq)) {
-		printk("%s: Unknown irq %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	vector = IRQ_SOURCE_TO_VECTOR(irq);
-	if (vectors[vector] == bad_interrupt)
-		goto not_found;
-
-	local_irq_save(flags);
-
-	if (irq_handler[irq].handler != atari_call_irq_list) {
-		/* It's the only handler for the interrupt */
-		if (irq_handler[irq].dev_id != dev_id) {
-			local_irq_restore(flags);
-			goto not_found;
-		}
-		irq_handler[irq].handler = NULL;
-		irq_handler[irq].dev_id  = NULL;
-		irq_param[irq].devname   = NULL;
-		vectors[vector] = bad_interrupt;
-		/* If MFP int, also disable it */
-		atari_disable_irq(irq);
-		atari_turnoff_irq(irq);
-
-		local_irq_restore(flags);
-		return;
-	}
-
-	/* The interrupt is chained, find the irq on the list */
-	for(list = (irq_node_t **)&irq_handler[irq].dev_id; *list; list = &(*list)->next) {
-		if ((*list)->dev_id == dev_id) break;
-	}
-	if (!*list) {
-		local_irq_restore(flags);
-		goto not_found;
-	}
-
-	(*list)->handler = NULL; /* Mark it as free for reallocation */
-	*list = (*list)->next;
-
-	/* If there's now only one handler, unchain the interrupt, i.e. plug in
-	 * the handler directly again and omit atari_call_irq_list */
-	node = (irq_node_t *)irq_handler[irq].dev_id;
-	if (node && !node->next) {
-		irq_handler[irq].handler = node->handler;
-		irq_handler[irq].dev_id  = node->dev_id;
-		irq_param[irq].devname   = node->devname;
-		node->handler = NULL; /* Mark it as free for reallocation */
-	}
-
-	local_irq_restore(flags);
-	return;
-
-not_found:
-	printk("%s: tried to remove invalid irq\n", __FUNCTION__);
-	return;
-}
-
-
 /*
  * atari_register_vme_int() returns the number of a free interrupt vector for
  * hardware with a programmable int vector (probably a VME board).
@@ -591,58 +431,24 @@
 {
 	int i;
 
-	for(i = 0; i < 32; i++)
-		if((free_vme_vec_bitmap & (1 << i)) == 0)
+	for (i = 0; i < 32; i++)
+		if ((free_vme_vec_bitmap & (1 << i)) == 0)
 			break;
 
-	if(i == 16)
+	if (i == 16)
 		return 0;
 
 	free_vme_vec_bitmap |= 1 << i;
-	return (VME_SOURCE_BASE + i);
+	return VME_SOURCE_BASE + i;
 }
 
 
 void atari_unregister_vme_int(unsigned long irq)
 {
-	if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
+	if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
 		irq -= VME_SOURCE_BASE;
 		free_vme_vec_bitmap &= ~(1 << irq);
 	}
 }
 
 
-int show_atari_interrupts(struct seq_file *p, void *v)
-{
-	int i;
-
-	for (i = 0; i < NUM_INT_SOURCES; ++i) {
-		if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt)
-			continue;
-		if (i < STMFP_SOURCE_BASE)
-			seq_printf(p, "auto %2d: %10u ",
-				       i, kstat_cpu(0).irqs[i]);
-		else
-			seq_printf(p, "vec $%02x: %10u ",
-				       IRQ_SOURCE_TO_VECTOR(i),
-				       kstat_cpu(0).irqs[i]);
-
-		if (irq_handler[i].handler != atari_call_irq_list) {
-			seq_printf(p, "%s\n", irq_param[i].devname);
-		}
-		else {
-			irq_node_t *n;
-			for( n = (irq_node_t *)irq_handler[i].dev_id; n; n = n->next ) {
-				seq_printf(p, "%s\n", n->devname);
-				if (n->next)
-					seq_puts(p, "                    " );
-			}
-		}
-	}
-	if (num_spurious)
-		seq_printf(p, "spurio.: %10u\n", num_spurious);
-
-	return 0;
-}
-
-
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 1012b08..727289a 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -57,12 +57,6 @@
 
 /* atari specific irq functions */
 extern void atari_init_IRQ (void);
-extern int atari_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname, void *dev_id);
-extern void atari_free_irq (unsigned int irq, void *dev_id);
-extern void atari_enable_irq (unsigned int);
-extern void atari_disable_irq (unsigned int);
-extern int show_atari_interrupts (struct seq_file *, void *);
 extern void atari_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_HEARTBEAT
 static void atari_heartbeat( int on );
@@ -232,13 +226,8 @@
 
     mach_sched_init      = atari_sched_init;
     mach_init_IRQ        = atari_init_IRQ;
-    mach_request_irq     = atari_request_irq;
-    mach_free_irq        = atari_free_irq;
-    enable_irq           = atari_enable_irq;
-    disable_irq          = atari_disable_irq;
     mach_get_model	 = atari_get_model;
     mach_get_hardware_list = atari_get_hardware_list;
-    mach_get_irq_list	 = show_atari_interrupts;
     mach_gettimeoffset   = atari_gettimeoffset;
     mach_reset           = atari_reset;
     mach_max_dma_address = 0xffffff;
diff --git a/arch/m68k/bvme6000/Makefile b/arch/m68k/bvme6000/Makefile
index 2348e6c..d817400 100644
--- a/arch/m68k/bvme6000/Makefile
+++ b/arch/m68k/bvme6000/Makefile
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/bvme6000 source directory
 #
 
-obj-y		:= config.o bvmeints.o rtc.o
+obj-y		:= config.o rtc.o
diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
deleted file mode 100644
index 298a8df..0000000
--- a/arch/m68k/bvme6000/bvmeints.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * arch/m68k/bvme6000/bvmeints.c
- *
- * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
-	irqreturn_t	(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-	const char	*devname;
-	unsigned	count;
-} irq_tab[256];
-
-/*
- * void bvme6000_init_IRQ (void)
- *
- * Parameters:	None
- *
- * Returns:	Nothing
- *
- * This function is called during kernel startup to initialize
- * the bvme6000 IRQ handling routines.
- */
-
-void bvme6000_init_IRQ (void)
-{
-	int i;
-
-	for (i = 0; i < 256; i++) {
-		irq_tab[i].handler = bvme6000_defhand;
-		irq_tab[i].flags = IRQ_FLG_STD;
-		irq_tab[i].dev_id = NULL;
-		irq_tab[i].devname = NULL;
-		irq_tab[i].count = 0;
-	}
-}
-
-int bvme6000_request_irq(unsigned int irq,
-		irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-	if (irq > 255) {
-		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-#if 0
-	/* Nothing special about auto-vectored devices for the BVME6000,
-	 * but treat it specially to avoid changes elsewhere.
-	 */
-
-	if (irq >= VEC_INT1 && irq <= VEC_INT7)
-		return cpu_request_irq(irq - VEC_SPUR, handler, flags,
-						devname, dev_id);
-#endif
-	if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
-		if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_tab[irq].devname);
-			return -EBUSY;
-		}
-		if (flags & IRQ_FLG_REPLACE) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_tab[irq].devname);
-			return -EBUSY;
-		}
-	}
-	irq_tab[irq].handler = handler;
-	irq_tab[irq].flags   = flags;
-	irq_tab[irq].dev_id  = dev_id;
-	irq_tab[irq].devname = devname;
-	return 0;
-}
-
-void bvme6000_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq > 255) {
-		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-#if 0
-	if (irq >= VEC_INT1 && irq <= VEC_INT7) {
-		cpu_free_irq(irq - VEC_SPUR, dev_id);
-		return;
-	}
-#endif
-	if (irq_tab[irq].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_tab[irq].devname);
-
-	irq_tab[irq].handler = bvme6000_defhand;
-	irq_tab[irq].flags   = IRQ_FLG_STD;
-	irq_tab[irq].dev_id  = NULL;
-	irq_tab[irq].devname = NULL;
-}
-
-irqreturn_t bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
-{
-	if (vec > 255) {
-		printk ("bvme6000_process_int: Illegal vector %ld", vec);
-		return IRQ_NONE;
-	} else {
-		irq_tab[vec].count++;
-		irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
-		return IRQ_HANDLED;
-	}
-}
-
-int show_bvme6000_interrupts(struct seq_file *p, void *v)
-{
-	int i;
-
-	for (i = 0; i < 256; i++) {
-		if (irq_tab[i].count)
-			seq_printf(p, "Vec 0x%02x: %8d  %s\n",
-			    i, irq_tab[i].count,
-			    irq_tab[i].devname ? irq_tab[i].devname : "free");
-	}
-	return 0;
-}
-
-
-static irqreturn_t bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-	printk ("Unknown interrupt 0x%02x\n", irq);
-	return IRQ_NONE;
-}
-
-void bvme6000_enable_irq (unsigned int irq)
-{
-}
-
-
-void bvme6000_disable_irq (unsigned int irq)
-{
-}
-
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index c90cb5f..d1e916a 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -36,15 +36,8 @@
 #include <asm/machdep.h>
 #include <asm/bvme6000hw.h>
 
-extern irqreturn_t bvme6000_process_int (int level, struct pt_regs *regs);
-extern void bvme6000_init_IRQ (void);
-extern void bvme6000_free_irq (unsigned int, void *);
-extern int  show_bvme6000_interrupts(struct seq_file *, void *);
-extern void bvme6000_enable_irq (unsigned int);
-extern void bvme6000_disable_irq (unsigned int);
 static void bvme6000_get_model(char *model);
 static int  bvme6000_get_hardware_list(char *buffer);
-extern int  bvme6000_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern unsigned long bvme6000_gettimeoffset (void);
 extern int bvme6000_hwclk (int, struct rtc_time *);
@@ -100,6 +93,14 @@
     return 0;
 }
 
+/*
+ * This function is called during kernel startup to initialize
+ * the bvme6000 IRQ handling routines.
+ */
+static void bvme6000_init_IRQ(void)
+{
+	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
 
 void __init config_bvme6000(void)
 {
@@ -127,12 +128,6 @@
     mach_hwclk           = bvme6000_hwclk;
     mach_set_clock_mmss	 = bvme6000_set_clock_mmss;
     mach_reset		 = bvme6000_reset;
-    mach_free_irq	 = bvme6000_free_irq;
-    mach_process_int	 = bvme6000_process_int;
-    mach_get_irq_list	 = show_bvme6000_interrupts;
-    mach_request_irq	 = bvme6000_request_irq;
-    enable_irq		 = bvme6000_enable_irq;
-    disable_irq          = bvme6000_disable_irq;
     mach_get_model       = bvme6000_get_model;
     mach_get_hardware_list = bvme6000_get_hardware_list;
 
diff --git a/arch/m68k/hp300/Makefile b/arch/m68k/hp300/Makefile
index 89b6317..288b9c6 100644
--- a/arch/m68k/hp300/Makefile
+++ b/arch/m68k/hp300/Makefile
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/hp300 source directory
 #
 
-obj-y		:= ksyms.o config.o ints.o time.o reboot.o
+obj-y		:= ksyms.o config.o time.o reboot.o
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
index 6d129ee..2ef271c 100644
--- a/arch/m68k/hp300/config.c
+++ b/arch/m68k/hp300/config.c
@@ -21,7 +21,6 @@
 #include <asm/hp300hw.h>
 #include <asm/rtc.h>
 
-#include "ints.h"
 #include "time.h"
 
 unsigned long hp300_model;
@@ -64,8 +63,6 @@
 static char hp300_model_name[13] = "HP9000/";
 
 extern void hp300_reset(void);
-extern irqreturn_t (*hp300_default_handler[])(int, void *, struct pt_regs *);
-extern int show_hp300_interrupts(struct seq_file *, void *);
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 extern int hp300_setup_serial_console(void) __init;
 #endif
@@ -245,16 +242,16 @@
 		hp300_rtc_read(RTC_REG_SEC2);
 }
 
+static void __init hp300_init_IRQ(void)
+{
+}
+
 void __init config_hp300(void)
 {
 	mach_sched_init      = hp300_sched_init;
 	mach_init_IRQ        = hp300_init_IRQ;
-	mach_request_irq     = hp300_request_irq;
-	mach_free_irq        = hp300_free_irq;
 	mach_get_model       = hp300_get_model;
-	mach_get_irq_list    = show_hp300_interrupts;
 	mach_gettimeoffset   = hp300_gettimeoffset;
-	mach_default_handler = &hp300_default_handler;
 	mach_hwclk	     = hp300_hwclk;
 	mach_get_ss	     = hp300_get_ss;
 	mach_reset           = hp300_reset;
diff --git a/arch/m68k/hp300/ints.c b/arch/m68k/hp300/ints.c
deleted file mode 100644
index 0c5bb40..0000000
--- a/arch/m68k/hp300/ints.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- *  linux/arch/m68k/hp300/ints.c
- *
- *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- *
- *  This file contains the HP300-specific interrupt handling.
- *  We only use the autovector interrupts, and therefore we need to
- *  maintain lists of devices sharing each ipl.
- *  [ipl list code added by Peter Maydell <pmaydell@chiark.greenend.org.uk> 06/1998]
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/ptrace.h>
-#include <asm/errno.h>
-#include "ints.h"
-
-/* Each ipl has a linked list of interrupt service routines.
- * Service routines are added via hp300_request_irq() and removed
- * via hp300_free_irq(). The device driver should set IRQ_FLG_FAST
- * if it needs to be serviced early (eg FIFOless UARTs); this will
- * cause it to be added at the front of the queue rather than
- * the back.
- * Currently IRQ_FLG_SLOW and flags=0 are treated identically; if
- * we needed three levels of priority we could distinguish them
- * but this strikes me as mildly ugly...
- */
-
-/* we start with no entries in any list */
-static irq_node_t *hp300_irq_list[HP300_NUM_IRQS];
-
-static spinlock_t irqlist_lock;
-
-/* This handler receives all interrupts, dispatching them to the registered handlers */
-static irqreturn_t hp300_int_handler(int irq, void *dev_id, struct pt_regs *fp)
-{
-        irq_node_t *t;
-        /* We just give every handler on the chain an opportunity to handle
-         * the interrupt, in priority order.
-         */
-        for(t = hp300_irq_list[irq]; t; t=t->next)
-                t->handler(irq, t->dev_id, fp);
-        /* We could put in some accounting routines, checks for stray interrupts,
-         * etc, in here. Note that currently we can't tell whether or not
-         * a handler handles the interrupt, though.
-         */
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t hp300_badint(int irq, void *dev_id, struct pt_regs *fp)
-{
-	num_spurious += 1;
-	return IRQ_NONE;
-}
-
-irqreturn_t (*hp300_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	[0] = hp300_badint,
-	[1] = hp300_int_handler,
-	[2] = hp300_int_handler,
-	[3] = hp300_int_handler,
-	[4] = hp300_int_handler,
-	[5] = hp300_int_handler,
-	[6] = hp300_int_handler,
-	[7] = hp300_int_handler
-};
-
-/* dev_id had better be unique to each handler because it's the only way we have
- * to distinguish handlers when removing them...
- *
- * It would be pretty easy to support IRQ_FLG_LOCK (handler is not replacable)
- * and IRQ_FLG_REPLACE (handler replaces existing one with this dev_id)
- * if we wanted to. IRQ_FLG_FAST is needed for devices where interrupt latency
- * matters (eg the dreaded FIFOless UART...)
- */
-int hp300_request_irq(unsigned int irq,
-                      irqreturn_t (*handler) (int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-        irq_node_t *t, *n = new_irq_node();
-
-        if (!n)                                   /* oops, no free nodes */
-                return -ENOMEM;
-
-	spin_lock_irqsave(&irqlist_lock, flags);
-
-        if (!hp300_irq_list[irq]) {
-                /* no list yet */
-                hp300_irq_list[irq] = n;
-                n->next = NULL;
-        } else if (flags & IRQ_FLG_FAST) {
-                /* insert at head of list */
-                n->next = hp300_irq_list[irq];
-                hp300_irq_list[irq] = n;
-        } else {
-                /* insert at end of list */
-                for(t = hp300_irq_list[irq]; t->next; t = t->next)
-                        /* do nothing */;
-                n->next = NULL;
-                t->next = n;
-        }
-
-        /* Fill in n appropriately */
-        n->handler = handler;
-        n->flags = flags;
-        n->dev_id = dev_id;
-        n->devname = devname;
-	spin_unlock_irqrestore(&irqlist_lock, flags);
-	return 0;
-}
-
-void hp300_free_irq(unsigned int irq, void *dev_id)
-{
-        irq_node_t *t;
-        unsigned long flags;
-
-        spin_lock_irqsave(&irqlist_lock, flags);
-
-        t = hp300_irq_list[irq];
-        if (!t)                                   /* no handlers at all for that IRQ */
-        {
-                printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %d\n", irq);
-                spin_unlock_irqrestore(&irqlist_lock, flags);
-		return;
-        }
-
-        if (t->dev_id == dev_id)
-        {                                         /* removing first handler on chain */
-                t->flags = IRQ_FLG_STD;           /* we probably don't really need these */
-                t->dev_id = NULL;
-                t->devname = NULL;
-                t->handler = NULL;                /* frees this irq_node_t */
-                hp300_irq_list[irq] = t->next;
-		spin_unlock_irqrestore(&irqlist_lock, flags);
-		return;
-        }
-
-        /* OK, must be removing from middle of the chain */
-
-        for (t = hp300_irq_list[irq]; t->next && t->next->dev_id != dev_id; t = t->next)
-                /* do nothing */;
-        if (!t->next)
-        {
-                printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %d\n", irq);
-		spin_unlock_irqrestore(&irqlist_lock, flags);
-		return;
-        }
-        /* remove the entry after t: */
-        t->next->flags = IRQ_FLG_STD;
-        t->next->dev_id = NULL;
-	t->next->devname = NULL;
-	t->next->handler = NULL;
-        t->next = t->next->next;
-
-	spin_unlock_irqrestore(&irqlist_lock, flags);
-}
-
-int show_hp300_interrupts(struct seq_file *p, void *v)
-{
-	return 0;
-}
-
-void __init hp300_init_IRQ(void)
-{
-	spin_lock_init(&irqlist_lock);
-}
diff --git a/arch/m68k/hp300/ints.h b/arch/m68k/hp300/ints.h
deleted file mode 100644
index 8cfabe2..0000000
--- a/arch/m68k/hp300/ints.h
+++ /dev/null
@@ -1,9 +0,0 @@
-extern void hp300_init_IRQ(void);
-extern void (*hp300_handlers[8])(int, void *, struct pt_regs *);
-extern void hp300_free_irq(unsigned int irq, void *dev_id);
-extern int hp300_request_irq(unsigned int irq,
-		irqreturn_t (*handler) (int, void *, struct pt_regs *),
-		unsigned long flags, const char *devname, void *dev_id);
-
-/* number of interrupts, includes 0 (what's that?) */
-#define HP300_NUM_IRQS 8
diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
index 8da5b1b..7df0566 100644
--- a/arch/m68k/hp300/time.c
+++ b/arch/m68k/hp300/time.c
@@ -18,7 +18,6 @@
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/blinken.h>
-#include "ints.h"
 
 /* Clock hardware definitions */
 
@@ -71,7 +70,7 @@
 
   asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE));
 
-  cpu_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+  request_irq(IRQ_AUTO_6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
 
   out_8(CLOCKBASE + CLKCR2, 0x1);		/* select CR1 */
   out_8(CLOCKBASE + CLKCR1, 0x40);		/* enable irq */
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 458925c..dae6097 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -9,8 +9,8 @@
 endif
 extra-y	+= vmlinux.lds
 
-obj-y		:= entry.o process.o traps.o ints.o signal.o ptrace.o \
-			sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
+obj-y	:= entry.o process.o traps.o ints.o dma.o signal.o ptrace.o \
+	   sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
 
 obj-$(CONFIG_PCI)	+= bios32.o
 obj-$(CONFIG_MODULES)	+= module.o
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
new file mode 100644
index 0000000..fc449f8
--- /dev/null
+++ b/arch/m68k/kernel/dma.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#undef DEBUG
+
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#include <asm/pgalloc.h>
+#include <asm/scatterlist.h>
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+			 dma_addr_t *handle, int flag)
+{
+	struct page *page, **map;
+	pgprot_t pgprot;
+	void *addr;
+	int i, order;
+
+	pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
+
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+
+	page = alloc_pages(flag, order);
+	if (!page)
+		return NULL;
+
+	*handle = page_to_phys(page);
+	map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
+	if (!map) {
+		__free_pages(page, order);
+		return NULL;
+	}
+	split_page(page, order);
+
+	order = 1 << order;
+	size >>= PAGE_SHIFT;
+	map[0] = page;
+	for (i = 1; i < size; i++)
+		map[i] = page + i;
+	for (; i < order; i++)
+		__free_page(page + i);
+	pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+	if (CPU_IS_040_OR_060)
+		pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
+	else
+		pgprot_val(pgprot) |= _PAGE_NOCACHE030;
+	addr = vmap(map, size, flag, pgprot);
+	kfree(map);
+
+	return addr;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+		       void *addr, dma_addr_t handle)
+{
+	pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
+	vfree(addr);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+inline void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
+				       enum dma_data_direction dir)
+{
+	switch (dir) {
+	case DMA_TO_DEVICE:
+		cache_push(handle, size);
+		break;
+	case DMA_FROM_DEVICE:
+		cache_clear(handle, size);
+		break;
+	default:
+		if (printk_ratelimit())
+			printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
+		break;
+	}
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
+			    enum dma_data_direction dir)
+{
+	int i;
+
+	for (i = 0; i < nents; sg++, i++)
+		dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
+			  enum dma_data_direction dir)
+{
+	dma_addr_t handle = virt_to_bus(addr);
+
+	dma_sync_single_for_device(dev, handle, size, dir);
+	return handle;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+			unsigned long offset, size_t size,
+			enum dma_data_direction dir)
+{
+	dma_addr_t handle = page_to_phys(page) + offset;
+
+	dma_sync_single_for_device(dev, handle, size, dir);
+	return handle;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+	       enum dma_data_direction dir)
+{
+	int i;
+
+	for (i = 0; i < nents; sg++, i++) {
+		sg->dma_address = page_to_phys(sg->page) + sg->offset;
+		dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+	}
+	return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 522079f..449b62b 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -45,9 +45,11 @@
 #include <asm/asm-offsets.h>
 
 .globl system_call, buserr, trap, resume
-.globl inthandler, sys_call_table
+.globl sys_call_table
 .globl sys_fork, sys_clone, sys_vfork
 .globl ret_from_interrupt, bad_interrupt
+.globl auto_irqhandler_fixup
+.globl user_irqvec_fixup, user_irqhandler_fixup
 
 .text
 ENTRY(buserr)
@@ -191,65 +193,29 @@
 	jbra	resume_userspace
 
 
-#if 0
-#ifdef CONFIG_AMIGA
-ami_inthandler:
-	addql	#1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT
-	SAVE_ALL_INT
-	GET_CURRENT(%d0)
+/* This is the main interrupt handler for autovector interrupts */
 
-	bfextu	%sp@(PT_VECTOR){#4,#12},%d0
-	movel	%d0,%a0
-	addql	#1,%a0@(kstat+STAT_IRQ-VECOFF(VEC_SPUR))
-	movel	%a0@(autoirq_list-VECOFF(VEC_SPUR)),%a0
-
-| amiga vector int handler get the req mask instead of irq vector
-	lea	CUSTOMBASE,%a1
-	movew	%a1@(C_INTREQR),%d0
-	andw	%a1@(C_INTENAR),%d0
-
-| prepare stack (push frame pointer, dev_id & req mask)
-	pea	%sp@
-	movel	%a0@(IRQ_DEVID),%sp@-
-	movel	%d0,%sp@-
-	pea	%pc@(ret_from_interrupt:w)
-	jbra	@(IRQ_HANDLER,%a0)@(0)
-
-ENTRY(nmi_handler)
-	rte
-#endif
-#endif
-
-/*
-** This is the main interrupt handler, responsible for calling process_int()
-*/
-inthandler:
+ENTRY(auto_inthandler)
 	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	addqb	#1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
 					|  put exception # in d0
-	bfextu %sp@(PT_VECTOR){#4,#10},%d0
+	bfextu	%sp@(PT_VECTOR){#4,#10},%d0
+	subw	#VEC_SPUR,%d0
 
 	movel	%sp,%sp@-
 	movel	%d0,%sp@-		|  put vector # on stack
-#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
-	btstb	#4,0xff000000		| Q40 floppy needs very special treatment ...
-	jbeq	1f
-	btstb	#3,0xff000004
-	jbeq	1f
-	jbsr	floppy_hardint
-	jbra	3f
-1:
-#endif
-	jbsr	process_int		|  process the IRQ
-3:	addql	#8,%sp			|  pop parameters off stack
+auto_irqhandler_fixup = . + 2
+	jsr	m68k_handle_int		|  process the IRQ
+	addql	#8,%sp			|  pop parameters off stack
 
 ret_from_interrupt:
 	subqb	#1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-	jeq	1f
-2:
-	RESTORE_ALL
-1:
+	jeq	ret_from_last_interrupt
+2:	RESTORE_ALL
+
+	ALIGN
+ret_from_last_interrupt:
 	moveq	#(~ALLOWINT>>8)&0xff,%d0
 	andb	%sp@(PT_SR),%d0
 	jne	2b
@@ -260,12 +226,42 @@
 	pea	ret_from_exception
 	jra	do_softirq
 
+/* Handler for user defined interrupt vectors */
+
+ENTRY(user_inthandler)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	addqb	#1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+					|  put exception # in d0
+	bfextu	%sp@(PT_VECTOR){#4,#10},%d0
+user_irqvec_fixup = . + 2
+	subw	#VEC_USER,%d0
+
+	movel	%sp,%sp@-
+	movel	%d0,%sp@-		|  put vector # on stack
+user_irqhandler_fixup = . + 2
+	jsr	m68k_handle_int		|  process the IRQ
+	addql	#8,%sp			|  pop parameters off stack
+
+	subqb	#1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+	jeq	ret_from_last_interrupt
+	RESTORE_ALL
 
 /* Handler for uninitialized and spurious interrupts */
 
-bad_interrupt:
-	addql	#1,num_spurious
-	rte
+ENTRY(bad_inthandler)
+	SAVE_ALL_INT
+	GET_CURRENT(%d0)
+	addqb	#1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+
+	movel	%sp,%sp@-
+	jsr	handle_badint
+	addql	#4,%sp
+
+	subqb	#1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+	jeq	ret_from_last_interrupt
+	RESTORE_ALL
+
 
 ENTRY(sys_fork)
 	SAVE_SWITCH_STACK
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 4b85514..5a8344b 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -39,47 +39,40 @@
 #include <asm/traps.h>
 #include <asm/page.h>
 #include <asm/machdep.h>
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_Q40
 #include <asm/q40ints.h>
 #endif
 
-/* table for system interrupt handlers */
-static irq_handler_t irq_list[SYS_IRQS];
+extern u32 auto_irqhandler_fixup[];
+extern u32 user_irqhandler_fixup[];
+extern u16 user_irqvec_fixup[];
 
-static const char *default_names[SYS_IRQS] = {
-	[0] = "spurious int",
-	[1] = "int1 handler",
-	[2] = "int2 handler",
-	[3] = "int3 handler",
-	[4] = "int4 handler",
-	[5] = "int5 handler",
-	[6] = "int6 handler",
-	[7] = "int7 handler"
+/* table for system interrupt handlers */
+static struct irq_node *irq_list[NR_IRQS];
+static struct irq_controller *irq_controller[NR_IRQS];
+static int irq_depth[NR_IRQS];
+
+static int m68k_first_user_vec;
+
+static struct irq_controller auto_irq_controller = {
+	.name		= "auto",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.startup	= m68k_irq_startup,
+	.shutdown	= m68k_irq_shutdown,
 };
 
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
+static struct irq_controller user_irq_controller = {
+	.name		= "user",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.startup	= m68k_irq_startup,
+	.shutdown	= m68k_irq_shutdown,
+};
 
 #define NUM_IRQ_NODES 100
 static irq_node_t nodes[NUM_IRQ_NODES];
 
-static void dummy_enable_irq(unsigned int irq);
-static void dummy_disable_irq(unsigned int irq);
-static int dummy_request_irq(unsigned int irq,
-		irqreturn_t (*handler) (int, void *, struct pt_regs *),
-		unsigned long flags, const char *devname, void *dev_id);
-static void dummy_free_irq(unsigned int irq, void *dev_id);
-
-void (*enable_irq) (unsigned int) = dummy_enable_irq;
-void (*disable_irq) (unsigned int) = dummy_disable_irq;
-
-int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *),
-                      unsigned long, const char *, void *) = dummy_request_irq;
-void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
-
-void init_irq_proc(void);
-
 /*
  * void init_IRQ(void)
  *
@@ -101,18 +94,70 @@
 		hardirq_mask_is_broken();
 	}
 
-	for (i = 0; i < SYS_IRQS; i++) {
-		if (mach_default_handler)
-			irq_list[i].handler = (*mach_default_handler)[i];
-		irq_list[i].flags   = 0;
-		irq_list[i].dev_id  = NULL;
-		irq_list[i].devname = default_names[i];
-	}
+	for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
+		irq_controller[i] = &auto_irq_controller;
 
-	for (i = 0; i < NUM_IRQ_NODES; i++)
-		nodes[i].handler = NULL;
+	mach_init_IRQ();
+}
 
-	mach_init_IRQ ();
+/**
+ * m68k_setup_auto_interrupt
+ * @handler: called from auto vector interrupts
+ *
+ * setup the handler to be called from auto vector interrupts instead of the
+ * standard m68k_handle_int(), it will be called with irq numbers in the range
+ * from IRQ_AUTO_1 - IRQ_AUTO_7.
+ */
+void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
+{
+	if (handler)
+		*auto_irqhandler_fixup = (u32)handler;
+	flush_icache();
+}
+
+/**
+ * m68k_setup_user_interrupt
+ * @vec: first user vector interrupt to handle
+ * @cnt: number of active user vector interrupts
+ * @handler: called from user vector interrupts
+ *
+ * setup user vector interrupts, this includes activating the specified range
+ * of interrupts, only then these interrupts can be requested (note: this is
+ * different from auto vector interrupts). An optional handler can be installed
+ * to be called instead of the default m68k_handle_int(), it will be called
+ * with irq numbers starting from IRQ_USER.
+ */
+void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+				      void (*handler)(unsigned int, struct pt_regs *))
+{
+	int i;
+
+	m68k_first_user_vec = vec;
+	for (i = 0; i < cnt; i++)
+		irq_controller[IRQ_USER + i] = &user_irq_controller;
+	*user_irqvec_fixup = vec - IRQ_USER;
+	if (handler)
+		*user_irqhandler_fixup = (u32)handler;
+	flush_icache();
+}
+
+/**
+ * m68k_setup_irq_controller
+ * @contr: irq controller which controls specified irq
+ * @irq: first irq to be managed by the controller
+ *
+ * Change the controller for the specified range of irq, which will be used to
+ * manage these irq. auto/user irq already have a default controller, which can
+ * be changed as well, but the controller probably should use m68k_irq_startup/
+ * m68k_irq_shutdown.
+ */
+void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq,
+			       unsigned int cnt)
+{
+	int i;
+
+	for (i = 0; i < cnt; i++)
+		irq_controller[irq + i] = contr;
 }
 
 irq_node_t *new_irq_node(void)
@@ -120,84 +165,183 @@
 	irq_node_t *node;
 	short i;
 
-	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-		if (!node->handler)
+	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) {
+		if (!node->handler) {
+			memset(node, 0, sizeof(*node));
 			return node;
+		}
+	}
 
 	printk ("new_irq_node: out of nodes\n");
 	return NULL;
 }
 
-/*
- * We will keep these functions until I have convinced Linus to move
- * the declaration of them from include/linux/sched.h to
- * include/asm/irq.h.
- */
+int setup_irq(unsigned int irq, struct irq_node *node)
+{
+	struct irq_controller *contr;
+	struct irq_node **prev;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+		printk("%s: Incorrect IRQ %d from %s\n",
+		       __FUNCTION__, irq, node->devname);
+		return -ENXIO;
+	}
+
+	spin_lock_irqsave(&contr->lock, flags);
+
+	prev = irq_list + irq;
+	if (*prev) {
+		/* Can't share interrupts unless both agree to */
+		if (!((*prev)->flags & node->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&contr->lock, flags);
+			return -EBUSY;
+		}
+		while (*prev)
+			prev = &(*prev)->next;
+	}
+
+	if (!irq_list[irq]) {
+		if (contr->startup)
+			contr->startup(irq);
+		else
+			contr->enable(irq);
+	}
+	node->next = NULL;
+	*prev = node;
+
+	spin_unlock_irqrestore(&contr->lock, flags);
+
+	return 0;
+}
+
 int request_irq(unsigned int irq,
 		irqreturn_t (*handler) (int, void *, struct pt_regs *),
 		unsigned long flags, const char *devname, void *dev_id)
 {
-	return mach_request_irq(irq, handler, flags, devname, dev_id);
+	struct irq_node *node;
+	int res;
+
+	node = new_irq_node();
+	if (!node)
+		return -ENOMEM;
+
+	node->handler = handler;
+	node->flags   = flags;
+	node->dev_id  = dev_id;
+	node->devname = devname;
+
+	res = setup_irq(irq, node);
+	if (res)
+		node->handler = NULL;
+
+	return res;
 }
 
 EXPORT_SYMBOL(request_irq);
 
 void free_irq(unsigned int irq, void *dev_id)
 {
-	mach_free_irq(irq, dev_id);
-}
+	struct irq_controller *contr;
+	struct irq_node **p, *node;
+	unsigned long flags;
 
-EXPORT_SYMBOL(free_irq);
-
-int cpu_request_irq(unsigned int irq,
-                    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-	if (irq < IRQ1 || irq > IRQ7) {
-		printk("%s: Incorrect IRQ %d from %s\n",
-		       __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-
-#if 0
-	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_list[irq].devname);
-			return -EBUSY;
-		}
-		if (!(flags & IRQ_FLG_REPLACE)) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_list[irq].devname);
-			return -EBUSY;
-		}
-	}
-#endif
-
-	irq_list[irq].handler = handler;
-	irq_list[irq].flags   = flags;
-	irq_list[irq].dev_id  = dev_id;
-	irq_list[irq].devname = devname;
-	return 0;
-}
-
-void cpu_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq < IRQ1 || irq > IRQ7) {
+	if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
 		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
 		return;
 	}
 
-	if (irq_list[irq].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_list[irq].devname);
+	spin_lock_irqsave(&contr->lock, flags);
 
-	irq_list[irq].handler = (*mach_default_handler)[irq];
-	irq_list[irq].flags   = 0;
-	irq_list[irq].dev_id  = NULL;
-	irq_list[irq].devname = default_names[irq];
+	p = irq_list + irq;
+	while ((node = *p)) {
+		if (node->dev_id == dev_id)
+			break;
+		p = &node->next;
+	}
+
+	if (node) {
+		*p = node->next;
+		node->handler = NULL;
+	} else
+		printk("%s: Removing probably wrong IRQ %d\n",
+		       __FUNCTION__, irq);
+
+	if (!irq_list[irq]) {
+		if (contr->shutdown)
+			contr->shutdown(irq);
+		else
+			contr->disable(irq);
+	}
+
+	spin_unlock_irqrestore(&contr->lock, flags);
 }
 
+EXPORT_SYMBOL(free_irq);
+
+void enable_irq(unsigned int irq)
+{
+	struct irq_controller *contr;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+		printk("%s: Incorrect IRQ %d\n",
+		       __FUNCTION__, irq);
+		return;
+	}
+
+	spin_lock_irqsave(&contr->lock, flags);
+	if (irq_depth[irq]) {
+		if (!--irq_depth[irq]) {
+			if (contr->enable)
+				contr->enable(irq);
+		}
+	} else
+		WARN_ON(1);
+	spin_unlock_irqrestore(&contr->lock, flags);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
+void disable_irq(unsigned int irq)
+{
+	struct irq_controller *contr;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS || !(contr = irq_controller[irq])) {
+		printk("%s: Incorrect IRQ %d\n",
+		       __FUNCTION__, irq);
+		return;
+	}
+
+	spin_lock_irqsave(&contr->lock, flags);
+	if (!irq_depth[irq]++) {
+		if (contr->disable)
+			contr->disable(irq);
+	}
+	spin_unlock_irqrestore(&contr->lock, flags);
+}
+
+EXPORT_SYMBOL(disable_irq);
+
+int m68k_irq_startup(unsigned int irq)
+{
+	if (irq <= IRQ_AUTO_7)
+		vectors[VEC_SPUR + irq] = auto_inthandler;
+	else
+		vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler;
+	return 0;
+}
+
+void m68k_irq_shutdown(unsigned int irq)
+{
+	if (irq <= IRQ_AUTO_7)
+		vectors[VEC_SPUR + irq] = bad_inthandler;
+	else
+		vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
+}
+
+
 /*
  * Do we need these probe functions on the m68k?
  *
@@ -225,58 +369,50 @@
 
 EXPORT_SYMBOL(probe_irq_off);
 
-static void dummy_enable_irq(unsigned int irq)
+unsigned int irq_canonicalize(unsigned int irq)
 {
-	printk("calling uninitialized enable_irq()\n");
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40 && irq == 11)
+		irq = 10;
+#endif
+	return irq;
 }
 
-static void dummy_disable_irq(unsigned int irq)
+EXPORT_SYMBOL(irq_canonicalize);
+
+asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs)
 {
-	printk("calling uninitialized disable_irq()\n");
+	struct irq_node *node;
+
+	kstat_cpu(0).irqs[irq]++;
+	node = irq_list[irq];
+	do {
+		node->handler(irq, node->dev_id, regs);
+		node = node->next;
+	} while (node);
 }
 
-static int dummy_request_irq(unsigned int irq,
-		irqreturn_t (*handler) (int, void *, struct pt_regs *),
-		unsigned long flags, const char *devname, void *dev_id)
+asmlinkage void handle_badint(struct pt_regs *regs)
 {
-	printk("calling uninitialized request_irq()\n");
-	return 0;
-}
-
-static void dummy_free_irq(unsigned int irq, void *dev_id)
-{
-	printk("calling uninitialized disable_irq()\n");
-}
-
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
-{
-	if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
-		vec -= VEC_SPUR;
-		kstat_cpu(0).irqs[vec]++;
-		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
-	} else {
-		if (mach_process_int)
-			mach_process_int(vec, fp);
-		else
-			panic("Can't process interrupt vector %ld\n", vec);
-		return;
-	}
+	kstat_cpu(0).irqs[0]++;
+	printk("unexpected interrupt from %u\n", regs->vector);
 }
 
 int show_interrupts(struct seq_file *p, void *v)
 {
+	struct irq_controller *contr;
+	struct irq_node *node;
 	int i = *(loff_t *) v;
 
 	/* autovector interrupts */
-	if (i < SYS_IRQS) {
-		if (mach_default_handler) {
-			seq_printf(p, "auto %2d: %10u ", i,
-			               i ? kstat_cpu(0).irqs[i] : num_spurious);
-			seq_puts(p, "  ");
-			seq_printf(p, "%s\n", irq_list[i].devname);
-		}
-	} else if (i == SYS_IRQS)
-		mach_get_irq_list(p, v);
+	if (irq_list[i]) {
+		contr = irq_controller[i];
+		node = irq_list[i];
+		seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname);
+		while ((node = node->next))
+			seq_printf(p, ", %s", node->devname);
+		seq_puts(p, "\n");
+	}
 	return 0;
 }
 
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 5b7952e..1f5e1b5 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -57,8 +57,6 @@
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_thread);
 #ifdef CONFIG_VME
 EXPORT_SYMBOL(vme_brdtype);
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 750d5b3..214a95f 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -68,11 +68,8 @@
 void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata = NULL;
-irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
 void (*mach_get_model) (char *model);
 int (*mach_get_hardware_list) (char *buffer);
-int (*mach_get_irq_list) (struct seq_file *, void *);
-irqreturn_t (*mach_process_int) (int, struct pt_regs *);
 /* machine dependent timer functions */
 unsigned long (*mach_gettimeoffset) (void);
 int (*mach_hwclk) (int, struct rtc_time*);
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 837a887..e86de7b 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -45,7 +45,6 @@
 asmlinkage void system_call(void);
 asmlinkage void buserr(void);
 asmlinkage void trap(void);
-asmlinkage void inthandler(void);
 asmlinkage void nmihandler(void);
 #ifdef CONFIG_M68KFPU_EMU
 asmlinkage void fpu_emu(void);
@@ -53,51 +52,7 @@
 
 e_vector vectors[256] = {
 	[VEC_BUSERR]	= buserr,
-	[VEC_ADDRERR]	= trap,
-	[VEC_ILLEGAL]	= trap,
-	[VEC_ZERODIV]	= trap,
-	[VEC_CHK]	= trap,
-	[VEC_TRAP]	= trap,
-	[VEC_PRIV]	= trap,
-	[VEC_TRACE]	= trap,
-	[VEC_LINE10]	= trap,
-	[VEC_LINE11]	= trap,
-	[VEC_RESV12]	= trap,
-	[VEC_COPROC]	= trap,
-	[VEC_FORMAT]	= trap,
-	[VEC_UNINT]	= trap,
-	[VEC_RESV16]	= trap,
-	[VEC_RESV17]	= trap,
-	[VEC_RESV18]	= trap,
-	[VEC_RESV19]	= trap,
-	[VEC_RESV20]	= trap,
-	[VEC_RESV21]	= trap,
-	[VEC_RESV22]	= trap,
-	[VEC_RESV23]	= trap,
-	[VEC_SPUR]	= inthandler,
-	[VEC_INT1]	= inthandler,
-	[VEC_INT2]	= inthandler,
-	[VEC_INT3]	= inthandler,
-	[VEC_INT4]	= inthandler,
-	[VEC_INT5]	= inthandler,
-	[VEC_INT6]	= inthandler,
-	[VEC_INT7]	= inthandler,
 	[VEC_SYS]	= system_call,
-	[VEC_TRAP1]	= trap,
-	[VEC_TRAP2]	= trap,
-	[VEC_TRAP3]	= trap,
-	[VEC_TRAP4]	= trap,
-	[VEC_TRAP5]	= trap,
-	[VEC_TRAP6]	= trap,
-	[VEC_TRAP7]	= trap,
-	[VEC_TRAP8]	= trap,
-	[VEC_TRAP9]	= trap,
-	[VEC_TRAP10]	= trap,
-	[VEC_TRAP11]	= trap,
-	[VEC_TRAP12]	= trap,
-	[VEC_TRAP13]	= trap,
-	[VEC_TRAP14]	= trap,
-	[VEC_TRAP15]	= trap,
 };
 
 /* nmi handler for the Amiga */
@@ -132,12 +87,15 @@
 {
 	int i;
 
-	for (i = 48; i < 64; i++)
+	for (i = VEC_SPUR; i <= VEC_INT7; i++)
+		vectors[i] = bad_inthandler;
+
+	for (i = 0; i < VEC_USER; i++)
 		if (!vectors[i])
 			vectors[i] = trap;
 
-	for (i = 64; i < 256; i++)
-		vectors[i] = inthandler;
+	for (i = VEC_USER; i < 256; i++)
+		vectors[i] = bad_inthandler;
 
 #ifdef CONFIG_M68KFPU_EMU
 	if (FPU_IS_EMU)
@@ -927,66 +885,88 @@
 void show_registers(struct pt_regs *regs)
 {
 	struct frame *fp = (struct frame *)regs;
+	mm_segment_t old_fs = get_fs();
+	u16 c, *cp;
 	unsigned long addr;
 	int i;
 
+	print_modules();
+	printk("PC: [<%08lx>]",regs->pc);
+	print_symbol(" %s", regs->pc);
+	printk("\nSR: %04x  SP: %p  a2: %08lx\n",
+	       regs->sr, regs, regs->a2);
+	printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
+	       regs->d0, regs->d1, regs->d2, regs->d3);
+	printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
+	       regs->d4, regs->d5, regs->a0, regs->a1);
+
+	printk("Process %s (pid: %d, task=%p)\n",
+		current->comm, current->pid, current);
 	addr = (unsigned long)&fp->un;
-	printk("Frame format=%X ", fp->ptregs.format);
-	switch (fp->ptregs.format) {
+	printk("Frame format=%X ", regs->format);
+	switch (regs->format) {
 	case 0x2:
-	    printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
-	    addr += sizeof(fp->un.fmt2);
-	    break;
+		printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
+		addr += sizeof(fp->un.fmt2);
+		break;
 	case 0x3:
-	    printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
-	    addr += sizeof(fp->un.fmt3);
-	    break;
+		printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
+		addr += sizeof(fp->un.fmt3);
+		break;
 	case 0x4:
-	    printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
-		    : "eff addr=%08lx pc=%08lx\n"),
-		   fp->un.fmt4.effaddr, fp->un.fmt4.pc);
-	    addr += sizeof(fp->un.fmt4);
-	    break;
+		printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
+			: "eff addr=%08lx pc=%08lx\n"),
+			fp->un.fmt4.effaddr, fp->un.fmt4.pc);
+		addr += sizeof(fp->un.fmt4);
+		break;
 	case 0x7:
-	    printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
-		   fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
-	    printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
-		   fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
-	    printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
-		   fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
-	    printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
-		   fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
-	    printk("push data: %08lx %08lx %08lx %08lx\n",
-		   fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
-		   fp->un.fmt7.pd3);
-	    addr += sizeof(fp->un.fmt7);
-	    break;
+		printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
+			fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
+		printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
+			fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
+		printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
+			fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
+		printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
+			fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
+		printk("push data: %08lx %08lx %08lx %08lx\n",
+			fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
+			fp->un.fmt7.pd3);
+		addr += sizeof(fp->un.fmt7);
+		break;
 	case 0x9:
-	    printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
-	    addr += sizeof(fp->un.fmt9);
-	    break;
+		printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
+		addr += sizeof(fp->un.fmt9);
+		break;
 	case 0xa:
-	    printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
-		   fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
-		   fp->un.fmta.daddr, fp->un.fmta.dobuf);
-	    addr += sizeof(fp->un.fmta);
-	    break;
+		printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+			fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
+			fp->un.fmta.daddr, fp->un.fmta.dobuf);
+		addr += sizeof(fp->un.fmta);
+		break;
 	case 0xb:
-	    printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
-		   fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
-		   fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
-	    printk("baddr=%08lx dibuf=%08lx ver=%x\n",
-		   fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
-	    addr += sizeof(fp->un.fmtb);
-	    break;
+		printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+			fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
+			fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
+		printk("baddr=%08lx dibuf=%08lx ver=%x\n",
+			fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
+		addr += sizeof(fp->un.fmtb);
+		break;
 	default:
-	    printk("\n");
+		printk("\n");
 	}
 	show_stack(NULL, (unsigned long *)addr);
 
-	printk("Code: ");
-	for (i = 0; i < 10; i++)
-		printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
+	printk("Code:");
+	set_fs(KERNEL_DS);
+	cp = (u16 *)regs->pc;
+	for (i = -8; i < 16; i++) {
+		if (get_user(c, cp + i) && i >= 0) {
+			printk(" Bad PC value.");
+			break;
+		}
+		printk(i ? " %04x" : " <%04x>", c);
+	}
+	set_fs(old_fs);
 	printk ("\n");
 }
 
@@ -1190,19 +1170,7 @@
 
 	console_verbose();
 	printk("%s: %08x\n",str,nr);
-	print_modules();
-	printk("PC: [<%08lx>]",fp->pc);
-	print_symbol(" %s\n", fp->pc);
-	printk("\nSR: %04x  SP: %p  a2: %08lx\n",
-	       fp->sr, fp, fp->a2);
-	printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-	       fp->d0, fp->d1, fp->d2, fp->d3);
-	printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-	       fp->d4, fp->d5, fp->a0, fp->a1);
-
-	printk("Process %s (pid: %d, stackpage=%08lx)\n",
-		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
-	show_stack(NULL, (unsigned long *)fp);
+	show_registers(fp);
 	do_exit(SIGSEGV);
 }
 
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index b19b7dd..6eaa881 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -81,7 +81,7 @@
 	for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
 	        if (events & irq_bit/* & baboon_active*/) {
 			baboon_active &= ~irq_bit;
-			mac_do_irq_list(IRQ_BABOON_0 + i, regs);
+			m68k_handle_int(IRQ_BABOON_0 + i, regs);
 			baboon_active |= irq_bit;
 			baboon->mb_ifr &= ~irq_bit;
 		}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 19dce75..5a9990e 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -94,20 +94,6 @@
 	via_init_clock(vector);
 }
 
-extern irqreturn_t mac_default_handler(int, void *, struct pt_regs *);
-
-irqreturn_t (*mac_handlers[8])(int, void *, struct pt_regs *)=
-{
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler
-};
-
 /*
  * Parse a Macintosh-specific record in the bootinfo
  */
@@ -183,13 +169,7 @@
 
 	mach_sched_init      = mac_sched_init;
 	mach_init_IRQ        = mac_init_IRQ;
-	mach_request_irq     = mac_request_irq;
-	mach_free_irq        = mac_free_irq;
-	enable_irq           = mac_enable_irq;
-	disable_irq          = mac_disable_irq;
 	mach_get_model	 = mac_get_model;
-	mach_default_handler = &mac_handlers;
-	mach_get_irq_list    = show_mac_interrupts;
 	mach_gettimeoffset   = mac_gettimeoffset;
 #warning move to adb/via init
 #if 0
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
index 9179a37..4c8ece7 100644
--- a/arch/m68k/mac/iop.c
+++ b/arch/m68k/mac/iop.c
@@ -317,7 +317,7 @@
 {
 	if (iop_ism_present) {
 		if (oss_present) {
-			cpu_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+			request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
 					IRQ_FLG_LOCK, "ISM IOP",
 					(void *) IOP_NUM_ISM);
 			oss_irq_enable(IRQ_MAC_ADB);
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 7a1600b..694b14b 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -137,14 +137,6 @@
 #define DEBUG_SPURIOUS
 #define SHUTUP_SONIC
 
-/*
- * The mac_irq_list array is an array of linked lists of irq_node_t nodes.
- * Each node contains one handler to be called whenever the interrupt
- * occurs, with fast handlers listed before slow handlers.
- */
-
-irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
-
 /* SCC interrupt mask */
 
 static int scc_mask;
@@ -209,8 +201,8 @@
  * SCC interrupt routines
  */
 
-static void scc_irq_enable(int);
-static void scc_irq_disable(int);
+static void scc_irq_enable(unsigned int);
+static void scc_irq_disable(unsigned int);
 
 /*
  * console_loglevel determines NMI handler function
@@ -221,21 +213,25 @@
 
 /* #define DEBUG_MACINTS */
 
+static void mac_enable_irq(unsigned int irq);
+static void mac_disable_irq(unsigned int irq);
+
+static struct irq_controller mac_irq_controller = {
+	.name		= "mac",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.enable		= mac_enable_irq,
+	.disable	= mac_disable_irq,
+};
+
 void mac_init_IRQ(void)
 {
-        int i;
-
 #ifdef DEBUG_MACINTS
 	printk("mac_init_IRQ(): Setting things up...\n");
 #endif
-	/* Initialize the IRQ handler lists. Initially each list is empty, */
-
-	for (i = 0; i < NUM_MAC_SOURCES; i++) {
-		mac_irq_list[i] = NULL;
-	}
-
 	scc_mask = 0;
 
+	m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,
+				  NUM_MAC_SOURCES - IRQ_USER);
 	/* Make sure the SONIC interrupt is cleared or things get ugly */
 #ifdef SHUTUP_SONIC
 	printk("Killing onboard sonic... ");
@@ -252,15 +248,16 @@
 	 * at levels 1-7. Most of the work is done elsewhere.
 	 */
 
-	if (oss_present) {
+	if (oss_present)
 		oss_register_interrupts();
-	} else {
+	else
 		via_register_interrupts();
-	}
-	if (psc_present) psc_register_interrupts();
-	if (baboon_present) baboon_register_interrupts();
+	if (psc_present)
+		psc_register_interrupts();
+	if (baboon_present)
+		baboon_register_interrupts();
 	iop_register_interrupts();
-	cpu_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI",
+	request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",
 			mac_nmi_handler);
 #ifdef DEBUG_MACINTS
 	printk("mac_init_IRQ(): Done!\n");
@@ -268,104 +265,6 @@
 }
 
 /*
- * Routines to work with irq_node_t's on linked lists lifted from
- * the Amiga code written by Roman Zippel.
- */
-
-static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-	unsigned long flags;
-	irq_node_t *cur;
-
-	if (!node->dev_id)
-		printk("%s: Warning: dev_id of %s is zero\n",
-		       __FUNCTION__, node->devname);
-
-	local_irq_save(flags);
-
-	cur = *list;
-
-	if (node->flags & IRQ_FLG_FAST) {
-		node->flags &= ~IRQ_FLG_SLOW;
-		while (cur && cur->flags & IRQ_FLG_FAST) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else if (node->flags & IRQ_FLG_SLOW) {
-		while (cur) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	} else {
-		while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
-			list = &cur->next;
-			cur = cur->next;
-		}
-	}
-
-	node->next = cur;
-	*list = node;
-
-	local_irq_restore(flags);
-}
-
-static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
-{
-	unsigned long flags;
-	irq_node_t *node;
-
-	local_irq_save(flags);
-
-	for (node = *list; node; list = &node->next, node = *list) {
-		if (node->dev_id == dev_id) {
-			*list = node->next;
-			/* Mark it as free. */
-			node->handler = NULL;
-			local_irq_restore(flags);
-			return;
-		}
-	}
-	local_irq_restore(flags);
-	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
-}
-
-/*
- * Call all the handlers for a given interrupt. Fast handlers are called
- * first followed by slow handlers.
- *
- * This code taken from the original Amiga code written by Roman Zippel.
- */
-
-void mac_do_irq_list(int irq, struct pt_regs *fp)
-{
-	irq_node_t *node, *slow_nodes;
-	unsigned long flags;
-
-	kstat_cpu(0).irqs[irq]++;
-
-#ifdef DEBUG_SPURIOUS
-	if (!mac_irq_list[irq] && (console_loglevel > 7)) {
-		printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
-		return;
-	}
-#endif
-
-	/* serve first fast and normal handlers */
-	for (node = mac_irq_list[irq];
-	     node && (!(node->flags & IRQ_FLG_SLOW));
-	     node = node->next)
-		node->handler(irq, node->dev_id, fp);
-	if (!node) return;
-	local_save_flags(flags);
-	local_irq_restore((flags & ~0x0700) | (fp->sr & 0x0700));
-	/* if slow handlers exists, serve them now */
-	slow_nodes = node;
-	for (; node; node = node->next) {
-		node->handler(irq, node->dev_id, fp);
-	}
-}
-
-/*
  *  mac_enable_irq - enable an interrupt source
  * mac_disable_irq - disable an interrupt source
  *   mac_clear_irq - clears a pending interrupt
@@ -374,276 +273,124 @@
  * These routines are just dispatchers to the VIA/OSS/PSC routines.
  */
 
-void mac_enable_irq (unsigned int irq)
+static void mac_enable_irq(unsigned int irq)
 {
-	int irq_src	= IRQ_SRC(irq);
+	int irq_src = IRQ_SRC(irq);
 
 	switch(irq_src) {
-		case 1: via_irq_enable(irq);
-			break;
-		case 2:
-		case 7: if (oss_present) {
-				oss_irq_enable(irq);
-			} else {
-				via_irq_enable(irq);
-			}
-			break;
-		case 3:
-		case 4:
-		case 5:
-		case 6: if (psc_present) {
-				psc_irq_enable(irq);
-			} else if (oss_present) {
-				oss_irq_enable(irq);
-			} else if (irq_src == 4) {
-				scc_irq_enable(irq);
-			}
-			break;
-		case 8: if (baboon_present) {
-				baboon_irq_enable(irq);
-			}
-			break;
+	case 1:
+		via_irq_enable(irq);
+		break;
+	case 2:
+	case 7:
+		if (oss_present)
+			oss_irq_enable(irq);
+		else
+			via_irq_enable(irq);
+		break;
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		if (psc_present)
+			psc_irq_enable(irq);
+		else if (oss_present)
+			oss_irq_enable(irq);
+		else if (irq_src == 4)
+			scc_irq_enable(irq);
+		break;
+	case 8:
+		if (baboon_present)
+			baboon_irq_enable(irq);
+		break;
 	}
 }
 
-void mac_disable_irq (unsigned int irq)
+static void mac_disable_irq(unsigned int irq)
 {
-	int irq_src	= IRQ_SRC(irq);
+	int irq_src = IRQ_SRC(irq);
 
 	switch(irq_src) {
-		case 1: via_irq_disable(irq);
-			break;
-		case 2:
-		case 7: if (oss_present) {
-				oss_irq_disable(irq);
-			} else {
-				via_irq_disable(irq);
-			}
-			break;
-		case 3:
-		case 4:
-		case 5:
-		case 6: if (psc_present) {
-				psc_irq_disable(irq);
-			} else if (oss_present) {
-				oss_irq_disable(irq);
-			} else if (irq_src == 4) {
-				scc_irq_disable(irq);
-			}
-			break;
-		case 8: if (baboon_present) {
-				baboon_irq_disable(irq);
-			}
-			break;
+	case 1:
+		via_irq_disable(irq);
+		break;
+	case 2:
+	case 7:
+		if (oss_present)
+			oss_irq_disable(irq);
+		else
+			via_irq_disable(irq);
+		break;
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		if (psc_present)
+			psc_irq_disable(irq);
+		else if (oss_present)
+			oss_irq_disable(irq);
+		else if (irq_src == 4)
+			scc_irq_disable(irq);
+		break;
+	case 8:
+		if (baboon_present)
+			baboon_irq_disable(irq);
+		break;
 	}
 }
 
-void mac_clear_irq( unsigned int irq )
+void mac_clear_irq(unsigned int irq)
 {
 	switch(IRQ_SRC(irq)) {
-		case 1: via_irq_clear(irq);
-			break;
-		case 2:
-		case 7: if (oss_present) {
-				oss_irq_clear(irq);
-			} else {
-				via_irq_clear(irq);
-			}
-			break;
-		case 3:
-		case 4:
-		case 5:
-		case 6: if (psc_present) {
-				psc_irq_clear(irq);
-			} else if (oss_present) {
-				oss_irq_clear(irq);
-			}
-			break;
-		case 8: if (baboon_present) {
-				baboon_irq_clear(irq);
-			}
-			break;
+	case 1:
+		via_irq_clear(irq);
+		break;
+	case 2:
+	case 7:
+		if (oss_present)
+			oss_irq_clear(irq);
+		else
+			via_irq_clear(irq);
+		break;
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		if (psc_present)
+			psc_irq_clear(irq);
+		else if (oss_present)
+			oss_irq_clear(irq);
+		break;
+	case 8:
+		if (baboon_present)
+			baboon_irq_clear(irq);
+		break;
 	}
 }
 
-int mac_irq_pending( unsigned int irq )
+int mac_irq_pending(unsigned int irq)
 {
 	switch(IRQ_SRC(irq)) {
-		case 1: return via_irq_pending(irq);
-		case 2:
-		case 7: if (oss_present) {
-				return oss_irq_pending(irq);
-			} else {
-				return via_irq_pending(irq);
-			}
-		case 3:
-		case 4:
-		case 5:
-		case 6: if (psc_present) {
-				return psc_irq_pending(irq);
-			} else if (oss_present) {
-				return oss_irq_pending(irq);
-			}
+	case 1:
+		return via_irq_pending(irq);
+	case 2:
+	case 7:
+		if (oss_present)
+			return oss_irq_pending(irq);
+		else
+			return via_irq_pending(irq);
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		if (psc_present)
+			return psc_irq_pending(irq);
+		else if (oss_present)
+			return oss_irq_pending(irq);
 	}
 	return 0;
 }
 
-/*
- * Add an interrupt service routine to an interrupt source.
- * Returns 0 on success.
- *
- * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
- *        non-PSC machine). We should return -EINVAL in those cases.
- */
-
-int mac_request_irq(unsigned int irq,
-		    irqreturn_t (*handler)(int, void *, struct pt_regs *),
-		    unsigned long flags, const char *devname, void *dev_id)
-{
-	irq_node_t *node;
-
-#ifdef DEBUG_MACINTS
-	printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
-#endif
-
-	if (irq < VIA1_SOURCE_BASE) {
-		return cpu_request_irq(irq, handler, flags, devname, dev_id);
-	}
-
-	if (irq >= NUM_MAC_SOURCES) {
-		printk ("%s: unknown irq %d requested by %s\n",
-		        __FUNCTION__, irq, devname);
-	}
-
-	/* Get a node and stick it onto the right list */
-
-	if (!(node = new_irq_node())) return -ENOMEM;
-
-	node->handler	= handler;
-	node->flags	= flags;
-	node->dev_id	= dev_id;
-	node->devname	= devname;
-	node->next	= NULL;
-	mac_insert_irq(&mac_irq_list[irq], node);
-
-	/* Now enable the IRQ source */
-
-	mac_enable_irq(irq);
-
-	return 0;
-}
-
-/*
- * Removes an interrupt service routine from an interrupt source.
- */
-
-void mac_free_irq(unsigned int irq, void *dev_id)
-{
-#ifdef DEBUG_MACINTS
-	printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
-#endif
-
-	if (irq < VIA1_SOURCE_BASE) {
-		cpu_free_irq(irq, dev_id);
-		return;
-	}
-
-	if (irq >= NUM_MAC_SOURCES) {
-		printk ("%s: unknown irq %d freed\n",
-		        __FUNCTION__, irq);
-		return;
-	}
-
-	mac_delete_irq(&mac_irq_list[irq], dev_id);
-
-	/* If the list for this interrupt is */
-	/* empty then disable the source.    */
-
-	if (!mac_irq_list[irq]) {
-		mac_disable_irq(irq);
-	}
-}
-
-/*
- * Generate a pretty listing for /proc/interrupts
- *
- * By the time we're called the autovector interrupt list has already been
- * generated, so we just need to do the machspec interrupts.
- *
- * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers.
- *                Also removed display of num_spurious it is already
- *		  displayed for us as autovector irq 0.
- */
-
-int show_mac_interrupts(struct seq_file *p, void *v)
-{
-	int i;
-	irq_node_t *node;
-	char *base;
-
-	/* Don't do Nubus interrupts in this loop; we do them separately  */
-	/* below so that we can print slot numbers instead of IRQ numbers */
-
-	for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) {
-
-		/* Nonexistant interrupt or nothing registered; skip it. */
-
-		if ((node = mac_irq_list[i]) == NULL) continue;
-		if (node->flags & IRQ_FLG_STD) continue;
-
-		base = "";
-		switch(IRQ_SRC(i)) {
-			case 1: base = "via1";
-				break;
-			case 2: if (oss_present) {
-					base = "oss";
-				} else {
-					base = "via2";
-				}
-				break;
-			case 3:
-			case 4:
-			case 5:
-			case 6: if (psc_present) {
-					base = "psc";
-				} else if (oss_present) {
-					base = "oss";
-				} else {
-					if (IRQ_SRC(i) == 4) base = "scc";
-				}
-				break;
-			case 7: base = "nbus";
-				break;
-			case 8: base = "bbn";
-				break;
-		}
-		seq_printf(p, "%4s %2d: %10u ", base, i, kstat_cpu(0).irqs[i]);
-
-		do {
-			if (node->flags & IRQ_FLG_FAST) {
-				seq_puts(p, "F ");
-			} else if (node->flags & IRQ_FLG_SLOW) {
-				seq_puts(p, "S ");
-			} else {
-				seq_puts(p, "  ");
-			}
-			seq_printf(p, "%s\n", node->devname);
-			if ((node = node->next)) {
-				seq_puts(p, "                    ");
-			}
-		} while(node);
-
-	}
-	return 0;
-}
-
-void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
-	printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
-#endif
-}
-
 static int num_debug[8];
 
 irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
@@ -683,7 +430,7 @@
 	while (nmi_hold == 1)
 		udelay(1000);
 
-	if ( console_loglevel >= 8 ) {
+	if (console_loglevel >= 8) {
 #if 0
 		show_state();
 		printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
@@ -712,14 +459,16 @@
  * done in hardware (only the PSC can do that.)
  */
 
-static void scc_irq_enable(int irq) {
-	int irq_idx     = IRQ_IDX(irq);
+static void scc_irq_enable(unsigned int irq)
+{
+	int irq_idx = IRQ_IDX(irq);
 
 	scc_mask |= (1 << irq_idx);
 }
 
-static void scc_irq_disable(int irq) {
-	int irq_idx     = IRQ_IDX(irq);
+static void scc_irq_disable(unsigned int irq)
+{
+	int irq_idx = IRQ_IDX(irq);
 
 	scc_mask &= ~(1 << irq_idx);
 }
@@ -754,6 +503,8 @@
 	/* and since they're autovector interrupts they */
 	/* pretty much kill the system.                 */
 
-	if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs);
-	if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs);
+	if (reg & 0x38)
+		m68k_handle_int(IRQ_SCCA, regs);
+	if (reg & 0x07)
+		m68k_handle_int(IRQ_SCCB, regs);
 }
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 3335476..63e0436 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -67,15 +67,15 @@
 
 void __init oss_register_interrupts(void)
 {
-	cpu_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+	request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
 			"scsi", (void *) oss);
-	cpu_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
+	request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
 			"scc", mac_scc_dispatch);
-	cpu_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+	request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
 			"nubus", (void *) oss);
-	cpu_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+	request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
 			"sound", (void *) oss);
-	cpu_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+	request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
 			"via1", (void *) via1);
 }
 
@@ -113,7 +113,7 @@
 		oss->irq_pending &= ~OSS_IP_SOUND;
 	} else if (events & OSS_IP_SCSI) {
 		oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
-		mac_do_irq_list(IRQ_MAC_SCSI, regs);
+		m68k_handle_int(IRQ_MAC_SCSI, regs);
 		oss->irq_pending &= ~OSS_IP_SCSI;
 		oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
 	} else {
@@ -146,7 +146,7 @@
 	for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
 		if (events & irq_bit) {
 			oss->irq_level[i] = OSS_IRQLEV_DISABLED;
-			mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+			m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
 			oss->irq_pending &= ~irq_bit;
 			oss->irq_level[i] = OSS_IRQLEV_NUBUS;
 		}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index e72384e..e262180 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -117,10 +117,10 @@
 
 void __init psc_register_interrupts(void)
 {
-	cpu_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", (void *) 0x30);
-	cpu_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", (void *) 0x40);
-	cpu_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", (void *) 0x50);
-	cpu_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", (void *) 0x60);
+	request_irq(IRQ_AUTO_3, psc_irq, 0, "psc3", (void *) 0x30);
+	request_irq(IRQ_AUTO_4, psc_irq, 0, "psc4", (void *) 0x40);
+	request_irq(IRQ_AUTO_5, psc_irq, 0, "psc5", (void *) 0x50);
+	request_irq(IRQ_AUTO_6, psc_irq, 0, "psc6", (void *) 0x60);
 }
 
 /*
@@ -149,7 +149,7 @@
 	for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
 	        if (events & irq_bit) {
 			psc_write_byte(pIER, irq_bit);
-			mac_do_irq_list(base_irq + i, regs);
+			m68k_handle_int(base_irq + i, regs);
 			psc_write_byte(pIFR, irq_bit);
 			psc_write_byte(pIER, irq_bit | 0x80);
 		}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index a6e3814..c4aa345 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -253,21 +253,21 @@
 void __init via_register_interrupts(void)
 {
 	if (via_alt_mapping) {
-		cpu_request_irq(IRQ_AUTO_1, via1_irq,
+		request_irq(IRQ_AUTO_1, via1_irq,
 				IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
 				(void *) via1);
-		cpu_request_irq(IRQ_AUTO_6, via1_irq,
+		request_irq(IRQ_AUTO_6, via1_irq,
 				IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
 				(void *) via1);
 	} else {
-		cpu_request_irq(IRQ_AUTO_1, via1_irq,
+		request_irq(IRQ_AUTO_1, via1_irq,
 				IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
 				(void *) via1);
 	}
-	cpu_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+	request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
 			"via2", (void *) via2);
 	if (!psc_present) {
-		cpu_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
+		request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
 				"scc", mac_scc_dispatch);
 	}
 	request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
@@ -424,7 +424,7 @@
 	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
 		if (events & irq_bit) {
 			via1[vIER] = irq_bit;
-			mac_do_irq_list(VIA1_SOURCE_BASE + i, regs);
+			m68k_handle_int(VIA1_SOURCE_BASE + i, regs);
 			via1[vIFR] = irq_bit;
 			via1[vIER] = irq_bit | 0x80;
 		}
@@ -439,7 +439,7 @@
 		/* No, it won't be set. that's why we're doing this. */
 		via_irq_disable(IRQ_MAC_NUBUS);
 		via_irq_clear(IRQ_MAC_NUBUS);
-		mac_do_irq_list(IRQ_MAC_NUBUS, regs);
+		m68k_handle_int(IRQ_MAC_NUBUS, regs);
 		via_irq_enable(IRQ_MAC_NUBUS);
 	}
 #endif
@@ -459,7 +459,7 @@
 		if (events & irq_bit) {
 			via2[gIER] = irq_bit;
 			via2[gIFR] = irq_bit | rbv_clear;
-			mac_do_irq_list(VIA2_SOURCE_BASE + i, regs);
+			m68k_handle_int(VIA2_SOURCE_BASE + i, regs);
 			via2[gIER] = irq_bit | 0x80;
 		}
 	return IRQ_HANDLED;
@@ -481,7 +481,7 @@
 	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
 		if (events & irq_bit) {
 			via_irq_disable(NUBUS_SOURCE_BASE + i);
-			mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+			m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
 			via_irq_enable(NUBUS_SOURCE_BASE + i);
 		}
 	}
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 85ad19a..43ffab0 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -259,13 +259,15 @@
 
 		if (CPU_IS_020_OR_030) {
 			int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+			int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
 
-			if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+			if (pmd_type == _PAGE_PRESENT) {
 				pmd_dir->pmd[pmd_off] = 0;
 				virtaddr += PTRTREESIZE;
 				size -= PTRTREESIZE;
 				continue;
-			}
+			} else if (pmd_type == 0)
+				continue;
 		}
 
 		if (pmd_bad(*pmd_dir)) {
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index d6d582a..a226668 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -94,8 +94,7 @@
 	PD_MARKBITS(dp) = mask & ~tmp;
 	if (!PD_MARKBITS(dp)) {
 		/* move to end of list */
-		list_del(dp);
-		list_add_tail(dp, &ptable_list);
+		list_move_tail(dp, &ptable_list);
 	}
 	return (pmd_t *) (page_address(PD_PAGE(dp)) + off);
 }
@@ -123,8 +122,7 @@
 		 * move this descriptor to the front of the list, since
 		 * it has one or more free tables.
 		 */
-		list_del(dp);
-		list_add(dp, &ptable_list);
+		list_move(dp, &ptable_list);
 	}
 	return 0;
 }
diff --git a/arch/m68k/mvme147/147ints.c b/arch/m68k/mvme147/147ints.c
deleted file mode 100644
index 69a744e..0000000
--- a/arch/m68k/mvme147/147ints.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * arch/m68k/mvme147/147ints.c
- *
- * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/ptrace.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-static irqreturn_t mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
-	irqreturn_t	(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-	const char	*devname;
-	unsigned	count;
-} irq_tab[256];
-
-/*
- * void mvme147_init_IRQ (void)
- *
- * Parameters:	None
- *
- * Returns:	Nothing
- *
- * This function is called during kernel startup to initialize
- * the mvme147 IRQ handling routines.
- */
-
-void mvme147_init_IRQ (void)
-{
-	int i;
-
-	for (i = 0; i < 256; i++) {
-		irq_tab[i].handler = mvme147_defhand;
-		irq_tab[i].flags = IRQ_FLG_STD;
-		irq_tab[i].dev_id = NULL;
-		irq_tab[i].devname = NULL;
-		irq_tab[i].count = 0;
-	}
-}
-
-int mvme147_request_irq(unsigned int irq,
-		irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-	if (irq > 255) {
-		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-	if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
-		if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_tab[irq].devname);
-			return -EBUSY;
-		}
-		if (flags & IRQ_FLG_REPLACE) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_tab[irq].devname);
-			return -EBUSY;
-		}
-	}
-	irq_tab[irq].handler = handler;
-	irq_tab[irq].flags   = flags;
-	irq_tab[irq].dev_id  = dev_id;
-	irq_tab[irq].devname = devname;
-	return 0;
-}
-
-void mvme147_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq > 255) {
-		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-	if (irq_tab[irq].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_tab[irq].devname);
-
-	irq_tab[irq].handler = mvme147_defhand;
-	irq_tab[irq].flags   = IRQ_FLG_STD;
-	irq_tab[irq].dev_id  = NULL;
-	irq_tab[irq].devname = NULL;
-}
-
-irqreturn_t mvme147_process_int (unsigned long vec, struct pt_regs *fp)
-{
-	if (vec > 255) {
-		printk ("mvme147_process_int: Illegal vector %ld\n", vec);
-		return IRQ_NONE;
-	} else {
-		irq_tab[vec].count++;
-		irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
-		return IRQ_HANDLED;
-	}
-}
-
-int show_mvme147_interrupts (struct seq_file *p, void *v)
-{
-	int i;
-
-	for (i = 0; i < 256; i++) {
-		if (irq_tab[i].count)
-			seq_printf(p, "Vec 0x%02x: %8d  %s\n",
-			    i, irq_tab[i].count,
-			    irq_tab[i].devname ? irq_tab[i].devname : "free");
-	}
-	return 0;
-}
-
-
-static irqreturn_t mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-	printk ("Unknown interrupt 0x%02x\n", irq);
-	return IRQ_NONE;
-}
-
-void mvme147_enable_irq (unsigned int irq)
-{
-}
-
-
-void mvme147_disable_irq (unsigned int irq)
-{
-}
-
diff --git a/arch/m68k/mvme147/Makefile b/arch/m68k/mvme147/Makefile
index f0153ed..a36d38d 100644
--- a/arch/m68k/mvme147/Makefile
+++ b/arch/m68k/mvme147/Makefile
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/mvme147 source directory
 #
 
-obj-y		:= config.o 147ints.o
+obj-y		:= config.o
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 0fcf972..0cd0e5b 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -36,15 +36,8 @@
 #include <asm/mvme147hw.h>
 
 
-extern irqreturn_t mvme147_process_int (int level, struct pt_regs *regs);
-extern void mvme147_init_IRQ (void);
-extern void mvme147_free_irq (unsigned int, void *);
-extern int  show_mvme147_interrupts (struct seq_file *, void *);
-extern void mvme147_enable_irq (unsigned int);
-extern void mvme147_disable_irq (unsigned int);
 static void mvme147_get_model(char *model);
 static int  mvme147_get_hardware_list(char *buffer);
-extern int mvme147_request_irq (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern unsigned long mvme147_gettimeoffset (void);
 extern int mvme147_hwclk (int, struct rtc_time *);
@@ -91,6 +84,15 @@
 	return 0;
 }
 
+/*
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ(void)
+{
+	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
 
 void __init config_mvme147(void)
 {
@@ -101,12 +103,6 @@
 	mach_hwclk		= mvme147_hwclk;
 	mach_set_clock_mmss	= mvme147_set_clock_mmss;
 	mach_reset		= mvme147_reset;
-	mach_free_irq		= mvme147_free_irq;
-	mach_process_int	= mvme147_process_int;
-	mach_get_irq_list	= show_mvme147_interrupts;
-	mach_request_irq	= mvme147_request_irq;
-	enable_irq		= mvme147_enable_irq;
-	disable_irq		= mvme147_disable_irq;
 	mach_get_model		= mvme147_get_model;
 	mach_get_hardware_list	= mvme147_get_hardware_list;
 
diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
deleted file mode 100644
index 793ef73..0000000
--- a/arch/m68k/mvme16x/16xints.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * arch/m68k/mvme16x/16xints.c
- *
- * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * based on amiints.c -- Amiga Linux interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/irq.h>
-
-static irqreturn_t mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp);
-
-/*
- * This should ideally be 4 elements only, for speed.
- */
-
-static struct {
-	irqreturn_t	(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-	const char	*devname;
-	unsigned	count;
-} irq_tab[192];
-
-/*
- * void mvme16x_init_IRQ (void)
- *
- * Parameters:	None
- *
- * Returns:	Nothing
- *
- * This function is called during kernel startup to initialize
- * the mvme16x IRQ handling routines.  Should probably ensure
- * that the base vectors for the VMEChip2 and PCCChip2 are valid.
- */
-
-void mvme16x_init_IRQ (void)
-{
-	int i;
-
-	for (i = 0; i < 192; i++) {
-		irq_tab[i].handler = mvme16x_defhand;
-		irq_tab[i].flags = IRQ_FLG_STD;
-		irq_tab[i].dev_id = NULL;
-		irq_tab[i].devname = NULL;
-		irq_tab[i].count = 0;
-	}
-}
-
-int mvme16x_request_irq(unsigned int irq,
-		irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-	if (irq < 64 || irq > 255) {
-		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-
-	if (!(irq_tab[irq-64].flags & IRQ_FLG_STD)) {
-		if (irq_tab[irq-64].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_tab[irq-64].devname);
-			return -EBUSY;
-		}
-		if (flags & IRQ_FLG_REPLACE) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_tab[irq-64].devname);
-			return -EBUSY;
-		}
-	}
-	irq_tab[irq-64].handler = handler;
-	irq_tab[irq-64].flags   = flags;
-	irq_tab[irq-64].dev_id  = dev_id;
-	irq_tab[irq-64].devname = devname;
-	return 0;
-}
-
-void mvme16x_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq < 64 || irq > 255) {
-		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (irq_tab[irq-64].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_tab[irq-64].devname);
-
-	irq_tab[irq-64].handler = mvme16x_defhand;
-	irq_tab[irq-64].flags   = IRQ_FLG_STD;
-	irq_tab[irq-64].dev_id  = NULL;
-	irq_tab[irq-64].devname = NULL;
-}
-
-irqreturn_t mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
-{
-	if (vec < 64 || vec > 255) {
-		printk ("mvme16x_process_int: Illegal vector %ld", vec);
-		return IRQ_NONE;
-	} else {
-		irq_tab[vec-64].count++;
-		irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
-		return IRQ_HANDLED;
-	}
-}
-
-int show_mvme16x_interrupts (struct seq_file *p, void *v)
-{
-	int i;
-
-	for (i = 0; i < 192; i++) {
-		if (irq_tab[i].count)
-			seq_printf(p, "Vec 0x%02x: %8d  %s\n",
-			    i+64, irq_tab[i].count,
-			    irq_tab[i].devname ? irq_tab[i].devname : "free");
-	}
-	return 0;
-}
-
-
-static irqreturn_t mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
-{
-	printk ("Unknown interrupt 0x%02x\n", irq);
-	return IRQ_NONE;
-}
-
-
-void mvme16x_enable_irq (unsigned int irq)
-{
-}
-
-
-void mvme16x_disable_irq (unsigned int irq)
-{
-}
-
-
diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile
index 5129f56..950e82f 100644
--- a/arch/m68k/mvme16x/Makefile
+++ b/arch/m68k/mvme16x/Makefile
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/mvme16x source directory
 #
 
-obj-y		:= config.o 16xints.o rtc.o mvme16x_ksyms.o
+obj-y		:= config.o rtc.o mvme16x_ksyms.o
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 26ce81c..ce2727e 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -40,15 +40,8 @@
 
 static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
 
-extern irqreturn_t mvme16x_process_int (int level, struct pt_regs *regs);
-extern void mvme16x_init_IRQ (void);
-extern void mvme16x_free_irq (unsigned int, void *);
-extern int show_mvme16x_interrupts (struct seq_file *, void *);
-extern void mvme16x_enable_irq (unsigned int);
-extern void mvme16x_disable_irq (unsigned int);
 static void mvme16x_get_model(char *model);
 static int  mvme16x_get_hardware_list(char *buffer);
-extern int  mvme16x_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern unsigned long mvme16x_gettimeoffset (void);
 extern int mvme16x_hwclk (int, struct rtc_time *);
@@ -120,6 +113,16 @@
     return (len);
 }
 
+/*
+ * This function is called during kernel startup to initialize
+ * the mvme16x IRQ handling routines.  Should probably ensure
+ * that the base vectors for the VMEChip2 and PCCChip2 are valid.
+ */
+
+static void mvme16x_init_IRQ (void)
+{
+	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+}
 
 #define pcc2chip	((volatile u_char *)0xfff42000)
 #define PccSCCMICR	0x1d
@@ -138,12 +141,6 @@
     mach_hwclk           = mvme16x_hwclk;
     mach_set_clock_mmss	 = mvme16x_set_clock_mmss;
     mach_reset		 = mvme16x_reset;
-    mach_free_irq	 = mvme16x_free_irq;
-    mach_process_int	 = mvme16x_process_int;
-    mach_get_irq_list	 = show_mvme16x_interrupts;
-    mach_request_irq	 = mvme16x_request_irq;
-    enable_irq           = mvme16x_enable_irq;
-    disable_irq          = mvme16x_disable_irq;
     mach_get_model       = mvme16x_get_model;
     mach_get_hardware_list = mvme16x_get_hardware_list;
 
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 5e0f9b0..efa52d3 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -37,15 +37,9 @@
 #include <asm/q40_master.h>
 
 extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
-extern irqreturn_t (*q40_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
 extern void q40_init_IRQ (void);
-extern void q40_free_irq (unsigned int, void *);
-extern int  show_q40_interrupts (struct seq_file *, void *);
-extern void q40_enable_irq (unsigned int);
-extern void q40_disable_irq (unsigned int);
 static void q40_get_model(char *model);
 static int  q40_get_hardware_list(char *buffer);
-extern int  q40_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 
 extern unsigned long q40_gettimeoffset (void);
@@ -175,13 +169,6 @@
     mach_set_clock_mmss	 = q40_set_clock_mmss;
 
     mach_reset		 = q40_reset;
-    mach_free_irq	 = q40_free_irq;
-    mach_process_int	 = q40_process_int;
-    mach_get_irq_list	 = show_q40_interrupts;
-    mach_request_irq	 = q40_request_irq;
-    enable_irq		 = q40_enable_irq;
-    disable_irq          = q40_disable_irq;
-    mach_default_handler = &q40_default_handler;
     mach_get_model       = q40_get_model;
     mach_get_hardware_list = q40_get_hardware_list;
 
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index f8ecc26..472f41c 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -14,13 +14,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
 #include <linux/interrupt.h>
-#include <linux/hardirq.h>
 
-#include <asm/rtc.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/irq.h>
@@ -39,29 +34,37 @@
  *
 */
 
-extern int ints_inited;
+static void q40_irq_handler(unsigned int, struct pt_regs *fp);
+static void q40_enable_irq(unsigned int);
+static void q40_disable_irq(unsigned int);
 
+unsigned short q40_ablecount[35];
+unsigned short q40_state[35];
 
-irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp);
+static int q40_irq_startup(unsigned int irq)
+{
+	/* test for ISA ints not implemented by HW */
+	switch (irq) {
+	case 1: case 2: case 8: case 9:
+	case 11: case 12: case 13:
+		printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq);
+		return -ENXIO;
+	}
+	return 0;
+}
 
+static void q40_irq_shutdown(unsigned int irq)
+{
+}
 
-static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs);
-
-
-#define DEVNAME_SIZE 24
-
-static struct q40_irq_node {
-	irqreturn_t	(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
-	void		*dev_id;
-  /*        struct q40_irq_node *next;*/
-        char	        devname[DEVNAME_SIZE];
-	unsigned	count;
-        unsigned short  state;
-} irq_tab[Q40_IRQ_MAX+1];
-
-short unsigned q40_ablecount[Q40_IRQ_MAX+1];
+static struct irq_controller q40_irq_controller = {
+	.name		= "q40",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.startup	= q40_irq_startup,
+	.shutdown	= q40_irq_shutdown,
+	.enable		= q40_enable_irq,
+	.disable	= q40_disable_irq,
+};
 
 /*
  * void q40_init_IRQ (void)
@@ -74,139 +77,29 @@
  * the q40 IRQ handling routines.
  */
 
-static int disabled=0;
+static int disabled;
 
-void q40_init_IRQ (void)
+void q40_init_IRQ(void)
 {
-	int i;
-
-	disabled=0;
-	for (i = 0; i <= Q40_IRQ_MAX; i++) {
-		irq_tab[i].handler = q40_defhand;
-		irq_tab[i].flags = 0;
-		irq_tab[i].dev_id = NULL;
-		/*		irq_tab[i].next = NULL;*/
-		irq_tab[i].devname[0] = 0;
-		irq_tab[i].count = 0;
-		irq_tab[i].state =0;
-		q40_ablecount[i]=0;   /* all enabled */
-	}
+	m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
 
 	/* setup handler for ISA ints */
-	cpu_request_irq(IRQ2, q40_irq2_handler, 0, "q40 ISA and master chip",
-			NULL);
+	m68k_setup_auto_interrupt(q40_irq_handler);
+
+	m68k_irq_startup(IRQ_AUTO_2);
+	m68k_irq_startup(IRQ_AUTO_4);
 
 	/* now enable some ints.. */
-	master_outb(1,EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
+	master_outb(1, EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
 
 	/* make sure keyboard IRQ is disabled */
-	master_outb(0,KEY_IRQ_ENABLE_REG);
+	master_outb(0, KEY_IRQ_ENABLE_REG);
 }
 
-int q40_request_irq(unsigned int irq,
-		irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-  /*printk("q40_request_irq %d, %s\n",irq,devname);*/
-
-	if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
-		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-
-	/* test for ISA ints not implemented by HW */
-	switch (irq)
-	  {
-	  case 1: case 2: case 8: case 9:
-	  case 12: case 13:
-	    printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
-	    return -ENXIO;
-	  case 11:
-	    printk("warning IRQ 10 and 11 not distinguishable\n");
-	    irq=10;
-	  default:
-	    ;
-	  }
-
-	if (irq<Q40_IRQ_SAMPLE)
-	  {
-	    if (irq_tab[irq].dev_id != NULL)
-		  {
-		    printk("%s: IRQ %d from %s is not replaceable\n",
-			   __FUNCTION__, irq, irq_tab[irq].devname);
-		    return -EBUSY;
-		  }
-	    /*printk("IRQ %d set to handler %p\n",irq,handler);*/
-	    if (dev_id==NULL)
-		  {
-		printk("WARNING: dev_id == NULL in request_irq\n");
-		dev_id=(void*)1;
-	      }
-	    irq_tab[irq].handler = handler;
-	    irq_tab[irq].flags   = flags;
-	    irq_tab[irq].dev_id  = dev_id;
-	    strlcpy(irq_tab[irq].devname,devname,sizeof(irq_tab[irq].devname));
-	    irq_tab[irq].state = 0;
-	    return 0;
-	  }
-	else {
-	  /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
-	  cpu_request_irq(4, handler, flags, devname, dev_id);
-	  cpu_request_irq(6, handler, flags, devname, dev_id);
-	  return 0;
-	}
-}
-
-void q40_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
-		printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
-		return;
-	}
-
-	/* test for ISA ints not implemented by HW */
-	switch (irq)
-	  {
-	  case 1: case 2: case 8: case 9:
-	  case 12: case 13:
-	    printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
-	    return;
-	  case 11: irq=10;
-	  default:
-	    ;
-	  }
-
-	if (irq<Q40_IRQ_SAMPLE)
-	  {
-	    if (irq_tab[irq].dev_id != dev_id)
-	      printk("%s: Removing probably wrong IRQ %d from %s\n",
-		     __FUNCTION__, irq, irq_tab[irq].devname);
-
-	    irq_tab[irq].handler = q40_defhand;
-	    irq_tab[irq].flags   = 0;
-	    irq_tab[irq].dev_id  = NULL;
-	    /* irq_tab[irq].devname = NULL; */
-	    /* do not reset state !! */
-	  }
-	else
-	  { /* == Q40_IRQ_SAMPLE */
-	    cpu_free_irq(4, dev_id);
-	    cpu_free_irq(6, dev_id);
-	  }
-}
-
-
-irqreturn_t q40_process_int (int level, struct pt_regs *fp)
-{
-  printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n",
-          level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2);
-  printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG));
-  return IRQ_HANDLED;
-}
 
 /*
  * this stuff doesn't really belong here..
-*/
+ */
 
 int ql_ticks;              /* 200Hz ticks since last jiffie */
 static int sound_ticks;
@@ -215,54 +108,53 @@
 
 void q40_mksound(unsigned int hz, unsigned int ticks)
 {
-  /* for now ignore hz, except that hz==0 switches off sound */
-  /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
-  if (hz==0)
-    {
-      if (sound_ticks)
-	sound_ticks=1;
+	/* for now ignore hz, except that hz==0 switches off sound */
+	/* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
+	if (hz == 0) {
+		if (sound_ticks)
+			sound_ticks = 1;
 
-      *DAC_LEFT=128;
-      *DAC_RIGHT=128;
+		*DAC_LEFT = 128;
+		*DAC_RIGHT = 128;
 
-      return;
-    }
-  /* sound itself is done in q40_timer_int */
-  if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
-  sound_ticks=ticks<<1;
+		return;
+	}
+	/* sound itself is done in q40_timer_int */
+	if (sound_ticks == 0)
+		sound_ticks = 1000; /* pretty long beep */
+	sound_ticks = ticks << 1;
 }
 
 static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *);
 
 static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
 {
-    ql_ticks = ql_ticks ? 0 : 1;
-    if (sound_ticks)
-      {
-	unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
-	sound_ticks--;
-	*DAC_LEFT=sval;
-	*DAC_RIGHT=sval;
-      }
+	ql_ticks = ql_ticks ? 0 : 1;
+	if (sound_ticks) {
+		unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
+		sound_ticks--;
+		*DAC_LEFT=sval;
+		*DAC_RIGHT=sval;
+	}
 
-    if (!ql_ticks)
-	q40_timer_routine(irq, dev, regs);
-    return IRQ_HANDLED;
+	if (!ql_ticks)
+		q40_timer_routine(irq, dev, regs);
+	return IRQ_HANDLED;
 }
 
 void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
 {
-    int timer_irq;
+	int timer_irq;
 
-    q40_timer_routine = timer_routine;
-    timer_irq=Q40_IRQ_FRAME;
+	q40_timer_routine = timer_routine;
+	timer_irq = Q40_IRQ_FRAME;
 
-    if (request_irq(timer_irq, q40_timer_int, 0,
+	if (request_irq(timer_irq, q40_timer_int, 0,
 				"timer", q40_timer_int))
-	panic ("Couldn't register timer int");
+		panic("Couldn't register timer int");
 
-    master_outb(-1,FRAME_CLEAR_REG);
-    master_outb( 1,FRAME_RATE_REG);
+	master_outb(-1, FRAME_CLEAR_REG);
+	master_outb( 1, FRAME_RATE_REG);
 }
 
 
@@ -308,169 +200,132 @@
 static int aliased_irq=0;  /* how many times inside handler ?*/
 
 
-/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */
-irqreturn_t q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+/* got interrupt, dispatch to ISA or keyboard/timer IRQs */
+static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
 {
-  unsigned mir, mer;
-  int irq,i;
+	unsigned mir, mer;
+	int i;
 
 //repeat:
-  mir=master_inb(IIRQ_REG);
-  if (mir&Q40_IRQ_FRAME_MASK) {
-	  irq_tab[Q40_IRQ_FRAME].count++;
-	  irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);
-	  master_outb(-1,FRAME_CLEAR_REG);
-  }
-  if ((mir&Q40_IRQ_SER_MASK) || (mir&Q40_IRQ_EXT_MASK)) {
-	  mer=master_inb(EIRQ_REG);
-	  for (i=0; eirqs[i].mask; i++) {
-		  if (mer&(eirqs[i].mask)) {
-			  irq=eirqs[i].irq;
+	mir = master_inb(IIRQ_REG);
+#ifdef CONFIG_BLK_DEV_FD
+	if ((mir & Q40_IRQ_EXT_MASK) &&
+	    (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
+		floppy_hardint();
+		return;
+	}
+#endif
+	switch (irq) {
+	case 4:
+	case 6:
+		m68k_handle_int(Q40_IRQ_SAMPLE, fp);
+		return;
+	}
+	if (mir & Q40_IRQ_FRAME_MASK) {
+		m68k_handle_int(Q40_IRQ_FRAME, fp);
+		master_outb(-1, FRAME_CLEAR_REG);
+	}
+	if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
+		mer = master_inb(EIRQ_REG);
+		for (i = 0; eirqs[i].mask; i++) {
+			if (mer & eirqs[i].mask) {
+				irq = eirqs[i].irq;
 /*
  * There is a little mess wrt which IRQ really caused this irq request. The
  * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
  * are read - which is long after the request came in. In theory IRQs should
  * not just go away but they occassionally do
  */
-			  if (irq>4 && irq<=15 && mext_disabled) {
-				  /*aliased_irq++;*/
-				  goto iirq;
-			  }
-			  if (irq_tab[irq].handler == q40_defhand ) {
-				  printk("handler for IRQ %d not defined\n",irq);
-				  continue; /* ignore uninited INTs :-( */
-			  }
-			  if ( irq_tab[irq].state & IRQ_INPROGRESS ) {
-				  /* some handlers do local_irq_enable() for irq latency reasons, */
-				  /* however reentering an active irq handler is not permitted */
+				if (irq > 4 && irq <= 15 && mext_disabled) {
+					/*aliased_irq++;*/
+					goto iirq;
+				}
+				if (q40_state[irq] & IRQ_INPROGRESS) {
+					/* some handlers do local_irq_enable() for irq latency reasons, */
+					/* however reentering an active irq handler is not permitted */
 #ifdef IP_USE_DISABLE
-				  /* in theory this is the better way to do it because it still */
-				  /* lets through eg the serial irqs, unfortunately it crashes */
-				  disable_irq(irq);
-				  disabled=1;
+					/* in theory this is the better way to do it because it still */
+					/* lets through eg the serial irqs, unfortunately it crashes */
+					disable_irq(irq);
+					disabled = 1;
 #else
-				  /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
-				  fp->sr = (((fp->sr) & (~0x700))+0x200);
-				  disabled=1;
+					/*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
+						irq, disabled ? "already" : "not yet"); */
+					fp->sr = (((fp->sr) & (~0x700))+0x200);
+					disabled = 1;
 #endif
-				  goto iirq;
-			  }
-			  irq_tab[irq].count++;
-			  irq_tab[irq].state |= IRQ_INPROGRESS;
-			  irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
-			  irq_tab[irq].state &= ~IRQ_INPROGRESS;
+					goto iirq;
+				}
+				q40_state[irq] |= IRQ_INPROGRESS;
+				m68k_handle_int(irq, fp);
+				q40_state[irq] &= ~IRQ_INPROGRESS;
 
-			  /* naively enable everything, if that fails than    */
-			  /* this function will be reentered immediately thus */
-			  /* getting another chance to disable the IRQ        */
+				/* naively enable everything, if that fails than    */
+				/* this function will be reentered immediately thus */
+				/* getting another chance to disable the IRQ        */
 
-			  if ( disabled ) {
+				if (disabled) {
 #ifdef IP_USE_DISABLE
-				  if (irq>4){
-					  disabled=0;
-					  enable_irq(irq);}
+					if (irq > 4) {
+						disabled = 0;
+						enable_irq(irq);
+					}
 #else
-				  disabled=0;
-				  /*printk("reenabling irq %d\n",irq); */
+					disabled = 0;
+					/*printk("reenabling irq %d\n", irq); */
 #endif
-			  }
+				}
 // used to do 'goto repeat;' here, this delayed bh processing too long
-			  return IRQ_HANDLED;
-		  }
-	  }
-	  if (mer && ccleirq>0 && !aliased_irq)
-		  printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
-  }
- iirq:
-  mir=master_inb(IIRQ_REG);
-  /* should test whether keyboard irq is really enabled, doing it in defhand */
-  if (mir&Q40_IRQ_KEYB_MASK) {
-	  irq_tab[Q40_IRQ_KEYBOARD].count++;
-	  irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
-  }
-  return IRQ_HANDLED;
-}
-
-int show_q40_interrupts (struct seq_file *p, void *v)
-{
-	int i;
-
-	for (i = 0; i <= Q40_IRQ_MAX; i++) {
-		if (irq_tab[i].count)
-		      seq_printf(p, "%sIRQ %02d: %8d  %s%s\n",
-			      (i<=15) ? "ISA-" : "    " ,
-			    i, irq_tab[i].count,
-			    irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
-			    irq_tab[i].handler == q40_defhand ?
-					" (now unassigned)" : "");
+				return;
+			}
+		}
+		if (mer && ccleirq > 0 && !aliased_irq) {
+			printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer);
+			ccleirq--;
+		}
 	}
-	return 0;
+ iirq:
+	mir = master_inb(IIRQ_REG);
+	/* should test whether keyboard irq is really enabled, doing it in defhand */
+	if (mir & Q40_IRQ_KEYB_MASK)
+		m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
+
+	return;
 }
 
-
-static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
+void q40_enable_irq(unsigned int irq)
 {
-        if (irq!=Q40_IRQ_KEYBOARD)
-	     printk ("Unknown q40 interrupt %d\n", irq);
-	else master_outb(-1,KEYBOARD_UNLOCK_REG);
-	return IRQ_NONE;
+	if (irq >= 5 && irq <= 15) {
+		mext_disabled--;
+		if (mext_disabled > 0)
+			printk("q40_enable_irq : nested disable/enable\n");
+		if (mext_disabled == 0)
+			master_outb(1, EXT_ENABLE_REG);
+	}
 }
-static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs)
+
+
+void q40_disable_irq(unsigned int irq)
 {
-	printk ("Uninitialised interrupt level %d\n", lev);
-	return IRQ_NONE;
+	/* disable ISA iqs : only do something if the driver has been
+	 * verified to be Q40 "compatible" - right now IDE, NE2K
+	 * Any driver should not attempt to sleep across disable_irq !!
+	 */
+
+	if (irq >= 5 && irq <= 15) {
+		master_outb(0, EXT_ENABLE_REG);
+		mext_disabled++;
+		if (mext_disabled > 1)
+			printk("disable_irq nesting count %d\n",mext_disabled);
+	}
 }
 
-irqreturn_t (*q40_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	 [0] = default_handler,
-	 [1] = default_handler,
-	 [2] = default_handler,
-	 [3] = default_handler,
-	 [4] = default_handler,
-	 [5] = default_handler,
-	 [6] = default_handler,
-	 [7] = default_handler
-};
-
-
-void q40_enable_irq (unsigned int irq)
+unsigned long q40_probe_irq_on(void)
 {
-  if ( irq>=5 && irq<=15 )
-  {
-    mext_disabled--;
-    if (mext_disabled>0)
-	  printk("q40_enable_irq : nested disable/enable\n");
-    if (mext_disabled==0)
-    master_outb(1,EXT_ENABLE_REG);
-    }
+	printk("irq probing not working - reconfigure the driver to avoid this\n");
+	return -1;
 }
-
-
-void q40_disable_irq (unsigned int irq)
+int q40_probe_irq_off(unsigned long irqs)
 {
-  /* disable ISA iqs : only do something if the driver has been
-   * verified to be Q40 "compatible" - right now IDE, NE2K
-   * Any driver should not attempt to sleep across disable_irq !!
-   */
-
-  if ( irq>=5 && irq<=15 ) {
-    master_outb(0,EXT_ENABLE_REG);
-    mext_disabled++;
-    if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled);
-  }
+	return -1;
 }
-
-unsigned long q40_probe_irq_on (void)
-{
-  printk("irq probing not working - reconfigure the driver to avoid this\n");
-  return -1;
-}
-int q40_probe_irq_off (unsigned long irqs)
-{
-  return -1;
-}
-/*
- * Local variables:
- * compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040   -c -o q40ints.o q40ints.c"
- * End:
- */
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index f1ca0df..553c304 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -36,7 +36,6 @@
 char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
 
 extern unsigned long sun3_gettimeoffset(void);
-extern int show_sun3_interrupts (struct seq_file *, void *);
 extern void sun3_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
 extern void sun3_get_model (char* model);
 extern void idprom_init (void);
@@ -147,13 +146,6 @@
 
         mach_sched_init      =  sun3_sched_init;
         mach_init_IRQ        =  sun3_init_IRQ;
-        mach_default_handler = &sun3_default_handler;
-        mach_request_irq     =  sun3_request_irq;
-        mach_free_irq        =  sun3_free_irq;
-	enable_irq	     =  sun3_enable_irq;
-        disable_irq	     =  sun3_disable_irq;
-	mach_process_int     =  sun3_process_int;
-        mach_get_irq_list    =  show_sun3_interrupts;
         mach_reset           =  sun3_reboot;
 	mach_gettimeoffset   =  sun3_gettimeoffset;
 	mach_get_model	     =  sun3_get_model;
diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c
index f04a1d2..97c7bfd 100644
--- a/arch/m68k/sun3/sun3dvma.c
+++ b/arch/m68k/sun3/sun3dvma.c
@@ -119,8 +119,7 @@
 		if(hole->end == prev->start) {
 			hole->size += prev->size;
 			hole->end = prev->end;
-			list_del(&(prev->list));
-			list_add(&(prev->list), &hole_cache);
+			list_move(&(prev->list), &hole_cache);
 			ret++;
 		}
 
@@ -182,8 +181,7 @@
 #endif
 			return hole->end;
 		} else if(hole->size == newlen) {
-			list_del(&(hole->list));
-			list_add(&(hole->list), &hole_cache);
+			list_move(&(hole->list), &hole_cache);
 			dvma_entry_use(hole->start) = newlen;
 #ifdef DVMA_DEBUG
 			dvma_allocs++;
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index e62a033..0912435 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -19,7 +19,6 @@
 #include <linux/seq_file.h>
 
 extern void sun3_leds (unsigned char);
-static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp);
 
 void sun3_disable_interrupts(void)
 {
@@ -40,48 +39,30 @@
 
 volatile unsigned char* sun3_intreg;
 
-void sun3_insert_irq(irq_node_t **list, irq_node_t *node)
-{
-}
-
-void sun3_delete_irq(irq_node_t **list, void *dev_id)
-{
-}
-
 void sun3_enable_irq(unsigned int irq)
 {
-	*sun3_intreg |=  (1<<irq);
+	*sun3_intreg |=  (1 << irq);
 }
 
 void sun3_disable_irq(unsigned int irq)
 {
-	*sun3_intreg &= ~(1<<irq);
-}
-
-inline void sun3_do_irq(int irq, struct pt_regs *fp)
-{
-	kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-	*sun3_intreg &= ~(1<<irq);
-	*sun3_intreg |=  (1<<irq);
+	*sun3_intreg &= ~(1 << irq);
 }
 
 static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
 {
-	sun3_do_irq(irq,fp);
-	if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 2000))
-		sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%16000)
-			  /2000]);
+	*sun3_intreg |=  (1 << irq);
+	if (!(kstat_cpu(0).irqs[irq] % 2000))
+		sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 16000) / 2000]);
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
 {
-        kstat_cpu(0).irqs[SYS_IRQS + irq]++;
 #ifdef CONFIG_SUN3
 	intersil_clear();
 #endif
-        *sun3_intreg &= ~(1<<irq);
-        *sun3_intreg |=  (1<<irq);
+        *sun3_intreg |=  (1 << irq);
 #ifdef CONFIG_SUN3
 	intersil_clear();
 #endif
@@ -89,65 +70,8 @@
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(fp));
 #endif
-        if(!(kstat_cpu(0).irqs[SYS_IRQS + irq] % 20))
-                sun3_leds(led_pattern[(kstat_cpu(0).irqs[SYS_IRQS+irq]%160)
-                /20]);
-	return IRQ_HANDLED;
-}
-
-/* handle requested ints, excepting 5 and 7, which always do the same
-   thing */
-irqreturn_t (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	[0] = sun3_inthandle,
-	[1] = sun3_inthandle,
-	[2] = sun3_inthandle,
-	[3] = sun3_inthandle,
-	[4] = sun3_inthandle,
-	[5] = sun3_int5,
-	[6] = sun3_inthandle,
-	[7] = sun3_int7
-};
-
-static const char *dev_names[SYS_IRQS] = {
-	[5] = "timer",
-	[7] = "int7 handler"
-};
-static void *dev_ids[SYS_IRQS];
-static irqreturn_t (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	[5] = sun3_int5,
-	[7] = sun3_int7
-};
-static irqreturn_t (*sun3_vechandler[SUN3_INT_VECS])(int, void *, struct pt_regs *);
-static void *vec_ids[SUN3_INT_VECS];
-static const char *vec_names[SUN3_INT_VECS];
-static int vec_ints[SUN3_INT_VECS];
-
-
-int show_sun3_interrupts(struct seq_file *p, void *v)
-{
-	int i;
-
-	for(i = 0; i < (SUN3_INT_VECS-1); i++) {
-		if(sun3_vechandler[i] != NULL) {
-			seq_printf(p, "vec %3d: %10u %s\n", i+64,
-				   vec_ints[i],
-				   (vec_names[i]) ? vec_names[i] :
-				   "sun3_vechandler");
-		}
-	}
-
-	return 0;
-}
-
-static irqreturn_t sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
-{
-	if(sun3_inthandler[irq] == NULL)
-		panic ("bad interrupt %d received (id %p)\n",irq, dev_id);
-
-        kstat_cpu(0).irqs[SYS_IRQS + irq]++;
-        *sun3_intreg &= ~(1<<irq);
-
-	sun3_inthandler[irq](irq, dev_ids[irq], fp);
+        if (!(kstat_cpu(0).irqs[irq] % 20))
+                sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
 	return IRQ_HANDLED;
 }
 
@@ -157,109 +81,31 @@
 	return IRQ_HANDLED;
 }
 
+static void sun3_inthandle(unsigned int irq, struct pt_regs *fp)
+{
+        *sun3_intreg &= ~(1 << irq);
+
+	m68k_handle_int(irq, fp);
+}
+
+static struct irq_controller sun3_irq_controller = {
+	.name		= "sun3",
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.startup	= m68k_irq_startup,
+	.shutdown	= m68k_irq_shutdown,
+	.enable		= sun3_enable_irq,
+	.disable	= sun3_disable_irq,
+};
+
 void sun3_init_IRQ(void)
 {
-	int i;
-
 	*sun3_intreg = 1;
 
-	for(i = 0; i < SYS_IRQS; i++)
-	{
-		if(dev_names[i])
-			cpu_request_irq(i, sun3_default_handler[i], 0,
-					dev_names[i], NULL);
-	}
+	m68k_setup_auto_interrupt(sun3_inthandle);
+	m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
+	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 
-	for(i = 0; i < 192; i++)
-		sun3_vechandler[i] = NULL;
-
-	sun3_vechandler[191] = sun3_vec255;
-}
-
-int sun3_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                      unsigned long flags, const char *devname, void *dev_id)
-{
-
-	if(irq < SYS_IRQS) {
-		if(sun3_inthandler[irq] != NULL) {
-			printk("sun3_request_irq: request for irq %d -- already taken!\n", irq);
-			return 1;
-		}
-
-		sun3_inthandler[irq] = handler;
-		dev_ids[irq] = dev_id;
-		dev_names[irq] = devname;
-
-		/* setting devname would be nice */
-		cpu_request_irq(irq, sun3_default_handler[irq], 0, devname,
-				NULL);
-
-		return 0;
-	} else {
-		if((irq >= 64) && (irq <= 255)) {
-		        int vec;
-
-			vec = irq - 64;
-			if(sun3_vechandler[vec] != NULL) {
-				printk("sun3_request_irq: request for vec %d -- already taken!\n", irq);
-				return 1;
-			}
-
-			sun3_vechandler[vec] = handler;
-			vec_ids[vec] = dev_id;
-			vec_names[vec] = devname;
-			vec_ints[vec] = 0;
-
-			return 0;
-		}
-	}
-
-	printk("sun3_request_irq: invalid irq %d\n", irq);
-	return 1;
-
-}
-
-void sun3_free_irq(unsigned int irq, void *dev_id)
-{
-
-	if(irq < SYS_IRQS) {
-		if(sun3_inthandler[irq] == NULL)
-			panic("sun3_free_int: attempt to free unused irq %d\n", irq);
-		if(dev_ids[irq] != dev_id)
-			panic("sun3_free_int: incorrect dev_id for irq %d\n", irq);
-
-		sun3_inthandler[irq] = NULL;
-		return;
-	} else if((irq >= 64) && (irq <= 255)) {
-		int vec;
-
-		vec = irq - 64;
-		if(sun3_vechandler[vec] == NULL)
-			panic("sun3_free_int: attempt to free unused vector %d\n", irq);
-		if(vec_ids[irq] != dev_id)
-			panic("sun3_free_int: incorrect dev_id for vec %d\n", irq);
-
-		sun3_vechandler[vec] = NULL;
-		return;
-	} else {
-		panic("sun3_free_irq: invalid irq %d\n", irq);
-	}
-}
-
-irqreturn_t sun3_process_int(int irq, struct pt_regs *regs)
-{
-
-	if((irq >= 64) && (irq <= 255)) {
-		int vec;
-
-		vec = irq - 64;
-		if(sun3_vechandler[vec] == NULL)
-			panic ("bad interrupt vector %d received\n",irq);
-
-		vec_ints[vec]++;
-		return sun3_vechandler[vec](irq, vec_ids[vec], regs);
-	} else {
-		panic("sun3_process_int: unable to handle interrupt vector %d\n",
-		      irq);
-	}
+	request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL);
+	request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL);
+	request_irq(IRQ_USER+127, sun3_vec255, 0, "vec255", NULL);
 }
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
index 0920f5d..52fb174 100644
--- a/arch/m68k/sun3x/config.c
+++ b/arch/m68k/sun3x/config.c
@@ -52,17 +52,10 @@
 
 	sun3x_prom_init();
 
-	mach_get_irq_list	 = show_sun3_interrupts;
 	mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
 
-	mach_default_handler = &sun3_default_handler;
 	mach_sched_init      = sun3x_sched_init;
 	mach_init_IRQ        = sun3_init_IRQ;
-	enable_irq           = sun3_enable_irq;
-	disable_irq          = sun3_disable_irq;
-	mach_request_irq     = sun3_request_irq;
-	mach_free_irq        = sun3_free_irq;
-	mach_process_int     = sun3_process_int;
 
 	mach_gettimeoffset   = sun3x_gettimeoffset;
 	mach_reset           = sun3x_reboot;
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 3cde682..8b6e723 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -5,7 +5,7 @@
 
 mainmenu "uClinux/68k (w/o MMU) Kernel Configuration"
 
-config M68KNOMMU
+config M68K
 	bool
 	default y
 
@@ -119,6 +119,11 @@
 	help
 	  Motorola ColdFire 5307 processor support.
 
+config M532x
+	bool "MCF532x"
+	help
+	  Freescale (Motorola) ColdFire 532x processor support.
+
 config M5407
 	bool "MCF5407"
 	help
@@ -133,125 +138,43 @@
 
 config COLDFIRE
 	bool
-	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M5407)
+	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407)
 	default y
 
-choice
-	prompt "CPU CLOCK Frequency"
-	default AUTO
-
-config CLOCK_AUTO
-	bool "AUTO"
-	---help---
-	  Define the CPU clock frequency in use. On many boards you don't
-	  really need to know, so you can select the AUTO option. On some
-	  boards you need to know the real clock frequency to determine other
-	  system timing (for example baud rate dividors, etc). Some processors
-	  have an internal PLL and you can select a frequency to run at.
-	  You need to know a little about the internals of your processor to
-	  set this. If in doubt choose the AUTO option.
-
-config CLOCK_11MHz
-	bool "11MHz"
+config CLOCK_SET
+	bool "Enable setting the CPU clock frequency"
+	default n
 	help
-	  Select a 11MHz CPU clock frequency.
+	  On some CPU's you do not need to know what the core CPU clock
+	  frequency is. On these you can disable clock setting. On some
+	  traditional 68K parts, and on all ColdFire parts you need to set
+	  the appropriate CPU clock frequency. On these devices many of the
+	  onboard peripherals derive their timing from the master CPU clock
+	  frequency.
 
-config CLOCK_16MHz
-	bool "16MHz"
+config CLOCK_FREQ
+	int "Set the core clock frequency"
+	default "66666666"
+	depends on CLOCK_SET
 	help
-	  Select a 16MHz CPU clock frequency.
+	  Define the CPU clock frequency in use. This is the core clock
+	  frequency, it may or may not be the same as the external clock
+	  crystal fitted to your board. Some processors have an internal
+	  PLL and can have their frequency programmed at run time, others
+	  use internal dividers. In gernal the kernel won't setup a PLL
+	  if it is fitted (there are some expections). This value will be
+	  specific to the exact CPU that you are using.
 
-config CLOCK_20MHz
-	bool "20MHz"
+config CLOCK_DIV
+	int "Set the core/bus clock divide ratio"
+	default "1"
+	depends on CLOCK_SET
 	help
-	  Select a 20MHz CPU clock frequency.
-
-config CLOCK_24MHz
-	bool "24MHz"
-	help
-	  Select a 24MHz CPU clock frequency.
-
-config CLOCK_25MHz
-	bool "25MHz"
-	help
-	  Select a 25MHz CPU clock frequency.
-
-config CLOCK_33MHz
-	bool "33MHz"
-	help
-	  Select a 33MHz CPU clock frequency.
-
-config CLOCK_40MHz
-	bool "40MHz"
-	help
-	  Select a 40MHz CPU clock frequency.
-
-config CLOCK_45MHz
-	bool "45MHz"
-	help
-	  Select a 45MHz CPU clock frequency.
-
-config CLOCK_48MHz
-	bool "48MHz"
-	help
-	  Select a 48MHz CPU clock frequency.
-
-config CLOCK_50MHz
-	bool "50MHz"
-	help
-	  Select a 50MHz CPU clock frequency.
-
-config CLOCK_54MHz
-	bool "54MHz"
-	help
-	  Select a 54MHz CPU clock frequency.
-
-config CLOCK_60MHz
-	bool "60MHz"
-	help
-	  Select a 60MHz CPU clock frequency.
-
-config CLOCK_62_5MHz
-	bool "62.5MHz"
-	help
-	  Select a 62.5MHz CPU clock frequency.
-
-config CLOCK_64MHz
-	bool "64MHz"
-	help
-	  Select a 64MHz CPU clock frequency.
-
-config CLOCK_66MHz
-	bool "66MHz"
-	help
-	  Select a 66MHz CPU clock frequency.
-
-config CLOCK_70MHz
-	bool "70MHz"
-	help
-	  Select a 70MHz CPU clock frequency.
-
-config CLOCK_100MHz
-	bool "100MHz"
-	help
-	  Select a 100MHz CPU clock frequency.
-
-config CLOCK_140MHz
-	bool "140MHz"
-	help
-	  Select a 140MHz CPU clock frequency.
-
-config CLOCK_150MHz
-	bool "150MHz"
-	help
-	  Select a 150MHz CPU clock frequency.
-
-config CLOCK_166MHz
-	bool "166MHz"
-	help
-	  Select a 166MHz CPU clock frequency.
-
-endchoice
+	  On many SoC style CPUs the master CPU clock is also used to drive 
+	  on-chip peripherals. The clock that is distributed to these
+	  peripherals is sometimes a fixed ratio of the master clock
+	  frequency. If so then set this to the divider ration of the
+	  master clock to the peripheral clock. If not sure then select 1.
 
 config OLDMASK
 	bool "Old mask 5307 (1H55J) silicon"
@@ -377,6 +300,12 @@
 	help
 	  Support for the senTec COBRA5272 board.
 
+config AVNET5282
+	bool "Avnet 5282 board support"
+	depends on M528x
+	help
+	  Support for the Avnet 5282 board.  
+	  
 config M5282EVB
 	bool "Motorola M5282EVB board support"
 	depends on M528x
@@ -419,6 +348,18 @@
 	help
 	  Support for the SnapGear SecureEdge/MP3 platform.
 
+config M5329EVB
+	bool "Freescale (Motorola) M5329EVB board support"
+	depends on M532x
+	help
+	  Support for the Freescale (Motorola) M5329EVB board.
+
+config COBRA5329
+	bool "senTec COBRA5329 board support"
+	depends on M532x
+	help
+	  Support for the senTec COBRA5329 board.
+
 config M5407C3
 	bool "Motorola M5407C3 board support"
 	depends on M5407
@@ -487,7 +428,7 @@
 config FREESCALE
 	bool
 	default y
-	depends on (M5206eC3 || M5208EVB || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
+	depends on (M5206eC3 || M5208EVB || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5329EVB || M5407C3)
 
 config HW_FEITH
 	bool
@@ -508,6 +449,11 @@
         bool
 	default y
 	depends on CPU16B
+	
+config AVNET
+	bool
+	default y
+	depends on (AVNET5282)
 
 config LARGE_ALLOCS
 	bool "Allow allocating large blocks (> 1MB) of memory"
@@ -526,38 +472,46 @@
 	  running more threads on a system and also reduces the pressure
 	  on the VM subsystem for higher order allocations.
 
-choice
-	prompt "RAM size"
-	default AUTO
+comment "RAM configuration"
 
-config RAMAUTO
-	bool "AUTO"
-	---help---
-	  Configure the RAM size on your platform. Many platforms can auto
-	  detect this, on those choose the AUTO option. Otherwise set the
-	  RAM size you intend using.
-
-config RAM4MB
-	bool "4MiB"
+config RAMBASE
+	hex "Address of the base of RAM"
+	default "0"
 	help
-	  Set RAM size to be 4MiB.
+	  Define the address that RAM starts at. On many platforms this is
+	  0, the base of the address space. And this is the default. Some
+	  platforms choose to setup their RAM at other addresses within the
+	  processor address space.
 
-config RAM8MB
-	bool "8MiB"
+config RAMSIZE
+	hex "Size of RAM (in bytes)"
+	default "0x400000"
 	help
-	  Set RAM size to be 8MiB.
+	  Define the size of the system RAM. If you select 0 then the
+	  kernel will try to probe the RAM size at runtime. This is not
+	  supported on all CPU types.
 
-config RAM16MB
-	bool "16MiB"
+config VECTORBASE
+	hex "Address of the base of system vectors"
+	default "0"
 	help
-	  Set RAM size to be 16MiB.
+	  Define the address of the the system vectors. Commonly this is
+	  put at the start of RAM, but it doesn't have to be. On ColdFire
+	  platforms this address is programmed into the VBR register, thus
+	  actually setting the address to use.
 
-config RAM32MB
-	bool "32MiB"
+config KERNELBASE
+	hex "Address of the base of kernel code"
+	default "0x400"
 	help
-	  Set RAM size to be 32MiB.
-
-endchoice
+	  Typically on m68k systems the kernel will not start at the base
+	  of RAM, but usually some small offset from it. Define the start
+	  address of the kernel here. The most common setup will have the
+	  processor vectors at the base of RAM and then the start of the
+	  kernel. On some platforms some RAM is reserved for boot loaders
+	  and the kernel starts after that. The 0x400 default was based on
+	  a system with the RAM based at address 0, and leaving enough room
+	  for the theoretical maximum number of 256 vectors.
 
 choice
 	prompt "RAM bus width"
@@ -565,7 +519,7 @@
 
 config RAMAUTOBIT
 	bool "AUTO"
-	---help---
+	help
 	  Select the physical RAM data bus size. Not needed on most platforms,
 	  so you can generally choose AUTO.
 
@@ -599,7 +553,9 @@
 config ROMKERNEL
 	bool "ROM"
 	help
-	  The kernel will be resident in FLASH/ROM when running.
+	  The kernel will be resident in FLASH/ROM when running. This is
+	  often referred to as Execute-in-Place (XIP), since the kernel
+	  code executes from the position it is stored in the FLASH/ROM.
 
 endchoice
 
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 93120b9..99d038e 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -42,7 +42,6 @@
 #include <asm/pgtable.h>
 #endif
 
-unsigned long rom_length;
 unsigned long memory_start;
 unsigned long memory_end;
 
@@ -56,29 +55,29 @@
 {
 }
 
-void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) = NULL;
-void (*mach_tick)( void ) = NULL;
+void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *));
+void (*mach_tick)( void );
 /* machine dependent keyboard functions */
-int (*mach_keyb_init) (void) = NULL;
-int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
-void (*mach_kbd_leds) (unsigned int) = NULL;
+int (*mach_keyb_init) (void);
+int (*mach_kbdrate) (struct kbd_repeat *);
+void (*mach_kbd_leds) (unsigned int);
 /* machine dependent irq functions */
-void (*mach_init_IRQ) (void) = NULL;
-irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
-int (*mach_get_irq_list) (struct seq_file *, void *) = NULL;
-void (*mach_process_int) (int irq, struct pt_regs *fp) = NULL;
+void (*mach_init_IRQ) (void);
+irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
+int (*mach_get_irq_list) (struct seq_file *, void *);
+void (*mach_process_int) (int irq, struct pt_regs *fp);
 void (*mach_trap_init) (void);
 /* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void) = NULL;
-void (*mach_gettod) (int*, int*, int*, int*, int*, int*) = NULL;
-int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
-int (*mach_set_clock_mmss) (unsigned long) = NULL;
-void (*mach_mksound)( unsigned int count, unsigned int ticks ) = NULL;
-void (*mach_reset)( void ) = NULL;
+unsigned long (*mach_gettimeoffset) (void);
+void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
+int (*mach_hwclk) (int, struct hwclk_time*);
+int (*mach_set_clock_mmss) (unsigned long);
+void (*mach_mksound)( unsigned int count, unsigned int ticks );
+void (*mach_reset)( void );
 void (*waitbut)(void) = dummy_waitbut;
-void (*mach_debug_init)(void) = NULL;
-void (*mach_halt)( void ) = NULL;
-void (*mach_power_off)( void ) = NULL;
+void (*mach_debug_init)(void);
+void (*mach_halt)( void );
+void (*mach_power_off)( void );
 
 
 #ifdef CONFIG_M68000
@@ -129,6 +128,9 @@
 #if defined(CONFIG_M5307)
 	#define	CPU "COLDFIRE(m5307)"
 #endif
+#if defined(CONFIG_M532x)
+	#define	CPU "COLDFIRE(m532x)"
+#endif
 #if defined(CONFIG_M5407)
 	#define	CPU "COLDFIRE(m5407)"
 #endif
@@ -267,34 +269,6 @@
 	paging_init();
 }
 
-int get_cpuinfo(char * buffer)
-{
-    char *cpu, *mmu, *fpu;
-    u_long clockfreq;
-
-    cpu = CPU;
-    mmu = "none";
-    fpu = "none";
-
-#ifdef CONFIG_COLDFIRE
-    clockfreq = (loops_per_jiffy*HZ)*3;
-#else
-    clockfreq = (loops_per_jiffy*HZ)*16;
-#endif
-
-    return(sprintf(buffer, "CPU:\t\t%s\n"
-		   "MMU:\t\t%s\n"
-		   "FPU:\t\t%s\n"
-		   "Clocking:\t%lu.%1luMHz\n"
-		   "BogoMips:\t%lu.%02lu\n"
-		   "Calibration:\t%lu loops\n",
-		   cpu, mmu, fpu,
-		   clockfreq/1000000,(clockfreq/100000)%10,
-		   (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
-		   (loops_per_jiffy*HZ)));
-
-}
-
 /*
  *	Get CPU information for use by the procfs.
  */
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
index 8e2c5a8..437f8c6 100644
--- a/arch/m68knommu/kernel/signal.c
+++ b/arch/m68knommu/kernel/signal.c
@@ -608,7 +608,7 @@
 	if (regs->stkadj) {
 		struct pt_regs *tregs =
 			(struct pt_regs *)((ulong)regs + regs->stkadj);
-#if DEBUG
+#if defined(DEBUG)
 		printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
 #endif
 		/* This must be copied with decreasing addresses to
@@ -678,7 +678,7 @@
 	if (regs->stkadj) {
 		struct pt_regs *tregs =
 			(struct pt_regs *)((ulong)regs + regs->stkadj);
-#if DEBUG
+#if defined(DEBUG)
 		printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
 #endif
 		/* This must be copied with decreasing addresses to
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 5bc0684..44ff74e 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -93,12 +93,12 @@
 	if (user_mode(&fp->ptregs))
 		current->thread.esp0 = (unsigned long) fp;
 
-#if DEBUG
+#if defined(DEBUG)
 	printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
 #endif
 
 	die_if_kernel("bad frame format",&fp->ptregs,0);
-#if DEBUG
+#if defined(DEBUG)
 	printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
 #endif
 	force_sig(SIGSEGV, current);
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index a331cc90..6a2f0c6 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -1,7 +1,7 @@
 /*
  *	vmlinux.lds.S -- master linker script for m68knommu arch
  *
- *	(C) Copyright 2002-2004, Greg Ungerer <gerg@snapgear.com>
+ *	(C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
  *
  *	This ends up looking compilcated, because of the number of
  *	address variations for ram and rom/flash layouts. The real
@@ -22,13 +22,7 @@
 #define	ROM_START	0x10c10400
 #define	ROM_LENGTH	0xfec00
 #define	ROM_END		0x10d00000
-#define	RAMVEC_START	0x00000000
-#define	RAMVEC_LENGTH	0x400
-#define	RAM_START	0x10000400
-#define	RAM_LENGTH	0xffc00
-#define	RAM_END		0x10100000
-#define _ramend	_ram_end_notused
-#define	DATA_ADDR	RAM_START
+#define	DATA_ADDR	CONFIG_KERNELBASE
 #endif
 
 /*
@@ -41,11 +35,6 @@
 #define	ROM_START	0x10c10400
 #define	ROM_LENGTH	0x1efc00
 #define	ROM_END		0x10e00000
-#define	RAMVEC_START	0x00000000
-#define	RAMVEC_LENGTH	0x400
-#define	RAM_START	0x00020400
-#define	RAM_LENGTH	0x7dfc00
-#define	RAM_END		0x00800000
 #endif
 #ifdef CONFIG_ROMKERNEL
 #define	ROMVEC_START	0x10c10000
@@ -53,11 +42,6 @@
 #define	ROM_START	0x10c10400
 #define	ROM_LENGTH	0x1efc00
 #define	ROM_END		0x10e00000
-#define	RAMVEC_START	0x00000000
-#define	RAMVEC_LENGTH	0x400
-#define	RAM_START	0x00020000
-#define	RAM_LENGTH	0x600000
-#define	RAM_END		0x00800000
 #endif
 #ifdef CONFIG_HIMEMKERNEL
 #define	ROMVEC_START	0x00600000
@@ -65,141 +49,28 @@
 #define	ROM_START	0x00600400
 #define	ROM_LENGTH	0x1efc00
 #define	ROM_END		0x007f0000
-#define	RAMVEC_START	0x00000000
-#define	RAMVEC_LENGTH	0x400
-#define	RAM_START	0x00020000
-#define	RAM_LENGTH	0x5e0000
-#define	RAM_END		0x00600000
 #endif
 #endif
 
-#ifdef CONFIG_DRAGEN2
-#define	RAM_START	0x10000
-#define	RAM_LENGTH	0x7f0000
-#endif
-
 #ifdef CONFIG_UCQUICC
 #define	ROMVEC_START	0x00000000
 #define	ROMVEC_LENGTH	0x404
 #define	ROM_START	0x00000404
 #define	ROM_LENGTH	0x1ff6fc
 #define	ROM_END		0x00200000
-#define	RAMVEC_START	0x00200000
-#define	RAMVEC_LENGTH	0x404
-#define	RAM_START	0x00200404
-#define	RAM_LENGTH	0x1ff6fc
-#define	RAM_END		0x00400000
-#endif
-
-/*
- *	The standard Arnewsh 5206 board only has 1MiB of ram. Not normally
- *	enough to be useful. Assume the user has fitted something larger,
- *	at least 4MiB in size. No point in not letting the kernel completely
- *	link, it will be obvious if it is too big when they go to load it.
- */
-#if defined(CONFIG_ARN5206)
-#define	RAM_START	0x10000
-#define	RAM_LENGTH	0x3f0000
-#endif
-
-/*
- *	The Motorola 5206eLITE board only has 1MiB of static RAM.
- */
-#if defined(CONFIG_ELITE)
-#define	RAM_START	0x30020000
-#define	RAM_LENGTH	0xe0000
-#endif
-
-/*
- *	All the Motorola eval boards have the same basic arrangement.
- *	The end of RAM will vary depending on how much ram is fitted,
- *	but this isn't important here, we assume at least 4MiB.
- */
-#if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \
-    defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \
-    defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \
-    defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB) || \
-    defined(CONFIG_M5235EVB)
-#define	RAM_START	0x20000
-#define	RAM_LENGTH	0x3e0000
-#endif
-
-/*
- *	The Freescale 5208EVB board has 32MB of RAM.
- */
-#if defined(CONFIG_M5208EVB)
-#define	RAM_START	0x40020000
-#define	RAM_LENGTH	0x01fe0000
-#endif
-
-/*
- *	The senTec COBRA5272 board has nearly the same memory layout as 
- *	the M5272C3. We assume 16MiB ram.
- */
-#if defined(CONFIG_COBRA5272)
-#define RAM_START   0x20000
-#define RAM_LENGTH  0xfe0000
-#endif
-
-#if defined(CONFIG_M5282EVB)
-#define	RAM_START	0x10000
-#define	RAM_LENGTH	0x3f0000
-#endif
-
-/*
- *	The senTec COBRA5282 board has the same memory layout as the M5282EVB.
- */
-#if defined(CONFIG_COBRA5282)
-#define  RAM_START   0x10000
-#define  RAM_LENGTH  0x3f0000
-#endif
-
-
-/*
- *	The EMAC SoM-5282EM module.
- */
-#if defined(CONFIG_SOM5282EM)
-#define  RAM_START   0x10000
-#define  RAM_LENGTH  0xff0000
-#endif
-
-
-/*
- *	These flash boot boards use all of ram for operation. Again the
- *	actual memory size is not important here, assume at least 4MiB.
- *	They currently have no support for running in flash.
- */
-#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
-    defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
-    defined(CONFIG_HW_FEITH)
-#define	RAM_START	0x400
-#define	RAM_LENGTH	0x3ffc00
-#endif
-
-/*
- *	Sneha Boards mimimun memory
- *	The end of RAM will vary depending on how much ram is fitted,
- *	but this isn't important here, we assume at least 4MiB.
- */
-#if defined(CONFIG_CPU16B)   
-#define	RAM_START	0x20000
-#define	RAM_LENGTH	0x3e0000
-#endif
-
-#if defined(CONFIG_MOD5272)
-#define RAM_START	0x02000000
-#define RAM_LENGTH	0x00800000
-#define RAMVEC_START	0x20000000
-#define RAMVEC_LENGTH	0x00000400
 #endif
 
 #if defined(CONFIG_RAMKERNEL)
+#define	RAM_START	CONFIG_KERNELBASE
+#define	RAM_LENGTH	(CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
 #define	TEXT		ram
 #define	DATA		ram
 #define	INIT		ram
 #define	BSS		ram
 #endif
 #if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
+#define	RAM_START	CONFIG_RAMBASE
+#define	RAM_LENGTH	CONFIG_RAMSIZE
 #define	TEXT		rom
 #define	DATA		ram
 #define	INIT		ram
@@ -215,13 +86,7 @@
 ENTRY(_start)
 
 MEMORY {
-#ifdef RAMVEC_START
-	ramvec	: ORIGIN = RAMVEC_START, LENGTH = RAMVEC_LENGTH
-#endif
 	ram	: ORIGIN = RAM_START, LENGTH = RAM_LENGTH
-#ifdef RAM_END
-	eram	: ORIGIN = RAM_END, LENGTH = 0
-#endif
 #ifdef ROM_START
 	romvec	: ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
 	rom	: ORIGIN = ROM_START, LENGTH = ROM_LENGTH
@@ -308,12 +173,6 @@
 		__rom_end = . ;
 	} > erom
 #endif
-#ifdef RAMVEC_START
-	. = RAMVEC_START ;
-	.ramvec : {
-		__ramvec = .;
-	} > ramvec
-#endif
 
 	.data DATA_ADDR : {
 		. = ALIGN(4);
@@ -373,12 +232,5 @@
 		_ebss = . ;
 	} > BSS
 
-#ifdef RAM_END
-	. = RAM_END ;
-	.eram : {
-		__ramend = . ;
-		_ramend = . ;
-	} > eram
-#endif
 }
 
diff --git a/arch/m68knommu/mm/init.c b/arch/m68knommu/mm/init.c
index d79503f..70d1653 100644
--- a/arch/m68knommu/mm/init.c
+++ b/arch/m68knommu/mm/init.c
@@ -63,8 +63,6 @@
 
 unsigned long empty_zero_page;
 
-extern unsigned long rom_length;
-
 void show_mem(void)
 {
     unsigned long i;
@@ -178,11 +176,9 @@
 	initk = (&__init_begin - &__init_end) >> 10;
 
 	tmp = nr_free_pages() << PAGE_SHIFT;
-	printk(KERN_INFO "Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel code, %dk data)\n",
+	printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
 	       tmp >> 10,
 	       len >> 10,
-	       (rom_length > 0) ? ((rom_length >> 10) - codek) : 0,
-	       rom_length >> 10,
 	       codek,
 	       datak
 	       );
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
index 8d1619d..2fd37dc 100644
--- a/arch/m68knommu/platform/5307/Makefile
+++ b/arch/m68knommu/platform/5307/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_M527x)     += pit.o
 obj-$(CONFIG_M5272)	+= timers.o
 obj-$(CONFIG_M5307)	+= config.o timers.o
+obj-$(CONFIG_M532x)	+= timers.o
 obj-$(CONFIG_M528x)     += pit.o
 obj-$(CONFIG_M5407)	+= timers.o
 
diff --git a/arch/m68knommu/platform/5307/entry.S b/arch/m68knommu/platform/5307/entry.S
index 89b180d..9ddf547 100644
--- a/arch/m68knommu/platform/5307/entry.S
+++ b/arch/m68knommu/platform/5307/entry.S
@@ -4,8 +4,8 @@
  *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
  *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
  *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *  Copyright (C) 2004  Macq Electronique SA. (www.macqel.com)
+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
+ *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
  *
  * Based on:
  *
@@ -56,32 +56,27 @@
 .globl inthandler
 .globl fasthandler
 
+enosys:
+	mov.l	#sys_ni_syscall,%d3
+	bra	1f
+
 ENTRY(system_call)
 	SAVE_ALL
 	move	#0x2000,%sr		/* enable intrs again */
 
-	movel	#-LENOSYS,%d2
-	movel	%d2,PT_D0(%sp)		/* default return value in d0 */
-					/* original D0 is in orig_d0 */
-	movel	%d0,%d2
-
-	/* save top of frame */
-	pea	%sp@
-	jbsr	set_esp0
-	addql	#4,%sp
-
-	cmpl	#NR_syscalls,%d2
-	jcc	ret_from_exception
+	cmpl	#NR_syscalls,%d0
+	jcc	enosys
 	lea	sys_call_table,%a0
-	lsll	#2,%d2			/* movel %a0@(%d2:l:4),%d3 */
-	movel	%a0@(%d2),%d3
-	jeq	ret_from_exception
-	lsrl	#2,%d2
+	lsll	#2,%d0			/* movel %a0@(%d0:l:4),%d3 */
+	movel	%a0@(%d0),%d3
+	jeq	enosys
 
+1:
 	movel	%sp,%d2			/* get thread_info pointer */
 	andl	#-THREAD_SIZE,%d2	/* at start of kernel stack */
 	movel	%d2,%a0
-	btst	#TIF_SYSCALL_TRACE,%a0@(TI_FLAGS)
+	movel	%sp,%a0@(THREAD_ESP0)	/* save top of frame */
+	btst	#(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
 	bnes	1f
 
 	movel	%d3,%a0
@@ -126,8 +121,8 @@
 	jne	Lwork_to_do		/* still work to do */
 
 Lreturn:
-	move    #0x2700,%sr		/* disable intrs */
-	movel   sw_usp,%a0		/* get usp */
+	move	#0x2700,%sr		/* disable intrs */
+	movel	sw_usp,%a0		/* get usp */
 	movel	%sp@(PT_PC),%a0@-	/* copy exception program counter */
 	movel	%sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */
 	moveml	%sp@,%d1-%d5/%a0-%a2
@@ -170,7 +165,7 @@
 	movel	%d0,%sp@(PT_ORIG_D0)
 	addql	#1,local_irq_count
 
-	movew   %sp@(PT_FORMATVEC),%d0	/* put exception # in d0 */
+	movew	%sp@(PT_FORMATVEC),%d0	/* put exception # in d0 */
 	andl	#0x03fc,%d0		/* mask out vector only */
 
 	leal	per_cpu__kstat+STAT_IRQ,%a0
@@ -184,7 +179,7 @@
 
 	movel	%sp,%sp@-		/* push regs arg onto stack */
 	movel	%a0@(8),%sp@-		/* push devid arg */
-	movel	%d0,%sp@- 		/* push vector # on stack */
+	movel	%d0,%sp@-		/* push vector # on stack */
 
 	movel	%a0@,%a0		/* get function to call */
 	jbsr	%a0@			/* call vector handler */
@@ -201,7 +196,7 @@
 ENTRY(fasthandler)
 	SAVE_LOCAL
 
-	movew   %sp@(PT_FORMATVEC),%d0
+	movew	%sp@(PT_FORMATVEC),%d0
 	andl	#0x03fc,%d0		/* mask out vector only */
 
 	leal	per_cpu__kstat+STAT_IRQ,%a0
@@ -210,7 +205,7 @@
 	movel	%sp,%sp@-		/* push regs arg onto stack */
 	clrl	%sp@-			/* push devid arg */
 	lsrl	#2,%d0			/* calculate real vector # */
-	movel	%d0,%sp@- 		/* push vector # on stack */
+	movel	%d0,%sp@-		/* push vector # on stack */
 
 	lsll	#4,%d0			/* adjust for array offset */
 	lea	irq_list,%a0
@@ -265,4 +260,3 @@
 	movew	%a1@(TASK_THREAD+THREAD_SR),%d0	/* restore thread status reg */
 	movew	%d0, %sr
 	rts
-
diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S
index c30c462..1d9eb30 100644
--- a/arch/m68knommu/platform/5307/head.S
+++ b/arch/m68knommu/platform/5307/head.S
@@ -3,7 +3,7 @@
 /*
  *	head.S -- common startup code for ColdFire CPUs.
  *
- *	(C) Copyright 1999-2004, Greg Ungerer (gerg@snapgear.com).
+ *	(C) Copyright 1999-2006, Greg Ungerer <gerg@snapgear.com>.
  */
 
 /*****************************************************************************/
@@ -19,47 +19,15 @@
 /*****************************************************************************/
 
 /*
- *	Define fixed memory sizes. Configuration of a fixed memory size
- *	overrides everything else. If the user defined a size we just
- *	blindly use it (they know what they are doing right :-)
- */
-#if defined(CONFIG_RAM32MB)
-#define MEM_SIZE	0x02000000	/* memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define MEM_SIZE	0x01000000	/* memory size 16Mb */
-#elif defined(CONFIG_RAM8MB)
-#define MEM_SIZE	0x00800000	/* memory size 8Mb */
-#elif defined(CONFIG_RAM4MB)
-#define MEM_SIZE	0x00400000	/* memory size 4Mb */
-#elif defined(CONFIG_RAM1MB)
-#define MEM_SIZE	0x00100000	/* memory size 1Mb */
-#endif
-
-/*
- *	Memory size exceptions for special cases. Some boards may be set
- *	for auto memory sizing, but we can't do it that way for some reason.
- *	For example the 5206eLITE board has static RAM, and auto-detecting
- *	the SDRAM will do you no good at all. Same goes for the MOD5272.
- */
-#ifdef CONFIG_RAMAUTO
-#if defined(CONFIG_M5206eLITE)
-#define	MEM_SIZE	0x00100000	/* 1MiB default memory */
-#endif
-#if defined(CONFIG_MOD5272)
-#define MEM_SIZE	0x00800000	/* 8MiB default memory */
-#endif
-#endif /* CONFIG_RAMAUTO */
-
-
-/*
- *	If we don't have a fixed memory size now, then lets build in code
+ *	If we don't have a fixed memory size, then lets build in code
  *	to auto detect the DRAM size. Obviously this is the prefered
- *	method, and should work for most boards (it won't work for those
- *	that do not have their RAM starting at address 0).
+ *	method, and should work for most boards. It won't work for those
+ *	that do not have their RAM starting at address 0, and it only
+ *	works on SDRAM (not boards fitted with SRAM).
  */
-#if defined(MEM_SIZE)
+#if CONFIG_RAMSIZE != 0
 .macro GET_MEM_SIZE
-	movel	#MEM_SIZE,%d0		/* hard coded memory size */
+	movel	#CONFIG_RAMSIZE,%d0	/* hard coded memory size */
 .endm
 
 #elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
@@ -98,37 +66,7 @@
 .endm
 
 #else
-#error "ERROR: I don't know how to determine your boards memory size?"
-#endif
-
-
-/*
- *	Most ColdFire boards have their DRAM starting at address 0.
- *	Notable exception is the 5206eLITE board, another is the MOD5272.
- */
-#if defined(CONFIG_M5206eLITE)
-#define	MEM_BASE	0x30000000
-#endif
-#if defined(CONFIG_MOD5272)
-#define MEM_BASE	0x02000000
-#define VBR_BASE	0x20000000	/* vectors in SRAM */
-#endif
-#if defined(CONFIG_M5208EVB)
-#define MEM_BASE	0x40000000
-#endif
-
-#ifndef MEM_BASE
-#define	MEM_BASE	0x00000000	/* memory base at address 0 */
-#endif
-
-/*
- *	The default location for the vectors is at the base of RAM.
- *	Some boards might like to use internal SRAM or something like
- *	that. If no board specific header defines an alternative then
- *	use the base of RAM.
- */
-#ifndef	VBR_BASE
-#define	VBR_BASE	MEM_BASE	/* vector address */
+#error "ERROR: I don't know how to probe your boards memory size?"
 #endif
 
 /*****************************************************************************/
@@ -191,11 +129,11 @@
 	 *	Create basic memory configuration. Set VBR accordingly,
 	 *	and size memory.
 	 */
-	movel	#VBR_BASE,%a7
+	movel	#CONFIG_VECTORBASE,%a7
 	movec   %a7,%VBR			/* set vectors addr */
 	movel	%a7,_ramvec
 
-	movel	#MEM_BASE,%a7			/* mark the base of RAM */
+	movel	#CONFIG_RAMBASE,%a7		/* mark the base of RAM */
 	movel	%a7,_rambase
 
 	GET_MEM_SIZE				/* macro code determines size */
diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c
index 323f267..ef17474 100644
--- a/arch/m68knommu/platform/5307/pit.c
+++ b/arch/m68knommu/platform/5307/pit.c
@@ -1,11 +1,11 @@
 /***************************************************************************/
 
 /*
- *	pit.c -- Motorola ColdFire PIT timer. Currently this type of
- *	         hardware timer only exists in the Motorola ColdFire
+ *	pit.c -- Freescale ColdFire PIT timer. Currently this type of
+ *	         hardware timer only exists in the Freescale ColdFire
  *		 5270/5271, 5282 and other CPUs.
  *
- *	Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
+ *	Copyright (C) 1999-2006, Greg Ungerer (gerg@snapgear.com)
  *	Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
  *
  */
@@ -18,6 +18,7 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/coldfire.h>
 #include <asm/mcfpit.h>
@@ -25,13 +26,20 @@
 
 /***************************************************************************/
 
+/*
+ *	By default use timer1 as the system clock timer.
+ */
+#define	TA(a)	(MCF_IPSBAR + MCFPIT_BASE1 + (a))
+
+/***************************************************************************/
+
 void coldfire_pit_tick(void)
 {
-	volatile struct mcfpit *tp;
+	unsigned short pcsr;
 
 	/* Reset the ColdFire timer */
-	tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1);
-	tp->pcsr |= MCFPIT_PCSR_PIF;
+	pcsr = __raw_readw(TA(MCFPIT_PCSR));
+	__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
 }
 
 /***************************************************************************/
@@ -40,7 +48,6 @@
 {
 	volatile unsigned char *icrp;
 	volatile unsigned long *imrp;
-	volatile struct mcfpit *tp;
 
 	request_irq(MCFINT_VECBASE + MCFINT_PIT1, handler, SA_INTERRUPT,
 		"ColdFire Timer", NULL);
@@ -53,27 +60,23 @@
 	*imrp &= ~MCFPIT_IMR_IBIT;
 
 	/* Set up PIT timer 1 as poll clock */
-	tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1);
-	tp->pcsr = MCFPIT_PCSR_DISABLE;
-
-	tp->pmr = ((MCF_CLK / 2) / 64) / HZ;
-	tp->pcsr = MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
-		MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64;
+	__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+	__raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR));
+	__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
+		MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
 }
 
 /***************************************************************************/
 
 unsigned long coldfire_pit_offset(void)
 {
-	volatile struct mcfpit *tp;
 	volatile unsigned long *ipr;
 	unsigned long pmr, pcntr, offset;
 
-	tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1);
 	ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
 
-	pmr = *(&tp->pmr);
-	pcntr = *(&tp->pcntr);
+	pmr = __raw_readw(TA(MCFPIT_PMR));
+	pcntr = __raw_readw(TA(MCFPIT_PCNTR));
 
 	/*
 	 * If we are still in the first half of the upcount and a
diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c
index ef49596..83b8b89 100644
--- a/arch/m68knommu/platform/5307/timers.c
+++ b/arch/m68knommu/platform/5307/timers.c
@@ -14,6 +14,7 @@
 #include <linux/param.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
@@ -24,6 +25,11 @@
 /***************************************************************************/
 
 /*
+ *	By default use timer1 as the system clock timer.
+ */
+#define	TA(a)	(MCF_MBAR + MCFTIMER_BASE1 + (a))
+
+/*
  *	Default the timer and vector to use for ColdFire. Some ColdFire
  *	CPU's and some boards may want different. Their sub-architecture
  *	startup code (in config.c) can change these if they want.
@@ -32,8 +38,6 @@
 unsigned int	mcf_profilevector = 31;
 unsigned int	mcf_timerlevel = 5;
 
-static volatile struct mcftimer *mcf_timerp;
-
 /*
  *	These provide the underlying interrupt vector support.
  *	Unfortunately it is a little different on each ColdFire.
@@ -46,20 +50,17 @@
 void coldfire_tick(void)
 {
 	/* Reset the ColdFire timer */
-	mcf_timerp->ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
+	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
 }
 
 /***************************************************************************/
 
 void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
 {
-	/* Set up an internal TIMER as poll clock */
-	mcf_timerp = (volatile struct mcftimer *) (MCF_MBAR + MCFTIMER_BASE1);
-	mcf_timerp->tmr = MCFTIMER_TMR_DISABLE;
-
-	mcf_timerp->trr = (unsigned short) ((MCF_BUSCLK / 16) / HZ);
-	mcf_timerp->tmr = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
-		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE;
+	__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
+	__raw_writew(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR));
+	__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
 
 	request_irq(mcf_timervector, handler, SA_INTERRUPT, "timer", NULL);
 	mcf_settimericr(1, mcf_timerlevel);
@@ -75,13 +76,8 @@
 {
 	unsigned long trr, tcn, offset;
 
-	/*
-	 * The change to pointer and de-reference is to force the compiler
-	 * to read the registers with a single 16bit access. Otherwise it
-	 * does some crazy 8bit read combining.
-	 */
-	tcn = *(&mcf_timerp->tcn);
-	trr = *(&mcf_timerp->trr);
+	tcn = __raw_readw(TA(MCFTIMER_TCN));
+	trr = __raw_readw(TA(MCFTIMER_TRR));
 	offset = (tcn * (1000000 / HZ)) / trr;
 
 	/* Check if we just wrapped the counters and maybe missed a tick */
@@ -95,21 +91,23 @@
 /***************************************************************************/
 
 /*
+ *	By default use timer2 as the profiler clock timer.
+ */
+#define	PA(a)	(MCF_MBAR + MCFTIMER_BASE2 + (a))
+
+/*
  *	Choose a reasonably fast profile timer. Make it an odd value to
  *	try and get good coverage of kernal operations.
  */
 #define	PROFILEHZ	1013
 
-static volatile struct mcftimer *mcf_proftp;
-
 /*
  *	Use the other timer to provide high accuracy profiling info.
  */
-
 void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs)
 {
 	/* Reset ColdFire timer2 */
-	mcf_proftp->ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
+	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
 	if (current->pid)
 		profile_tick(CPU_PROFILING, regs);
 }
@@ -121,12 +119,11 @@
 	printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ);
 
 	/* Set up TIMER 2 as high speed profile clock */
-	mcf_proftp = (volatile struct mcftimer *) (MCF_MBAR + MCFTIMER_BASE2);
-	mcf_proftp->tmr = MCFTIMER_TMR_DISABLE;
+	__raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
 
-	mcf_proftp->trr = (unsigned short) ((MCF_CLK / 16) / PROFILEHZ);
-	mcf_proftp->tmr = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
-		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE;
+	__raw_writew(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
+	__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
 
 	request_irq(mcf_profilevector, coldfire_profile_tick,
 		(SA_INTERRUPT | IRQ_FLG_FAST), "profile timer", NULL);
diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68knommu/platform/532x/Makefile
new file mode 100644
index 0000000..1230180
--- /dev/null
+++ b/arch/m68knommu/platform/532x/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+ifdef CONFIG_FULLDEBUG
+AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
+endif
+
+#obj-y := config.o usb-mcf532x.o spi-mcf532x.o
+obj-y := config.o
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
new file mode 100644
index 0000000..ceef9bc
--- /dev/null
+++ b/arch/m68knommu/platform/532x/config.c
@@ -0,0 +1,486 @@
+/***************************************************************************/
+
+/*
+ *	linux/arch/m68knommu/platform/532x/config.c
+ *
+ *	Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *	Copyright (C) 2000, Lineo (www.lineo.com)
+ *	Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
+ *	Copyright Freescale Semiconductor, Inc 2006
+ *	Copyright (c) 2006, emlix, Sebastian Hess <sh@emlix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcftimer.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+#include <asm/mcfwdebug.h>
+
+/***************************************************************************/
+
+void coldfire_tick(void);
+void coldfire_timer_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+unsigned long coldfire_timer_offset(void);
+void coldfire_trap_init(void);
+void coldfire_reset(void);
+
+extern unsigned int mcf_timervector;
+extern unsigned int mcf_profilevector;
+extern unsigned int mcf_timerlevel;
+
+/***************************************************************************/
+
+/*
+ *	DMA channel base address table.
+ */
+unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { };
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
+
+void mcf_settimericr(unsigned int timer, unsigned int level)
+{
+	volatile unsigned char *icrp;
+	unsigned int icr;
+	unsigned char irq;
+
+	if (timer <= 2) {
+		switch (timer) {
+		case 2:  irq = 33; icr = MCFSIM_ICR_TIMER2; break;
+		default: irq = 32; icr = MCFSIM_ICR_TIMER1; break;
+		}
+		
+		icrp = (volatile unsigned char *) (MCF_MBAR + icr);
+		*icrp = level;
+		mcf_enable_irq0(irq);
+	}
+}
+
+/***************************************************************************/
+
+int mcf_timerirqpending(int timer)
+{
+	unsigned int imr = 0;
+
+	switch (timer) {
+	case 1:  imr = 0x1; break;
+	case 2:  imr = 0x2; break;
+	default: break;
+	}
+	return (mcf_getiprh() & imr);
+}
+
+/***************************************************************************/
+
+void config_BSP(char *commandp, int size)
+{
+	mcf_setimr(MCFSIM_IMR_MASKALL);
+
+#if defined(CONFIG_BOOTPARAM)
+	strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+	commandp[size-1] = 0;
+#else
+	/* Copy command line from FLASH to local buffer... */
+	memcpy(commandp, (char *) 0x4000, 4);
+	if(strncmp(commandp, "kcl ", 4) == 0){
+		memcpy(commandp, (char *) 0x4004, size);
+		commandp[size-1] = 0;
+	} else {
+		memset(commandp, 0, size);
+	}
+#endif
+
+	mcf_timervector = 64+32;
+	mcf_profilevector = 64+33;
+	mach_sched_init = coldfire_timer_init;
+	mach_tick = coldfire_tick;
+	mach_gettimeoffset = coldfire_timer_offset;
+	mach_trap_init = coldfire_trap_init;
+	mach_reset = coldfire_reset;
+
+#ifdef MCF_BDM_DISABLE
+	/*
+	 * Disable the BDM clocking.  This also turns off most of the rest of
+	 * the BDM device.  This is good for EMC reasons. This option is not
+	 * incompatible with the memory protection option.
+	 */
+	wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
+#endif
+}
+
+/***************************************************************************/
+/* Board initialization */
+
+/********************************************************************/
+/* 
+ * PLL min/max specifications
+ */
+#define MAX_FVCO	500000	/* KHz */
+#define MAX_FSYS	80000 	/* KHz */
+#define MIN_FSYS	58333 	/* KHz */
+#define FREF		16000   /* KHz */
+
+
+#define MAX_MFD		135     /* Multiplier */
+#define MIN_MFD		88      /* Multiplier */
+#define BUSDIV		6       /* Divider */
+
+/*
+ * Low Power Divider specifications
+ */
+#define MIN_LPD		(1 << 0)    /* Divider (not encoded) */
+#define MAX_LPD		(1 << 15)   /* Divider (not encoded) */
+#define DEFAULT_LPD	(1 << 1)	/* Divider (not encoded) */
+
+#define SYS_CLK_KHZ	80000
+#define SYSTEM_PERIOD	12.5
+/*
+ *  SDRAM Timing Parameters
+ */  
+#define SDRAM_BL	8	/* # of beats in a burst */
+#define SDRAM_TWR	2	/* in clocks */
+#define SDRAM_CASL	2.5	/* CASL in clocks */
+#define SDRAM_TRCD	2	/* in clocks */
+#define SDRAM_TRP	2	/* in clocks */
+#define SDRAM_TRFC	7	/* in clocks */
+#define SDRAM_TREFI	7800	/* in ns */
+
+#define EXT_SRAM_ADDRESS	(0xC0000000)
+#define FLASH_ADDRESS		(0x00000000)
+#define SDRAM_ADDRESS		(0x40000000)
+
+#define NAND_FLASH_ADDRESS	(0xD0000000)
+
+int sys_clk_khz = 0;
+int sys_clk_mhz = 0;
+
+void wtm_init(void);
+void scm_init(void);
+void gpio_init(void);
+void fbcs_init(void);
+void sdramc_init(void);
+int  clock_pll (int fsys, int flags);
+int  clock_limp (int);
+int  clock_exit_limp (void);
+int  get_sys_clock (void);
+
+asmlinkage void __init sysinit(void)
+{
+	sys_clk_khz = clock_pll(0, 0);
+	sys_clk_mhz = sys_clk_khz/1000;
+	
+	wtm_init();
+	scm_init();
+	gpio_init();
+	fbcs_init();
+	sdramc_init();
+}
+
+void wtm_init(void)
+{
+	/* Disable watchdog timer */
+	MCF_WTM_WCR = 0;
+}
+
+#define MCF_SCM_BCR_GBW		(0x00000100)
+#define MCF_SCM_BCR_GBR		(0x00000200)
+
+void scm_init(void)
+{
+	/* All masters are trusted */
+	MCF_SCM_MPR = 0x77777777;
+    
+	/* Allow supervisor/user, read/write, and trusted/untrusted
+	   access to all slaves */
+	MCF_SCM_PACRA = 0;
+	MCF_SCM_PACRB = 0;
+	MCF_SCM_PACRC = 0;
+	MCF_SCM_PACRD = 0;
+	MCF_SCM_PACRE = 0;
+	MCF_SCM_PACRF = 0;
+
+	/* Enable bursts */
+	MCF_SCM_BCR = (MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW);
+}
+
+
+void fbcs_init(void)
+{
+	MCF_GPIO_PAR_CS = 0x0000003E;
+
+	/* Latch chip select */
+	MCF_FBCS1_CSAR = 0x10080000;
+
+	MCF_FBCS1_CSCR = 0x002A3780;
+	MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V);
+
+	/* Initialize latch to drive signals to inactive states */
+	*((u16 *)(0x10080000)) = 0xFFFF;
+
+	/* External SRAM */
+	MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS;
+	MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16
+			| MCF_FBCS_CSCR_AA
+			| MCF_FBCS_CSCR_SBM
+			| MCF_FBCS_CSCR_WS(1));
+	MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K
+			| MCF_FBCS_CSMR_V);
+
+	/* Boot Flash connected to FBCS0 */
+	MCF_FBCS0_CSAR = FLASH_ADDRESS;
+	MCF_FBCS0_CSCR = (MCF_FBCS_CSCR_PS_16
+			| MCF_FBCS_CSCR_BEM
+			| MCF_FBCS_CSCR_AA
+			| MCF_FBCS_CSCR_SBM
+			| MCF_FBCS_CSCR_WS(7));
+	MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_32M
+			| MCF_FBCS_CSMR_V);
+}
+
+void sdramc_init(void)
+{
+	/*
+	 * Check to see if the SDRAM has already been initialized
+	 * by a run control tool
+	 */
+	if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) {
+		/* SDRAM chip select initialization */
+		
+		/* Initialize SDRAM chip select */
+		MCF_SDRAMC_SDCS0 = (0
+			| MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS)
+			| MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE));
+
+	/*
+	 * Basic configuration and initialization
+	 */
+	MCF_SDRAMC_SDCFG1 = (0
+		| MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5 ))
+		| MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1)
+		| MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL*2) + 2))
+		| MCF_SDRAMC_SDCFG1_ACT2RW((int)((SDRAM_TRCD ) + 0.5))
+		| MCF_SDRAMC_SDCFG1_PRE2ACT((int)((SDRAM_TRP ) + 0.5))
+		| MCF_SDRAMC_SDCFG1_REF2ACT((int)(((SDRAM_TRFC) ) + 0.5))
+		| MCF_SDRAMC_SDCFG1_WTLAT(3));
+	MCF_SDRAMC_SDCFG2 = (0
+		| MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL/2 + 1)
+		| MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL/2 + SDRAM_TWR)
+		| MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL+SDRAM_BL/2-1.0)+0.5))
+		| MCF_SDRAMC_SDCFG2_BL(SDRAM_BL-1));
+
+            
+	/*
+	 * Precharge and enable write to SDMR
+	 */
+        MCF_SDRAMC_SDCR = (0
+		| MCF_SDRAMC_SDCR_MODE_EN
+		| MCF_SDRAMC_SDCR_CKE
+		| MCF_SDRAMC_SDCR_DDR
+		| MCF_SDRAMC_SDCR_MUX(1)
+		| MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI/(SYSTEM_PERIOD*64)) - 1) + 0.5))
+		| MCF_SDRAMC_SDCR_PS_16
+		| MCF_SDRAMC_SDCR_IPALL);            
+
+	/*
+	 * Write extended mode register
+	 */
+	MCF_SDRAMC_SDMR = (0
+		| MCF_SDRAMC_SDMR_BNKAD_LEMR
+		| MCF_SDRAMC_SDMR_AD(0x0)
+		| MCF_SDRAMC_SDMR_CMD);
+
+	/*
+	 * Write mode register and reset DLL
+	 */
+	MCF_SDRAMC_SDMR = (0
+		| MCF_SDRAMC_SDMR_BNKAD_LMR
+		| MCF_SDRAMC_SDMR_AD(0x163)
+		| MCF_SDRAMC_SDMR_CMD);
+
+	/*
+	 * Execute a PALL command
+	 */
+	MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL;
+
+	/*
+	 * Perform two REF cycles
+	 */
+	MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
+	MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
+
+	/*
+	 * Write mode register and clear reset DLL
+	 */
+	MCF_SDRAMC_SDMR = (0
+		| MCF_SDRAMC_SDMR_BNKAD_LMR
+		| MCF_SDRAMC_SDMR_AD(0x063)
+		| MCF_SDRAMC_SDMR_CMD);
+				
+	/*
+	 * Enable auto refresh and lock SDMR
+	 */
+	MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN;
+	MCF_SDRAMC_SDCR |= (0
+		| MCF_SDRAMC_SDCR_REF
+		| MCF_SDRAMC_SDCR_DQS_OE(0xC));
+	}
+}
+
+void gpio_init(void)
+{
+	/* Enable UART0 pins */
+	MCF_GPIO_PAR_UART = ( 0
+		| MCF_GPIO_PAR_UART_PAR_URXD0
+		| MCF_GPIO_PAR_UART_PAR_UTXD0);
+
+	/* Initialize TIN3 as a GPIO output to enable the write
+	   half of the latch */
+	MCF_GPIO_PAR_TIMER = 0x00;
+	MCF_GPIO_PDDR_TIMER = 0x08;
+	MCF_GPIO_PCLRR_TIMER = 0x0;
+
+}
+
+int clock_pll(int fsys, int flags)
+{
+	int fref, temp, fout, mfd;
+	u32 i;
+
+	fref = FREF;
+        
+	if (fsys == 0) {
+		/* Return current PLL output */
+		mfd = MCF_PLL_PFDR;
+
+		return (fref * mfd / (BUSDIV * 4));
+	}
+
+	/* Check bounds of requested system clock */
+	if (fsys > MAX_FSYS)
+		fsys = MAX_FSYS;
+	if (fsys < MIN_FSYS)
+		fsys = MIN_FSYS;
+
+	/* Multiplying by 100 when calculating the temp value,
+	   and then dividing by 100 to calculate the mfd allows
+	   for exact values without needing to include floating
+	   point libraries. */
+	temp = 100 * fsys / fref;
+	mfd = 4 * BUSDIV * temp / 100;
+    	    	    	
+	/* Determine the output frequency for selected values */
+	fout = (fref * mfd / (BUSDIV * 4));
+
+	/*
+	 * Check to see if the SDRAM has already been initialized.
+	 * If it has then the SDRAM needs to be put into self refresh
+	 * mode before reprogramming the PLL.
+	 */
+	if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
+		/* Put SDRAM into self refresh mode */
+		MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_CKE;
+
+	/*
+	 * Initialize the PLL to generate the new system clock frequency.
+	 * The device must be put into LIMP mode to reprogram the PLL.
+	 */
+
+	/* Enter LIMP mode */
+	clock_limp(DEFAULT_LPD);
+     					
+	/* Reprogram PLL for desired fsys */
+	MCF_PLL_PODR = (0
+		| MCF_PLL_PODR_CPUDIV(BUSDIV/3)
+		| MCF_PLL_PODR_BUSDIV(BUSDIV));
+						
+	MCF_PLL_PFDR = mfd;
+		
+	/* Exit LIMP mode */
+	clock_exit_limp();
+	
+	/*
+	 * Return the SDRAM to normal operation if it is in use.
+	 */
+	if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
+		/* Exit self refresh mode */
+		MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_CKE;
+
+	/* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
+	MCF_SDRAMC_LIMP_FIX = MCF_SDRAMC_REFRESH;
+
+	/* wait for DQS logic to relock */
+	for (i = 0; i < 0x200; i++)
+		;
+
+	return fout;
+}
+
+int clock_limp(int div)
+{
+	u32 temp;
+
+	/* Check bounds of divider */
+	if (div < MIN_LPD)
+		div = MIN_LPD;
+	if (div > MAX_LPD)
+		div = MAX_LPD;
+    
+	/* Save of the current value of the SSIDIV so we don't
+	   overwrite the value*/
+	temp = (MCF_CCM_CDR & MCF_CCM_CDR_SSIDIV(0xF));
+      
+	/* Apply the divider to the system clock */
+	MCF_CCM_CDR = ( 0
+		| MCF_CCM_CDR_LPDIV(div)
+		| MCF_CCM_CDR_SSIDIV(temp));
+    
+	MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LIMP;
+    
+	return (FREF/(3*(1 << div)));
+}
+
+int clock_exit_limp(void)
+{
+	int fout;
+	
+	/* Exit LIMP mode */
+	MCF_CCM_MISCCR = (MCF_CCM_MISCCR & ~ MCF_CCM_MISCCR_LIMP);
+
+	/* Wait for PLL to lock */
+	while (!(MCF_CCM_MISCCR & MCF_CCM_MISCCR_PLL_LOCK))
+		;
+	
+	fout = get_sys_clock();
+
+	return fout;
+}
+
+int get_sys_clock(void)
+{
+	int divider;
+	
+	/* Test to see if device is in LIMP mode */
+	if (MCF_CCM_MISCCR & MCF_CCM_MISCCR_LIMP) {
+		divider = MCF_CCM_CDR & MCF_CCM_CDR_LPDIV(0xF);
+		return (FREF/(2 << divider));
+	}
+	else
+		return ((FREF * MCF_PLL_PFDR) / (BUSDIV * 4));
+}
diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68knommu/platform/68328/head-pilot.S
index c46775f..46b3604 100644
--- a/arch/m68knommu/platform/68328/head-pilot.S
+++ b/arch/m68knommu/platform/68328/head-pilot.S
@@ -21,7 +21,6 @@
 .global _start
 
 .global _rambase
-.global __ramvec
 .global _ramvec
 .global _ramstart
 .global _ramend
@@ -121,7 +120,7 @@
 	DBG_PUTC('B')
 
 	/* Copy command line from beginning of RAM (+16) to end of bss */
-	movel	#__ramvec, %d7
+	movel	#CONFIG_VECTORBASE, %d7
 	addl	#16, %d7
 	moveal	%d7, %a0
 	moveal	#_ebss, %a1
diff --git a/arch/m68knommu/platform/68328/head-ram.S b/arch/m68knommu/platform/68328/head-ram.S
index 6bdc9bc..e8dc924 100644
--- a/arch/m68knommu/platform/68328/head-ram.S
+++ b/arch/m68knommu/platform/68328/head-ram.S
@@ -1,10 +1,7 @@
 #include <linux/config.h>
 
 	.global __main
-	.global __ram_start
-	.global __ram_end
 	.global __rom_start
-	.global __rom_end
 
         .global _rambase
         .global _ramstart
@@ -12,6 +9,7 @@
 	.global splash_bits
 	.global _start
 	.global _stext
+	.global _edata
 
 #define DEBUG
 #define ROM_OFFSET 0x10C00000
@@ -73,7 +71,7 @@
 #ifdef CONFIG_RELOCATE
 	/* Copy me to RAM */
 	moveal	#__rom_start, %a0
-	moveal	#__ram_start, %a1
+	moveal	#_stext, %a1
 	moveal	#_edata, %a2
 
 	/* Copy %a0 to %a1 until %a1 == %a2 */
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index a9bf6cc..676e868 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -13,6 +13,7 @@
 #include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/ptrace.h>
+#include <linux/resource.h>
 
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
@@ -540,8 +541,6 @@
 #define IRIX_P_PGID   2
 #define IRIX_P_ALL    7
 
-extern int getrusage(struct task_struct *, int, struct rusage __user *);
-
 #define W_EXITED     1
 #define W_TRAPPED    2
 #define W_STOPPED    4
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 19e1ef4..1137dd6 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -31,6 +31,7 @@
 #include <linux/socket.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/resource.h>
 
 #include <asm/ptrace.h>
 #include <asm/page.h>
@@ -235,7 +236,6 @@
 #undef DEBUG_PROCGRPS
 
 extern unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt);
-extern int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
 extern char *prom_getenv(char *name);
 extern long prom_setenv(char *name, char *value);
 
diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c
index e5eceed..8bd9b84 100644
--- a/arch/mips/momentum/ocelot_g/gt-irq.c
+++ b/arch/mips/momentum/ocelot_g/gt-irq.c
@@ -59,7 +59,7 @@
  * bit_num   - Indicates which bit number in the cause register
  *
  * Outputs :
- * 1 if succesful, 0 if failure
+ * 1 if successful, 0 if failure
  */
 int enable_galileo_irq(int int_cause, int bit_num)
 {
@@ -83,7 +83,7 @@
  * bit_num   - Indicates which bit number in the cause register
  *
  * Outputs :
- * 1 if succesful, 0 if failure
+ * 1 if successful, 0 if failure
  */
 int disable_galileo_irq(int int_cause, int bit_num)
 {
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
index c31e4cf..65eb554 100644
--- a/arch/mips/oprofile/common.c
+++ b/arch/mips/oprofile/common.c
@@ -38,7 +38,7 @@
 
 	for (i = 0; i < model->num_counters; ++i) {
 		struct dentry *dir;
-		char buf[3];
+		char buf[4];
 
 		snprintf(buf, sizeof buf, "%d", i);
 		dir = oprofilefs_mkdir(sb, root, buf);
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
index a9c58e0..8134220 100644
--- a/arch/mips/sgi-ip22/ip22-reset.c
+++ b/arch/mips/sgi-ip22/ip22-reset.c
@@ -34,7 +34,7 @@
 #define POWERDOWN_TIMEOUT	120
 
 /*
- * Blink frequency during reboot grace period and when paniced.
+ * Blink frequency during reboot grace period and when panicked.
  */
 #define POWERDOWN_FREQ		(HZ / 4)
 #define PANIC_FREQ		(HZ / 8)
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
index ab9d9ce..79ddb46 100644
--- a/arch/mips/sgi-ip32/ip32-reset.c
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -28,13 +28,13 @@
 
 #define POWERDOWN_TIMEOUT	120
 /*
- * Blink frequency during reboot grace period and when paniced.
+ * Blink frequency during reboot grace period and when panicked.
  */
 #define POWERDOWN_FREQ		(HZ / 4)
 #define PANIC_FREQ		(HZ / 8)
 
 static struct timer_list power_timer, blink_timer, debounce_timer;
-static int has_paniced, shuting_down;
+static int has_panicked, shuting_down;
 
 static void ip32_machine_restart(char *command) __attribute__((noreturn));
 static void ip32_machine_halt(void) __attribute__((noreturn));
@@ -109,7 +109,7 @@
 	}
 	CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A);
 
-	if (has_paniced)
+	if (has_panicked)
 		ip32_machine_restart(NULL);
 
 	enable_irq(MACEISA_RTC_IRQ);
@@ -117,7 +117,7 @@
 
 static inline void ip32_power_button(void)
 {
-	if (has_paniced)
+	if (has_panicked)
 		return;
 
 	if (shuting_down || kill_proc(1, SIGINT, 1)) {
@@ -161,9 +161,9 @@
 {
 	unsigned long led;
 
-	if (has_paniced)
+	if (has_panicked)
 		return NOTIFY_DONE;
-	has_paniced = 1;
+	has_panicked = 1;
 
 	/* turn off the green LED */
 	led = mace->perif.ctrl.misc | MACEISA_LED_GREEN;
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index dbcb859..e253a45 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -179,7 +179,7 @@
 
 	/*
 	 * This function is only called after the system
-	 * has paniced or is otherwise in a critical state.
+	 * has panicked or is otherwise in a critical state.
 	 * The minimum amount of code to allow a kexec'd kernel
 	 * to run successfully needs to happen here.
 	 *
diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c
index 4436061..cbaa341 100644
--- a/arch/powerpc/kernel/machine_kexec_32.c
+++ b/arch/powerpc/kernel/machine_kexec_32.c
@@ -30,8 +30,8 @@
  */
 void default_machine_kexec(struct kimage *image)
 {
-	const extern unsigned char relocate_new_kernel[];
-	const extern unsigned int relocate_new_kernel_size;
+	extern const unsigned char relocate_new_kernel[];
+	extern const unsigned int relocate_new_kernel_size;
 	unsigned long page_list;
 	unsigned long reboot_code_buffer, reboot_code_buffer_phys;
 	relocate_new_kernel_t rnk;
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index c858eb4..b5431cc 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -1654,7 +1654,6 @@
 		return -EINVAL;
 
 	vma->vm_pgoff = offset >> PAGE_SHIFT;
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
 	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
 						  vma->vm_page_prot,
 						  mmap_state, write_combine);
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 5ad87c4..247937d 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -877,7 +877,6 @@
 		return -EINVAL;
 
 	vma->vm_pgoff = offset >> PAGE_SHIFT;
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
 	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
 						  vma->vm_page_prot,
 						  mmap_state, write_combine);
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index 2b87f82..2ab8f2b 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -115,8 +115,6 @@
 {
 	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
 
-	vma->vm_flags |= VM_SHM | VM_LOCKED;
-
 	if ((vma->vm_end - vma->vm_start) > dp->size)
 		return -EINVAL;
 
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index d209075..7dd5dab 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -102,7 +102,7 @@
 u64 tb_to_xs;
 unsigned tb_to_us;
 
-#define TICKLEN_SCALE	(SHIFT_SCALE - 10)
+#define TICKLEN_SCALE	TICK_LENGTH_SHIFT
 u64 last_tick_len;	/* units are ns / 2^TICKLEN_SCALE */
 u64 ticklen_to_xs;	/* 0.64 fraction */
 
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 91a6e04..52f5659 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
+#include <linux/backlight.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -105,10 +106,18 @@
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac)) {
-		set_backlight_enable(1);
-		set_backlight_level(BACKLIGHT_MAX);
+	mutex_lock(&pmac_backlight_mutex);
+	if (machine_is(powermac) && pmac_backlight) {
+		struct backlight_properties *props;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+		props->brightness = props->max_brightness;
+		props->power = FB_BLANK_UNBLANK;
+		props->update_status(pmac_backlight);
+		up(&pmac_backlight->sem);
 	}
+	mutex_unlock(&pmac_backlight_mutex);
 #endif
 	printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index fdbba42..a0a9e1e 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -40,6 +40,40 @@
 #include <asm/kdebug.h>
 #include <asm/siginfo.h>
 
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+/* Hook to register for page fault notifications */
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	struct die_args args = {
+		.regs = regs,
+		.str = str,
+		.err = err,
+		.trapnr = trap,
+		.signr = sig
+	};
+	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	return NOTIFY_DONE;
+}
+#endif
+
 /*
  * Check whether the instruction at regs->nip is a store using
  * an update addressing form which will update r1.
@@ -142,7 +176,7 @@
 	is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
-	if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, error_code,
+	if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, error_code,
 				11, SIGSEGV) == NOTIFY_STOP)
 		return 0;
 
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 27ad56b..fd0bbbe 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -94,7 +94,7 @@
 
 	for (i = 0; i < model->num_counters; ++i) {
 		struct dentry *dir;
-		char buf[3];
+		char buf[4];
 
 		snprintf(buf, sizeof buf, "%d", i);
 		dir = oprofilefs_mkdir(sb, root, buf);
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 2dfde61..ce696c1 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -89,7 +89,7 @@
 	struct device_node *cpu;
 
 	/* Build local fast map of CPUs */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
 
 	/* Find maps for each device tree CPU */
@@ -110,7 +110,7 @@
 			return;
 		}
 		map->cpu_node = cpu;
-		for_each_cpu(i)
+		for_each_possible_cpu(i)
 			if (cbe_thread_map[i].cpu_node == cpu)
 				cbe_thread_map[i].regs = map;
 
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index f4e2d88..1bbf822 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -180,7 +180,7 @@
 	unsigned long regs;
 	struct iic *iic;
 
-	for_each_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		iic = &per_cpu(iic, cpu);
 		nodeid = cpu/2;
 
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 80c0266..7854a38 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -1150,7 +1150,7 @@
 	return mask;
 }
 
-static int spufs_mfc_flush(struct file *file)
+static int spufs_mfc_flush(struct file *file, fl_owner_t id)
 {
 	struct spu_context *ctx = file->private_data;
 	int ret;
@@ -1176,7 +1176,7 @@
 static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
 			   int datasync)
 {
-	return spufs_mfc_flush(file);
+	return spufs_mfc_flush(file, NULL);
 }
 
 static int spufs_mfc_fasync(int fd, struct file *file, int on)
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index b30e55d..3068b42 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -2100,7 +2100,7 @@
  * @spu: pointer to SPU iomem structure.
  *
  * Perform harvest + restore, as we may not be coming
- * from a previous succesful save operation, and the
+ * from a previous successful save operation, and the
  * hardware state is unknown.
  */
 int spu_restore(struct spu_state *new, struct spu *spu)
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index 8be2f7d..498b042 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -3,200 +3,148 @@
  * Contains support for the backlight.
  *
  *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *   Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  *
  */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <linux/console.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
 #include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
 #include <asm/backlight.h>
 
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#define OLD_BACKLIGHT_MAX 15
 
-static struct backlight_controller *backlighter;
-static void* backlighter_data;
-static int backlight_autosave;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-static int backlight_req_level = -1;
-static int backlight_req_enable = -1;
+/* Protect the pmac_backlight variable */
+DEFINE_MUTEX(pmac_backlight_mutex);
 
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+/* Main backlight storage
+ *
+ * Backlight drivers in this variable are required to have the "props"
+ * attribute set and to have an update_status function.
+ *
+ * We can only store one backlight here, but since Apple laptops have only one
+ * internal display, it doesn't matter. Other backlight drivers can be used
+ * independently.
+ *
+ * Lock ordering:
+ * pmac_backlight_mutex (global, main backlight)
+ *   pmac_backlight->sem (backlight class)
+ */
+struct backlight_device *pmac_backlight;
 
-void register_backlight_controller(struct backlight_controller *ctrler,
-					  void *data, char *type)
+int pmac_has_backlight_type(const char *type)
 {
-	struct device_node* bk_node;
-	char *prop;
-	int valid = 0;
+	struct device_node* bk_node = find_devices("backlight");
 
-	/* There's already a matching controller, bail out */
-	if (backlighter != NULL)
-		return;
-
-	bk_node = find_devices("backlight");
-
-#ifdef CONFIG_ADB_PMU
-	/* Special case for the old PowerBook since I can't test on it */
-	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-		|| machine_is_compatible("AAPL,3500");
-	if ((backlight_autosave
-	     || machine_is_compatible("AAPL,PowerBook1998")
-	     || machine_is_compatible("PowerBook1,1"))
-	    && !strcmp(type, "pmu"))
-		valid = 1;
-#endif
 	if (bk_node) {
-		prop = get_property(bk_node, "backlight-control", NULL);
-		if (prop && !strncmp(prop, type, strlen(type)))
-			valid = 1;
-	}
-	if (!valid)
-		return;
-	backlighter = ctrler;
-	backlighter_data = data;
-
-	if (bk_node && !backlight_autosave)
-		prop = get_property(bk_node, "bklt", NULL);
-	else
-		prop = NULL;
-	if (prop) {
-		backlight_level = ((*prop)+1) >> 1;
-		if (backlight_level > BACKLIGHT_MAX)
-			backlight_level = BACKLIGHT_MAX;
+		char *prop = get_property(bk_node, "backlight-control", NULL);
+		if (prop && strncmp(prop, type, strlen(type)) == 0)
+			return 1;
 	}
 
-#ifdef CONFIG_ADB_PMU
-	if (backlight_autosave) {
-		struct adb_request req;
-		pmu_request(&req, NULL, 2, 0xd9, 0);
-		while (!req.complete)
-			pmu_poll();
-		backlight_level = req.reply[0] >> 4;
-	}
-#endif
-	acquire_console_sem();
-	if (!backlighter->set_enable(1, backlight_level, data))
-		backlight_enabled = 1;
-	release_console_sem();
-
-	printk(KERN_INFO "Registered \"%s\" backlight controller,"
-	       "level: %d/15\n", type, backlight_level);
-}
-EXPORT_SYMBOL(register_backlight_controller);
-
-void unregister_backlight_controller(struct backlight_controller
-					    *ctrler, void *data)
-{
-	/* We keep the current backlight level (for now) */
-	if (ctrler == backlighter && data == backlighter_data)
-		backlighter = NULL;
-}
-EXPORT_SYMBOL(unregister_backlight_controller);
-
-static int __set_backlight_enable(int enable)
-{
-	int rc;
-
-	if (!backlighter)
-		return -ENODEV;
-	acquire_console_sem();
-	rc = backlighter->set_enable(enable, backlight_level,
-				     backlighter_data);
-	if (!rc)
-		backlight_enabled = enable;
-	release_console_sem();
-	return rc;
-}
-int set_backlight_enable(int enable)
-{
-	if (!backlighter)
-		return -ENODEV;
-	backlight_req_enable = enable;
-	schedule_work(&backlight_work);
 	return 0;
 }
 
-EXPORT_SYMBOL(set_backlight_enable);
-
-int get_backlight_enable(void)
+int pmac_backlight_curve_lookup(struct fb_info *info, int value)
 {
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_enabled;
-}
-EXPORT_SYMBOL(get_backlight_enable);
+	int level = (FB_BACKLIGHT_LEVELS - 1);
 
-static int __set_backlight_level(int level)
-{
-	int rc = 0;
+	if (info && info->bl_dev) {
+		int i, max = 0;
 
-	if (!backlighter)
-		return -ENODEV;
-	if (level < BACKLIGHT_MIN)
-		level = BACKLIGHT_OFF;
-	if (level > BACKLIGHT_MAX)
-		level = BACKLIGHT_MAX;
-	acquire_console_sem();
-	if (backlight_enabled)
-		rc = backlighter->set_level(level, backlighter_data);
-	if (!rc)
-		backlight_level = level;
-	release_console_sem();
-	if (!rc && !backlight_autosave) {
-		level <<=1;
-		if (level & 0x10)
-			level |= 0x01;
-		// -- todo: save to property "bklt"
+		/* Look for biggest value */
+		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
+			max = max((int)info->bl_curve[i], max);
+
+		/* Look for nearest value */
+		for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
+			int diff = abs(info->bl_curve[i] - value);
+			if (diff < max) {
+				max = diff;
+				level = i;
+			}
+		}
+
 	}
-	return rc;
-}
-int set_backlight_level(int level)
-{
-	if (!backlighter)
-		return -ENODEV;
-	backlight_req_level = level;
-	schedule_work(&backlight_work);
-	return 0;
+
+	return level;
 }
 
-EXPORT_SYMBOL(set_backlight_level);
-
-int get_backlight_level(void)
+static void pmac_backlight_key(int direction)
 {
-	if (!backlighter)
-		return -ENODEV;
-	return backlight_level;
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		struct backlight_properties *props;
+		int brightness;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+
+		brightness = props->brightness +
+			((direction?-1:1) * (props->max_brightness / 15));
+
+		if (brightness < 0)
+			brightness = 0;
+		else if (brightness > props->max_brightness)
+			brightness = props->max_brightness;
+
+		props->brightness = brightness;
+		props->update_status(pmac_backlight);
+
+		up(&pmac_backlight->sem);
+	}
+	mutex_unlock(&pmac_backlight_mutex);
 }
-EXPORT_SYMBOL(get_backlight_level);
 
-static void backlight_callback(void *dummy)
+void pmac_backlight_key_up()
 {
-	int level, enable;
+	pmac_backlight_key(0);
+}
 
-	do {
-		level = backlight_req_level;
-		enable = backlight_req_enable;
-		mb();
+void pmac_backlight_key_down()
+{
+	pmac_backlight_key(1);
+}
 
-		if (level >= 0)
-			__set_backlight_level(level);
-		if (enable >= 0)
-			__set_backlight_enable(enable);
-	} while(cmpxchg(&backlight_req_level, level, -1) != level ||
-		cmpxchg(&backlight_req_enable, enable, -1) != enable);
+int pmac_backlight_set_legacy_brightness(int brightness)
+{
+	int error = -ENXIO;
+
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		struct backlight_properties *props;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+		props->brightness = brightness *
+			props->max_brightness / OLD_BACKLIGHT_MAX;
+		props->update_status(pmac_backlight);
+		up(&pmac_backlight->sem);
+
+		error = 0;
+	}
+	mutex_unlock(&pmac_backlight_mutex);
+
+	return error;
+}
+
+int pmac_backlight_get_legacy_brightness()
+{
+	int result = -ENXIO;
+
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		struct backlight_properties *props;
+
+		down(&pmac_backlight->sem);
+		props = pmac_backlight->props;
+		result = props->brightness *
+			OLD_BACKLIGHT_MAX / props->max_brightness;
+		up(&pmac_backlight->sem);
+	}
+	mutex_unlock(&pmac_backlight_mutex);
+
+	return result;
 }
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index 98c23ae..c37a849 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -287,7 +287,7 @@
  * find the pci device that corresponds to a given address.
  * This routine scans all pci busses to build the cache.
  * Must be run late in boot process, after the pci controllers
- * have been scaned for devices (after all device resources are known).
+ * have been scanned for devices (after all device resources are known).
  */
 void __init pci_addr_cache_build(void)
 {
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 4735b41..0741df8 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -26,9 +26,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
index 84d65a8..a469ba4 100644
--- a/arch/ppc/kernel/machine_kexec.c
+++ b/arch/ppc/kernel/machine_kexec.c
@@ -25,8 +25,8 @@
 				unsigned long reboot_code_buffer,
 				unsigned long start_address) ATTRIB_NORET;
 
-const extern unsigned char relocate_new_kernel[];
-const extern unsigned int relocate_new_kernel_size;
+extern const unsigned char relocate_new_kernel[];
+extern const unsigned int relocate_new_kernel_size;
 
 void machine_shutdown(void)
 {
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 809673a..d20accf 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1032,7 +1032,6 @@
 		return -EINVAL;
 
 	vma->vm_pgoff = offset >> PAGE_SHIFT;
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
 	vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
 						  vma->vm_page_prot,
 						  mmap_state, write_combine);
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index c5ca2dc..5713c7e 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -37,10 +37,10 @@
 	int key_len;
 };
 
-static int aes_set_key(void *ctx, const u8 *in_key, unsigned int key_len,
-		       u32 *flags)
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len, u32 *flags)
 {
-	struct s390_aes_ctx *sctx = ctx;
+	struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	switch (key_len) {
 	case 16:
@@ -70,9 +70,9 @@
 	return -EINVAL;
 }
 
-static void aes_encrypt(void *ctx, u8 *out, const u8 *in)
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	const struct s390_aes_ctx *sctx = ctx;
+	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	switch (sctx->key_len) {
 	case 16:
@@ -90,9 +90,9 @@
 	}
 }
 
-static void aes_decrypt(void *ctx, u8 *out, const u8 *in)
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	const struct s390_aes_ctx *sctx = ctx;
+	const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	switch (sctx->key_len) {
 	case 16:
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index e3c37aa..b3f7496 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -44,10 +44,10 @@
 	u8 key[DES3_192_KEY_SIZE];
 };
 
-static int des_setkey(void *ctx, const u8 *key, unsigned int keylen,
-		      u32 *flags)
+static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
+		      unsigned int keylen, u32 *flags)
 {
-	struct crypt_s390_des_ctx *dctx = ctx;
+	struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
 	int ret;
 
 	/* test if key is valid (not a weak key) */
@@ -57,16 +57,16 @@
 	return ret;
 }
 
-static void des_encrypt(void *ctx, u8 *out, const u8 *in)
+static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct crypt_s390_des_ctx *dctx = ctx;
+	struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
 }
 
-static void des_decrypt(void *ctx, u8 *out, const u8 *in)
+static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct crypt_s390_des_ctx *dctx = ctx;
+	struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
 }
@@ -166,11 +166,11 @@
  *   Implementers MUST reject keys that exhibit this property.
  *
  */
-static int des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen,
-			   u32 *flags)
+static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
+			   unsigned int keylen, u32 *flags)
 {
 	int i, ret;
-	struct crypt_s390_des3_128_ctx *dctx = ctx;
+	struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
 	const u8* temp_key = key;
 
 	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
@@ -186,17 +186,17 @@
 	return 0;
 }
 
-static void des3_128_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_128_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_128_ctx *dctx = ctx;
+	struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
 		      DES3_128_BLOCK_SIZE);
 }
 
-static void des3_128_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_128_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_128_ctx *dctx = ctx;
+	struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
 		      DES3_128_BLOCK_SIZE);
@@ -302,11 +302,11 @@
  *   property.
  *
  */
-static int des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen,
-			   u32 *flags)
+static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
+			   unsigned int keylen, u32 *flags)
 {
 	int i, ret;
-	struct crypt_s390_des3_192_ctx *dctx = ctx;
+	struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
 	const u8* temp_key = key;
 
 	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
@@ -325,17 +325,17 @@
 	return 0;
 }
 
-static void des3_192_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_192_ctx *dctx = ctx;
+	struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
 		      DES3_192_BLOCK_SIZE);
 }
 
-static void des3_192_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_192_ctx *dctx = ctx;
+	struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
 
 	crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
 		      DES3_192_BLOCK_SIZE);
diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
index 98c896b..9d34a35 100644
--- a/arch/s390/crypto/sha1_s390.c
+++ b/arch/s390/crypto/sha1_s390.c
@@ -40,28 +40,29 @@
 	u8 buffer[2 * SHA1_BLOCK_SIZE];
 };
 
-static void
-sha1_init(void *ctx)
+static void sha1_init(struct crypto_tfm *tfm)
 {
-	static const struct crypt_s390_sha1_ctx initstate = {
-		.state = {
-			0x67452301,
-			0xEFCDAB89,
-			0x98BADCFE,
-			0x10325476,
-			0xC3D2E1F0
-		},
+	struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
+	static const u32 initstate[5] = {
+		0x67452301,
+		0xEFCDAB89,
+		0x98BADCFE,
+		0x10325476,
+		0xC3D2E1F0
 	};
-	memcpy(ctx, &initstate, sizeof(initstate));
+
+	ctx->count = 0;
+	memcpy(ctx->state, &initstate, sizeof(initstate));
+	ctx->buf_len = 0;
 }
 
-static void
-sha1_update(void *ctx, const u8 *data, unsigned int len)
+static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
+			unsigned int len)
 {
 	struct crypt_s390_sha1_ctx *sctx;
 	long imd_len;
 
-	sctx = ctx;
+	sctx = crypto_tfm_ctx(tfm);
 	sctx->count += len * 8; //message bit length
 
 	//anything in buffer yet? -> must be completed
@@ -110,10 +111,9 @@
 }
 
 /* Add padding and return the message digest. */
-static void
-sha1_final(void* ctx, u8 *out)
+static void sha1_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct crypt_s390_sha1_ctx *sctx = ctx;
+	struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	//must perform manual padding
 	pad_message(sctx);
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index 1ec5e92..f573df3 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -31,9 +31,9 @@
 	u8 buf[2 * SHA256_BLOCK_SIZE];
 };
 
-static void sha256_init(void *ctx)
+static void sha256_init(struct crypto_tfm *tfm)
 {
-	struct s390_sha256_ctx *sctx = ctx;
+	struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	sctx->state[0] = 0x6a09e667;
 	sctx->state[1] = 0xbb67ae85;
@@ -44,12 +44,12 @@
 	sctx->state[6] = 0x1f83d9ab;
 	sctx->state[7] = 0x5be0cd19;
 	sctx->count = 0;
-	memset(sctx->buf, 0, sizeof(sctx->buf));
 }
 
-static void sha256_update(void *ctx, const u8 *data, unsigned int len)
+static void sha256_update(struct crypto_tfm *tfm, const u8 *data,
+			  unsigned int len)
 {
-	struct s390_sha256_ctx *sctx = ctx;
+	struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 	unsigned int index;
 	int ret;
 
@@ -108,9 +108,9 @@
 }
 
 /* Add padding and return the message digest */
-static void sha256_final(void* ctx, u8 *out)
+static void sha256_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct s390_sha256_ctx *sctx = ctx;
+	struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	/* must perform manual padding */
 	pad_message(sctx);
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index bad81b5..fbde6a9 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -27,8 +27,8 @@
 
 typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
 
-const extern unsigned char relocate_kernel[];
-const extern unsigned long long relocate_kernel_len;
+extern const unsigned char relocate_kernel[];
+extern const unsigned long long relocate_kernel_len;
 
 int
 machine_kexec_prepare(struct kimage *image)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 0a04e4a..b282034 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -47,6 +47,7 @@
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
+#include <asm/sections.h>
 
 /*
  * Machine setup..
@@ -66,11 +67,6 @@
 static unsigned long __initdata memory_end;
 
 /*
- * Setup options
- */
-extern int _text,_etext, _edata, _end;
-
-/*
  * This is set up by the setup-routine at boot-time
  * for S390 need to find out, what we have to setup
  * using address 0x10400 ...
@@ -80,15 +76,11 @@
 
 static struct resource code_resource = {
 	.name  = "Kernel code",
-	.start = (unsigned long) &_text,
-	.end = (unsigned long) &_etext - 1,
 	.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
 static struct resource data_resource = {
 	.name = "Kernel data",
-	.start = (unsigned long) &_etext,
-	.end = (unsigned long) &_edata - 1,
 	.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
@@ -422,6 +414,11 @@
 	struct resource *res;
 	int i;
 
+	code_resource.start = (unsigned long) &_text;
+	code_resource.end = (unsigned long) &_etext - 1;
+	data_resource.start = (unsigned long) &_etext;
+	data_resource.end = (unsigned long) &_edata - 1;
+
 	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
 		res = alloc_bootmem_low(sizeof(struct resource));
 		res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index dfe6f08..1f0439d 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -356,7 +356,7 @@
 
 	set_vtimer(event->expires);
 	spin_unlock_irqrestore(&vt_list->lock, flags);
-	/* release CPU aquired in prepare_vtimer or mod_virt_timer() */
+	/* release CPU acquired in prepare_vtimer or mod_virt_timer() */
 	put_cpu();
 }
 
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index c72e17a..e467a45 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -147,7 +147,7 @@
 #	them changed.  We use .arch and .mach to indicate when they were
 #	updated last, otherwise make uses the target directory mtime.
 
-include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/MARKER
+include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/auto.conf
 	@echo '  SYMLINK include/asm-sh/cpu -> include/asm-sh/$(cpuincdir-y)'
 	$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
 	$(Q)ln -fsn $(incdir-prefix)$(cpuincdir-y) include/asm-sh/cpu
@@ -157,7 +157,7 @@
 #	don't, just reference the parent directory so the semantics are
 #	kept roughly the same.
 
-include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/MARKER
+include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/auto.conf
 	@echo -n '  SYMLINK include/asm-sh/mach -> '
 	$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
 	$(Q)if [ -d $(incdir-prefix)$(incdir-y) ]; then \
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 4354652..6bcd8d9 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -25,8 +25,8 @@
 				unsigned long start_address,
 				unsigned long vbr_reg) ATTRIB_NORET;
 
-const extern unsigned char relocate_new_kernel[];
-const extern unsigned int relocate_new_kernel_size;
+extern const unsigned char relocate_new_kernel[];
+extern const unsigned int relocate_new_kernel_size;
 extern void *gdb_vbr_vector;
 
 /*
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c
index 5ec9ddc..c265185 100644
--- a/arch/sh/oprofile/op_model_sh7750.c
+++ b/arch/sh/oprofile/op_model_sh7750.c
@@ -198,7 +198,7 @@
 
 	for (i = 0; i < NR_CNTRS; i++) {
 		struct dentry *dir;
-		char buf[3];
+		char buf[4];
 
 		snprintf(buf, sizeof(buf), "%d", i);
 		dir = oprofilefs_mkdir(sb, root, buf);
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 001b867..80a8094 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -138,6 +138,7 @@
        .suspend	= of_device_suspend,
        .resume	= of_device_resume,
 };
+EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
@@ -149,6 +150,7 @@
        .suspend	= of_device_suspend,
        .resume	= of_device_resume,
 };
+EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
 static int __init of_bus_driver_init(void)
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index 63b2b9b..946ce6d 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -27,6 +27,11 @@
 
 static struct device_node *allnodes;
 
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+static DEFINE_RWLOCK(devtree_lock);
+
 int of_device_is_compatible(struct device_node *device, const char *compat)
 {
 	const char* cp;
@@ -185,6 +190,54 @@
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+int of_set_property(struct device_node *dp, const char *name, void *val, int len)
+{
+	struct property **prevp;
+	void *new_val;
+	int err;
+
+	new_val = kmalloc(len, GFP_KERNEL);
+	if (!new_val)
+		return -ENOMEM;
+
+	memcpy(new_val, val, len);
+
+	err = -ENODEV;
+
+	write_lock(&devtree_lock);
+	prevp = &dp->properties;
+	while (*prevp) {
+		struct property *prop = *prevp;
+
+		if (!strcmp(prop->name, name)) {
+			void *old_val = prop->value;
+			int ret;
+
+			ret = prom_setprop(dp->node, name, val, len);
+			err = -EINVAL;
+			if (ret >= 0) {
+				prop->value = new_val;
+				prop->length = len;
+
+				if (OF_IS_DYNAMIC(prop))
+					kfree(old_val);
+
+				OF_MARK_DYNAMIC(prop);
+
+				err = 0;
+			}
+			break;
+		}
+		prevp = &(*prevp)->next;
+	}
+	write_unlock(&devtree_lock);
+
+	/* XXX Upate procfs if necessary... */
+
+	return err;
+}
+EXPORT_SYMBOL(of_set_property);
+
 static unsigned int prom_early_allocated;
 
 static void * __init prom_early_alloc(unsigned long size)
@@ -354,7 +407,9 @@
 	return n;
 }
 
-static struct property * __init build_one_prop(phandle node, char *prev)
+static unsigned int unique_id;
+
+static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
 {
 	static struct property *tmp = NULL;
 	struct property *p;
@@ -364,25 +419,34 @@
 		p = tmp;
 		memset(p, 0, sizeof(*p) + 32);
 		tmp = NULL;
-	} else
+	} else {
 		p = prom_early_alloc(sizeof(struct property) + 32);
+		p->unique_id = unique_id++;
+	}
 
 	p->name = (char *) (p + 1);
-	if (prev == NULL) {
-		prom_firstprop(node, p->name);
+	if (special_name) {
+		p->length = special_len;
+		p->value = prom_early_alloc(special_len);
+		memcpy(p->value, special_val, special_len);
 	} else {
-		prom_nextprop(node, prev, p->name);
-	}
-	if (strlen(p->name) == 0) {
-		tmp = p;
-		return NULL;
-	}
-	p->length = prom_getproplen(node, p->name);
-	if (p->length <= 0) {
-		p->length = 0;
-	} else {
-		p->value = prom_early_alloc(p->length);
-		len = prom_getproperty(node, p->name, p->value, p->length);
+		if (prev == NULL) {
+			prom_firstprop(node, p->name);
+		} else {
+			prom_nextprop(node, prev, p->name);
+		}
+		if (strlen(p->name) == 0) {
+			tmp = p;
+			return NULL;
+		}
+		p->length = prom_getproplen(node, p->name);
+		if (p->length <= 0) {
+			p->length = 0;
+		} else {
+			p->value = prom_early_alloc(p->length + 1);
+			prom_getproperty(node, p->name, p->value, p->length);
+			((unsigned char *)p->value)[p->length] = '\0';
+		}
 	}
 	return p;
 }
@@ -391,9 +455,14 @@
 {
 	struct property *head, *tail;
 
-	head = tail = build_one_prop(node, NULL);
+	head = tail = build_one_prop(node, NULL,
+				     ".node", &node, sizeof(node));
+
+	tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
+	tail = tail->next;
 	while(tail) {
-		tail->next = build_one_prop(node, tail->name);
+		tail->next = build_one_prop(node, tail->name,
+					    NULL, NULL, 0);
 		tail = tail->next;
 	}
 
@@ -422,6 +491,7 @@
 		return NULL;
 
 	dp = prom_early_alloc(sizeof(*dp));
+	dp->unique_id = unique_id++;
 
 	kref_init(&dp->kref);
 
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index fa50069..5db7e1d 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -9,3 +9,5 @@
 	 strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
 	 copy_user.o locks.o atomic.o atomic32.o bitops.o \
 	 lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o
+
+obj-y += iomap.o
diff --git a/arch/sparc/lib/iomap.c b/arch/sparc/lib/iomap.c
new file mode 100644
index 0000000..54501c1
--- /dev/null
+++ b/arch/sparc/lib/iomap.c
@@ -0,0 +1,48 @@
+/*
+ * Implement the sparc iomap interfaces
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+/* Create a virtual mapping cookie for an IO port range */
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+	return (void __iomem *) (unsigned long) port;
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+	/* Nothing to do */
+}
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+	unsigned long start = pci_resource_start(dev, bar);
+	unsigned long len = pci_resource_len(dev, bar);
+	unsigned long flags = pci_resource_flags(dev, bar);
+
+	if (!len || !start)
+		return NULL;
+	if (maxlen && len > maxlen)
+		len = maxlen;
+	if (flags & IORESOURCE_IO)
+		return ioport_map(start, len);
+	if (flags & IORESOURCE_MEM) {
+		if (flags & IORESOURCE_CACHEABLE)
+			return ioremap(start, len);
+		return ioremap_nocache(start, len);
+	}
+	/* What? */
+	return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+{
+	/* nothing to do */
+}
+EXPORT_SYMBOL(pci_iomap);
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 2c42894..c2c69c1 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -16,8 +17,8 @@
 #include <asm/ebus.h>
 #include <asm/auxio.h>
 
-/* This cannot be static, as it is referenced in irq.c */
 void __iomem *auxio_register = NULL;
+EXPORT_SYMBOL(auxio_register);
 
 enum auxio_type {
 	AUXIO_TYPE_NODEV,
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 31e0fbb..cc89b06 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -563,67 +563,6 @@
 	irq_exit();
 }
 
-#ifdef CONFIG_BLK_DEV_FD
-extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *);
-
-/* XXX No easy way to include asm/floppy.h XXX */
-extern unsigned char *pdma_vaddr;
-extern unsigned long pdma_size;
-extern volatile int doing_pdma;
-extern unsigned long fdc_status;
-
-irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
-{
-	if (likely(doing_pdma)) {
-		void __iomem *stat = (void __iomem *) fdc_status;
-		unsigned char *vaddr = pdma_vaddr;
-		unsigned long size = pdma_size;
-		u8 val;
-
-		while (size) {
-			val = readb(stat);
-			if (unlikely(!(val & 0x80))) {
-				pdma_vaddr = vaddr;
-				pdma_size = size;
-				return IRQ_HANDLED;
-			}
-			if (unlikely(!(val & 0x20))) {
-				pdma_vaddr = vaddr;
-				pdma_size = size;
-				doing_pdma = 0;
-				goto main_interrupt;
-			}
-			if (val & 0x40) {
-				/* read */
-				*vaddr++ = readb(stat + 1);
-			} else {
-				unsigned char data = *vaddr++;
-
-				/* write */
-				writeb(data, stat + 1);
-			}
-			size--;
-		}
-
-		pdma_vaddr = vaddr;
-		pdma_size = size;
-
-		/* Send Terminal Count pulse to floppy controller. */
-		val = readb(auxio_register);
-		val |= AUXIO_AUX1_FTCNT;
-		writeb(val, auxio_register);
-		val &= ~AUXIO_AUX1_FTCNT;
-		writeb(val, auxio_register);
-
-		doing_pdma = 0;
-	}
-
-main_interrupt:
-	return floppy_interrupt(irq, dev_cookie, regs);
-}
-EXPORT_SYMBOL(sparc_floppy_irq);
-#endif
-
 struct sun5_timer {
 	u64	count0;
 	u64	limit0;
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 566aa34..768475b 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -138,6 +138,7 @@
        .suspend	= of_device_suspend,
        .resume	= of_device_resume,
 };
+EXPORT_SYMBOL(isa_bus_type);
 
 struct bus_type ebus_bus_type = {
        .name	= "ebus",
@@ -147,6 +148,7 @@
        .suspend	= of_device_suspend,
        .resume	= of_device_resume,
 };
+EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
@@ -158,6 +160,7 @@
        .suspend	= of_device_suspend,
        .resume	= of_device_resume,
 };
+EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
 static int __init of_bus_driver_init(void)
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index e9d703e..8e87e7e 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -27,6 +27,11 @@
 
 static struct device_node *allnodes;
 
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+static DEFINE_RWLOCK(devtree_lock);
+
 int of_device_is_compatible(struct device_node *device, const char *compat)
 {
 	const char* cp;
@@ -185,6 +190,54 @@
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+int of_set_property(struct device_node *dp, const char *name, void *val, int len)
+{
+	struct property **prevp;
+	void *new_val;
+	int err;
+
+	new_val = kmalloc(len, GFP_KERNEL);
+	if (!new_val)
+		return -ENOMEM;
+
+	memcpy(new_val, val, len);
+
+	err = -ENODEV;
+
+	write_lock(&devtree_lock);
+	prevp = &dp->properties;
+	while (*prevp) {
+		struct property *prop = *prevp;
+
+		if (!strcmp(prop->name, name)) {
+			void *old_val = prop->value;
+			int ret;
+
+			ret = prom_setprop(dp->node, name, val, len);
+			err = -EINVAL;
+			if (ret >= 0) {
+				prop->value = new_val;
+				prop->length = len;
+
+				if (OF_IS_DYNAMIC(prop))
+					kfree(old_val);
+
+				OF_MARK_DYNAMIC(prop);
+
+				err = 0;
+			}
+			break;
+		}
+		prevp = &(*prevp)->next;
+	}
+	write_unlock(&devtree_lock);
+
+	/* XXX Upate procfs if necessary... */
+
+	return err;
+}
+EXPORT_SYMBOL(of_set_property);
+
 static unsigned int prom_early_allocated;
 
 static void * __init prom_early_alloc(unsigned long size)
@@ -531,7 +584,9 @@
 	return n;
 }
 
-static struct property * __init build_one_prop(phandle node, char *prev)
+static unsigned int unique_id;
+
+static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
 {
 	static struct property *tmp = NULL;
 	struct property *p;
@@ -540,25 +595,35 @@
 		p = tmp;
 		memset(p, 0, sizeof(*p) + 32);
 		tmp = NULL;
-	} else
+	} else {
 		p = prom_early_alloc(sizeof(struct property) + 32);
+		p->unique_id = unique_id++;
+	}
 
 	p->name = (char *) (p + 1);
-	if (prev == NULL) {
-		prom_firstprop(node, p->name);
+	if (special_name) {
+		strcpy(p->name, special_name);
+		p->length = special_len;
+		p->value = prom_early_alloc(special_len);
+		memcpy(p->value, special_val, special_len);
 	} else {
-		prom_nextprop(node, prev, p->name);
-	}
-	if (strlen(p->name) == 0) {
-		tmp = p;
-		return NULL;
-	}
-	p->length = prom_getproplen(node, p->name);
-	if (p->length <= 0) {
-		p->length = 0;
-	} else {
-		p->value = prom_early_alloc(p->length);
-		prom_getproperty(node, p->name, p->value, p->length);
+		if (prev == NULL) {
+			prom_firstprop(node, p->name);
+		} else {
+			prom_nextprop(node, prev, p->name);
+		}
+		if (strlen(p->name) == 0) {
+			tmp = p;
+			return NULL;
+		}
+		p->length = prom_getproplen(node, p->name);
+		if (p->length <= 0) {
+			p->length = 0;
+		} else {
+			p->value = prom_early_alloc(p->length + 1);
+			prom_getproperty(node, p->name, p->value, p->length);
+			((unsigned char *)p->value)[p->length] = '\0';
+		}
 	}
 	return p;
 }
@@ -567,9 +632,14 @@
 {
 	struct property *head, *tail;
 
-	head = tail = build_one_prop(node, NULL);
+	head = tail = build_one_prop(node, NULL,
+				     ".node", &node, sizeof(node));
+
+	tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
+	tail = tail->next;
 	while(tail) {
-		tail->next = build_one_prop(node, tail->name);
+		tail->next = build_one_prop(node, tail->name,
+					    NULL, NULL, 0);
 		tail = tail->next;
 	}
 
@@ -598,6 +668,7 @@
 		return NULL;
 
 	dp = prom_early_alloc(sizeof(*dp));
+	dp->unique_id = unique_id++;
 
 	kref_init(&dp->kref);
 
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 6e002aa..1605967 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -31,6 +31,40 @@
 #include <asm/kdebug.h>
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+/* Hook to register for page fault notifications */
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	struct die_args args = {
+		.regs = regs,
+		.str = str,
+		.err = err,
+		.trapnr = trap,
+		.signr = sig
+	};
+	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	return NOTIFY_DONE;
+}
+#endif
+
 /*
  * To debug kernel to catch accesses to certain virtual/physical addresses.
  * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
@@ -263,7 +297,7 @@
 
 	fault_code = get_thread_fault_code();
 
-	if (notify_die(DIE_PAGE_FAULT, "page_fault", regs,
+	if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs,
 		       fault_code, 0, SIGSEGV) == NOTIFY_STOP)
 		return;
 
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 5139934..5c2bcf3 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1568,6 +1568,7 @@
 unsigned long pg_iobits __read_mostly;
 
 unsigned long _PAGE_IE __read_mostly;
+EXPORT_SYMBOL(_PAGE_IE);
 
 unsigned long _PAGE_E __read_mostly;
 EXPORT_SYMBOL(_PAGE_E);
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 6d7173f..7914931 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -300,8 +300,6 @@
 	machine_restart(NULL);
 }
 
-extern void ctrl_alt_del(void);
-
 void mconsole_cad(struct mc_request *req)
 {
 	mconsole_reply(req, "", 0, 0);
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 0897852..290cec6 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -1222,7 +1222,7 @@
 		}
 	}
 
-	/* Succesful return case! */
+	/* Successful return case! */
 	if(backing_file_out == NULL)
 		return(fd);
 
diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h
index e06f83e..5e86aa0 100644
--- a/arch/um/include/sysdep-x86_64/syscalls.h
+++ b/arch/um/include/sysdep-x86_64/syscalls.h
@@ -12,8 +12,6 @@
 
 typedef long syscall_handler_t(void);
 
-extern syscall_handler_t *ia32_sys_call_table[];
-
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index af44130..ccc4a7f 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -386,24 +386,45 @@
 	bool "Provide RTC interrupt"
 	depends on HPET_TIMER && RTC=y
 
-config GART_IOMMU
-	bool "K8 GART IOMMU support"
+# Mark as embedded because too many people got it wrong.
+# The code disables itself when not needed.
+config IOMMU
+	bool "IOMMU support" if EMBEDDED
 	default y
 	select SWIOTLB
 	select AGP
 	depends on PCI
 	help
-	  Support for hardware IOMMU in AMD's Opteron/Athlon64 Processors
-	  and for the bounce buffering software IOMMU.
-	  Needed to run systems with more than 3GB of memory properly with
-	  32-bit PCI devices that do not support DAC (Double Address Cycle).
-	  The IOMMU can be turned off at runtime with the iommu=off parameter.
-  	  Normally the kernel will take the right choice by itself.
-  	  This option includes a driver for the AMD Opteron/Athlon64 IOMMU
-  	  northbridge and a software emulation used on other systems without
-	  hardware IOMMU.  If unsure, say Y.
+	  Support for full DMA access of devices with 32bit memory access only
+	  on systems with more than 3GB. This is usually needed for USB,
+	  sound, many IDE/SATA chipsets and some other devices.
+	  Provides a driver for the AMD Athlon64/Opteron/Turion/Sempron GART
+	  based IOMMU and a software bounce buffer based IOMMU used on Intel
+	  systems and as fallback.
+	  The code is only active when needed (enough memory and limited
+	  device) unless CONFIG_IOMMU_DEBUG or iommu=force is specified
+	  too.
 
-# need this always selected by GART_IOMMU for the VIA workaround
+config CALGARY_IOMMU
+	bool "IBM Calgary IOMMU support"
+	default y
+	select SWIOTLB
+	depends on PCI && EXPERIMENTAL
+	help
+	  Support for hardware IOMMUs in IBM's xSeries x366 and x460
+	  systems. Needed to run systems with more than 3GB of memory
+	  properly with 32-bit PCI devices that do not support DAC
+	  (Double Address Cycle). Calgary also supports bus level
+	  isolation, where all DMAs pass through the IOMMU.  This
+	  prevents them from going anywhere except their intended
+	  destination. This catches hard-to-find kernel bugs and
+	  mis-behaving drivers and devices that do not use the DMA-API
+	  properly to set up their DMA buffers.  The IOMMU can be
+	  turned off at boot time with the iommu=off parameter.
+	  Normally the kernel will make the right choice by itself.
+	  If unsure, say Y.
+
+# need this always selected by IOMMU for the VIA workaround
 config SWIOTLB
 	bool
 
@@ -501,6 +522,10 @@
          optimal TLB usage. If you have pretty much any version of binutils, 
 	 this can increase your kernel build time by roughly one minute.
 
+config K8_NB
+	def_bool y
+	depends on AGP_AMD64 || IOMMU || (PCI && NUMA)
+
 endmenu
 
 #
diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug
index ea31b4c..1d92ab5 100644
--- a/arch/x86_64/Kconfig.debug
+++ b/arch/x86_64/Kconfig.debug
@@ -13,7 +13,7 @@
 	 If in doubt, say "N".
 
 config IOMMU_DEBUG
-       depends on GART_IOMMU && DEBUG_KERNEL
+       depends on IOMMU && DEBUG_KERNEL
        bool "Enable IOMMU debugging"
        help
          Force the IOMMU to on even when you have less than 4GB of
@@ -35,6 +35,22 @@
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
 
+config DEBUG_STACKOVERFLOW
+        bool "Check for stack overflows"
+        depends on DEBUG_KERNEL
+        help
+	  This option will cause messages to be printed if free stack space
+	  drops below a certain limit.
+
+config DEBUG_STACK_USAGE
+        bool "Stack utilization instrumentation"
+        depends on DEBUG_KERNEL
+        help
+	  Enables the display of the minimum amount of free stack which each
+	  task has ever had available in the sysrq-T and sysrq-P debug output.
+
+	  This option will slow down process creation somewhat.
+
 #config X86_REMOTE_DEBUG
 #       bool "kgdb debugging stub"
 
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index e573e2a..431bb4b 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -27,6 +27,7 @@
 CHECKFLAGS      += -D__x86_64__ -m64
 
 cflags-y	:=
+cflags-kernel-y	:=
 cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
 cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
 cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
@@ -35,7 +36,7 @@
 cflags-y += -mno-red-zone
 cflags-y += -mcmodel=kernel
 cflags-y += -pipe
-cflags-$(CONFIG_REORDER) += -ffunction-sections
+cflags-kernel-$(CONFIG_REORDER) += -ffunction-sections
 # this makes reading assembly source easier, but produces worse code
 # actually it makes the kernel smaller too.
 cflags-y += -fno-reorder-blocks
@@ -55,6 +56,7 @@
 cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
 
 CFLAGS += $(cflags-y)
+CFLAGS_KERNEL += $(cflags-kernel-y)
 AFLAGS += -m64
 
 head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index 43ee6c5..deb063e 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -107,8 +107,13 @@
 isoimage: $(BOOTIMAGE)
 	-rm -rf $(obj)/isoimage
 	mkdir $(obj)/isoimage
-	cp `echo /usr/lib*/syslinux/isolinux.bin | awk '{ print $1; }'` \
-		$(obj)/isoimage
+	for i in lib lib64 share end ; do \
+		if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
+			cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
+			break ; \
+		fi ; \
+		if [ $$i = end ] ; then exit 1 ; fi ; \
+	done
 	cp $(BOOTIMAGE) $(obj)/isoimage/linux
 	echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
 	if [ -f '$(FDINITRD)' ] ; then \
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c
index cf4b88c..3755b2e 100644
--- a/arch/x86_64/boot/compressed/misc.c
+++ b/arch/x86_64/boot/compressed/misc.c
@@ -77,11 +77,11 @@
  */
 static unsigned char *real_mode; /* Pointer to real-mode data */
 
-#define EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
+#define RM_EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
 #ifndef STANDARD_MEMORY_BIOS_CALL
-#define ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
+#define RM_ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
 #endif
-#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
+#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
 
 extern unsigned char input_data[];
 extern int input_len;
@@ -92,9 +92,9 @@
 
 static void *malloc(int size);
 static void free(void *where);
- 
-void* memset(void* s, int c, unsigned n);
-void* memcpy(void* dest, const void* src, unsigned n);
+
+static void *memset(void *s, int c, unsigned n);
+static void *memcpy(void *dest, const void *src, unsigned n);
 
 static void putstr(const char *);
 
@@ -162,8 +162,8 @@
 	int x,y,pos;
 	char c;
 
-	x = SCREEN_INFO.orig_x;
-	y = SCREEN_INFO.orig_y;
+	x = RM_SCREEN_INFO.orig_x;
+	y = RM_SCREEN_INFO.orig_y;
 
 	while ( ( c = *s++ ) != '\0' ) {
 		if ( c == '\n' ) {
@@ -184,8 +184,8 @@
 		}
 	}
 
-	SCREEN_INFO.orig_x = x;
-	SCREEN_INFO.orig_y = y;
+	RM_SCREEN_INFO.orig_x = x;
+	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
 	outb_p(14, vidport);
@@ -194,7 +194,7 @@
 	outb_p(0xff & (pos >> 1), vidport+1);
 }
 
-void* memset(void* s, int c, unsigned n)
+static void* memset(void* s, int c, unsigned n)
 {
 	int i;
 	char *ss = (char*)s;
@@ -203,7 +203,7 @@
 	return s;
 }
 
-void* memcpy(void* dest, const void* src, unsigned n)
+static void* memcpy(void* dest, const void* src, unsigned n)
 {
 	int i;
 	char *d = (char *)dest, *s = (char *)src;
@@ -278,15 +278,15 @@
 	putstr(x);
 	putstr("\n\n -- System halted");
 
-	while(1);
+	while(1);	/* Halt */
 }
 
-void setup_normal_output_buffer(void)
+static void setup_normal_output_buffer(void)
 {
 #ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < 1024) error("Less than 2MB of memory");
+	if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
 #else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
 	output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
 	free_mem_end_ptr = (long)real_mode;
@@ -297,13 +297,13 @@
 	uch *high_buffer_start; int hcount;
 };
 
-void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
 {
 	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
 #ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
+	if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
 #else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
 #endif	
 	mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
 	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
@@ -319,7 +319,7 @@
 	mv->high_buffer_start = high_buffer_start;
 }
 
-void close_output_buffer_if_we_run_high(struct moveparams *mv)
+static void close_output_buffer_if_we_run_high(struct moveparams *mv)
 {
 	if (bytes_out > low_buffer_size) {
 		mv->lcount = low_buffer_size;
@@ -335,7 +335,7 @@
 {
 	real_mode = rmode;
 
-	if (SCREEN_INFO.orig_video_mode == 7) {
+	if (RM_SCREEN_INFO.orig_video_mode == 7) {
 		vidmem = (char *) 0xb0000;
 		vidport = 0x3b4;
 	} else {
@@ -343,8 +343,8 @@
 		vidport = 0x3d4;
 	}
 
-	lines = SCREEN_INFO.orig_video_lines;
-	cols = SCREEN_INFO.orig_video_cols;
+	lines = RM_SCREEN_INFO.orig_video_lines;
+	cols = RM_SCREEN_INFO.orig_video_cols;
 
 	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
 	else setup_output_buffer_if_we_run_high(mv);
diff --git a/arch/x86_64/boot/tools/build.c b/arch/x86_64/boot/tools/build.c
index c44f5e2..eae8669 100644
--- a/arch/x86_64/boot/tools/build.c
+++ b/arch/x86_64/boot/tools/build.c
@@ -149,10 +149,8 @@
 	sz = sb.st_size;
 	fprintf (stderr, "System is %d kB\n", sz/1024);
 	sys_size = (sz + 15) / 16;
-	/* 0x40000*16 = 4.0 MB, reasonable estimate for the current maximum */
-	if (sys_size > (is_big_kernel ? 0x40000 : DEF_SYSSIZE))
-		die("System is too big. Try using %smodules.",
-			is_big_kernel ? "" : "bzImage or ");
+	if (!is_big_kernel && sys_size > DEF_SYSSIZE)
+		die("System is too big. Try using bzImage or modules.");
 	while (sz > 0) {
 		int l, n;
 
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
index 32327bb..2aa565c 100644
--- a/arch/x86_64/boot/video.S
+++ b/arch/x86_64/boot/video.S
@@ -1929,6 +1929,7 @@
 	ret
 
 store_edid:
+#ifdef CONFIG_FIRMWARE_EDID
 	pushw	%es				# just save all registers
 	pushw	%ax
 	pushw	%bx
@@ -1946,6 +1947,22 @@
 	rep
 	stosl
 
+	pushw   %es				# save ES
+	xorw    %di, %di                        # Report Capability
+	pushw   %di
+	popw    %es                             # ES:DI must be 0:0
+	movw	$0x4f15, %ax
+	xorw	%bx, %bx
+	xorw	%cx, %cx
+	int	$0x10
+	popw    %es                             # restore ES
+
+	cmpb    $0x00, %ah                      # call successful
+	jne     no_edid
+
+	cmpb    $0x4f, %al                      # function supported
+	jne     no_edid
+
 	movw	$0x4f15, %ax                    # do VBE/DDC
 	movw	$0x01, %bx
 	movw	$0x00, %cx
@@ -1953,12 +1970,14 @@
 	movw	$0x140, %di
 	int	$0x10
 
+no_edid:
 	popw	%di				# restore all registers
 	popw	%dx
 	popw	%cx
 	popw	%bx
 	popw	%ax
 	popw	%es
+#endif
 	ret
 
 # VIDEO_SELECT-only variables
diff --git a/arch/x86_64/crypto/aes-x86_64-asm.S b/arch/x86_64/crypto/aes-x86_64-asm.S
index 483cbb2..26b40de 100644
--- a/arch/x86_64/crypto/aes-x86_64-asm.S
+++ b/arch/x86_64/crypto/aes-x86_64-asm.S
@@ -15,6 +15,10 @@
 
 .text
 
+#include <asm/asm-offsets.h>
+
+#define BASE crypto_tfm_ctx_offset
+
 #define R1	%rax
 #define R1E	%eax
 #define R1X	%ax
@@ -46,19 +50,19 @@
 #define R10	%r10
 #define R11	%r11
 
-#define prologue(FUNC,BASE,B128,B192,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11) \
+#define prologue(FUNC,KEY,B128,B192,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11) \
 	.global	FUNC;			\
 	.type	FUNC,@function;		\
 	.align	8;			\
 FUNC:	movq	r1,r2;			\
 	movq	r3,r4;			\
-	leaq	BASE+52(r8),r9;		\
+	leaq	BASE+KEY+52(r8),r9;	\
 	movq	r10,r11;		\
 	movl	(r7),r5 ## E;		\
 	movl	4(r7),r1 ## E;		\
 	movl	8(r7),r6 ## E;		\
 	movl	12(r7),r7 ## E;		\
-	movl	(r8),r10 ## E;		\
+	movl	BASE(r8),r10 ## E;	\
 	xorl	-48(r9),r5 ## E;	\
 	xorl	-44(r9),r1 ## E;	\
 	xorl	-40(r9),r6 ## E;	\
@@ -128,8 +132,8 @@
 	movl	r3 ## E,r1 ## E;	\
 	movl	r4 ## E,r2 ## E;
 
-#define entry(FUNC,BASE,B128,B192) \
-	prologue(FUNC,BASE,B128,B192,R2,R8,R7,R9,R1,R3,R4,R6,R10,R5,R11)
+#define entry(FUNC,KEY,B128,B192) \
+	prologue(FUNC,KEY,B128,B192,R2,R8,R7,R9,R1,R3,R4,R6,R10,R5,R11)
 
 #define return epilogue(R8,R2,R9,R7,R5,R6,R3,R4,R11)
 
@@ -147,9 +151,9 @@
 #define decrypt_final(TAB,OFFSET) \
 	round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4)
 
-/* void aes_encrypt(void *ctx, u8 *out, const u8 *in) */
+/* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */
 
-	entry(aes_encrypt,0,enc128,enc192)
+	entry(aes_enc_blk,0,enc128,enc192)
 	encrypt_round(aes_ft_tab,-96)
 	encrypt_round(aes_ft_tab,-80)
 enc192:	encrypt_round(aes_ft_tab,-64)
@@ -166,9 +170,9 @@
 	encrypt_final(aes_fl_tab,112)
 	return
 
-/* void aes_decrypt(void *ctx, u8 *out, const u8 *in) */
+/* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */
 
-	entry(aes_decrypt,240,dec128,dec192)
+	entry(aes_dec_blk,240,dec128,dec192)
 	decrypt_round(aes_it_tab,-96)
 	decrypt_round(aes_it_tab,-80)
 dec192:	decrypt_round(aes_it_tab,-64)
diff --git a/arch/x86_64/crypto/aes.c b/arch/x86_64/crypto/aes.c
index 6f77e77..68866fa 100644
--- a/arch/x86_64/crypto/aes.c
+++ b/arch/x86_64/crypto/aes.c
@@ -227,10 +227,10 @@
 	t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;	\
 }
 
-static int aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len,
-		       u32 *flags)
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len, u32 *flags)
 {
-	struct aes_ctx *ctx = ctx_arg;
+	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 	u32 i, j, t, u, v, w;
 
@@ -283,8 +283,18 @@
 	return 0;
 }
 
-extern void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in);
-extern void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in);
+asmlinkage void aes_enc_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+asmlinkage void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in);
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	aes_enc_blk(tfm, dst, src);
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+	aes_dec_blk(tfm, dst, src);
+}
 
 static struct crypto_alg aes_alg = {
 	.cra_name		=	"aes",
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 69db0c0..e69d403 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17-rc1-git11
-# Sun Apr 16 07:22:36 2006
+# Linux kernel version: 2.6.17-git6
+# Sat Jun 24 00:52:28 2006
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
@@ -42,7 +42,6 @@
 # CONFIG_RELAY is not set
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_UID16=y
-CONFIG_VM86=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
@@ -57,7 +56,6 @@
 CONFIG_EPOLL=y
 CONFIG_SHMEM=y
 CONFIG_SLAB=y
-CONFIG_DOUBLEFAULT=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 # CONFIG_SLOB is not set
@@ -144,7 +142,8 @@
 CONFIG_HOTPLUG_CPU=y
 CONFIG_HPET_TIMER=y
 CONFIG_HPET_EMULATE_RTC=y
-CONFIG_GART_IOMMU=y
+CONFIG_IOMMU=y
+# CONFIG_CALGARY_IOMMU is not set
 CONFIG_SWIOTLB=y
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_INTEL=y
@@ -158,6 +157,7 @@
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 # CONFIG_REORDER is not set
+CONFIG_K8_NB=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_ISA_DMA_API=y
@@ -293,6 +293,8 @@
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -305,7 +307,10 @@
 # CONFIG_INET6_IPCOMP is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
 # CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 
 #
@@ -344,6 +349,7 @@
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
@@ -360,6 +366,7 @@
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -526,6 +533,7 @@
 # CONFIG_SCSI_SATA_MV is not set
 CONFIG_SCSI_SATA_NV=y
 # CONFIG_SCSI_PDC_ADMA is not set
+# CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_SATA_QSTOR is not set
 # CONFIG_SCSI_SATA_PROMISE is not set
 # CONFIG_SCSI_SATA_SX4 is not set
@@ -591,10 +599,7 @@
 #
 # Device Drivers
 #
-
-#
-# Texas Instruments PCILynx requires I2C
-#
+# CONFIG_IEEE1394_PCILYNX is not set
 CONFIG_IEEE1394_OHCI1394=y
 
 #
@@ -645,7 +650,16 @@
 #
 # Tulip family network device support
 #
-# CONFIG_NET_TULIP is not set
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
@@ -697,6 +711,7 @@
 # CONFIG_IXGB is not set
 CONFIG_S2IO=m
 # CONFIG_S2IO_NAPI is not set
+# CONFIG_MYRI10GE is not set
 
 #
 # Token Ring devices
@@ -887,7 +902,56 @@
 #
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
 # SPI support
@@ -898,14 +962,51 @@
 #
 # Dallas's 1-wire bus
 #
-# CONFIG_W1 is not set
 
 #
 # Hardware Monitoring support
 #
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+CONFIG_SENSORS_SMSC47B397=m
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_SENSORS_HDAPS is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
@@ -918,6 +1019,7 @@
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
 
 #
 # Digital Video Broadcasting Devices
@@ -953,28 +1055,17 @@
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-CONFIG_OBSOLETE_OSS_DRIVER=y
 # CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
 CONFIG_SOUND_ICH=y
-# CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_VIA82CXXX is not set
 # CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_ALI5455 is not set
-# CONFIG_SOUND_FORTE is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_AD1980 is not set
+# CONFIG_SOUND_TVMIXER is not set
 
 #
 # USB support
@@ -1000,6 +1091,7 @@
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN is not set
@@ -1089,10 +1181,12 @@
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
+# CONFIG_USB_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
 # CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
 # CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TEST is not set
@@ -1141,6 +1235,19 @@
 # CONFIG_RTC_CLASS is not set
 
 #
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
 # Firmware Drivers
 #
 # CONFIG_EDD is not set
@@ -1175,6 +1282,7 @@
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
@@ -1331,7 +1439,8 @@
 CONFIG_DEBUG_FS=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_FRAME_POINTER is not set
-# CONFIG_UNWIND_INFO is not set
+CONFIG_UNWIND_INFO=y
+CONFIG_STACK_UNWIND=y
 # CONFIG_FORCED_INLINING is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_DEBUG_RODATA is not set
diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c
index 1c23095..2c8209a 100644
--- a/arch/x86_64/ia32/fpu32.c
+++ b/arch/x86_64/ia32/fpu32.c
@@ -2,7 +2,6 @@
  * Copyright 2002 Andi Kleen, SuSE Labs.
  * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
  * This is used for ptrace, signals and coredumps in 32bit emulation.
- * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
  */ 
 
 #include <linux/sched.h>
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index e0a9243..25e5ca2 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -6,8 +6,6 @@
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
- * 
- *  $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
  */
 
 #include <linux/sched.h>
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 4ec594a..c536fa9 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -155,6 +155,7 @@
 	.previous
 	jmp	sysenter_do_call
 	CFI_ENDPROC
+ENDPROC(ia32_sysenter_target)
 
 /*
  * 32bit SYSCALL instruction entry.
@@ -178,7 +179,7 @@
  */ 	
 ENTRY(ia32_cstar_target)
 	CFI_STARTPROC32	simple
-	CFI_DEF_CFA	rsp,0
+	CFI_DEF_CFA	rsp,PDA_STACKOFFSET
 	CFI_REGISTER	rip,rcx
 	/*CFI_REGISTER	rflags,r11*/
 	swapgs
@@ -249,6 +250,7 @@
 	.quad 1b,ia32_badarg
 	.previous
 	jmp cstar_do_call
+END(ia32_cstar_target)
 				
 ia32_badarg:
 	movq $-EFAULT,%rax
@@ -314,16 +316,13 @@
 	LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
 	RESTORE_REST
 	jmp ia32_do_syscall
+END(ia32_syscall)
 
 ia32_badsys:
 	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
 	jmp int_ret_from_sys_call
 
-ni_syscall:
-	movq %rax,%rdi
-	jmp  sys32_ni_syscall			
-
 quiet_ni_syscall:
 	movq $-ENOSYS,%rax
 	ret
@@ -370,10 +369,10 @@
 	RESTORE_REST
 	jmp  ia32_sysret	/* misbalances the return cache */
 	CFI_ENDPROC
+END(ia32_ptregs_common)
 
 	.section .rodata,"a"
 	.align 8
-	.globl ia32_sys_call_table
 ia32_sys_call_table:
 	.quad sys_restart_syscall
 	.quad sys_exit
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
index 23a4515..a590b7a 100644
--- a/arch/x86_64/ia32/ptrace32.c
+++ b/arch/x86_64/ia32/ptrace32.c
@@ -7,8 +7,6 @@
  * 
  * This allows to access 64bit processes too; but there is no way to see the extended 
  * register contents.
- *
- * $Id: ptrace32.c,v 1.16 2003/03/14 16:06:35 ak Exp $
  */ 
 
 #include <linux/kernel.h>
@@ -27,6 +25,7 @@
 #include <asm/debugreg.h>
 #include <asm/i387.h>
 #include <asm/fpu32.h>
+#include <asm/ia32.h>
 
 /*
  * Determines which flags the user has access to [1 = access, 0 = no access].
@@ -199,6 +198,24 @@
 
 #undef R32
 
+static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
+{
+	int ret;
+	compat_siginfo_t *si32 = (compat_siginfo_t *)compat_ptr(data);
+	siginfo_t *si = compat_alloc_user_space(sizeof(siginfo_t));
+	if (request == PTRACE_SETSIGINFO) {
+		ret = copy_siginfo_from_user32(si, si32);
+		if (ret)
+			return ret;
+	}
+	ret = sys_ptrace(request, pid, addr, (unsigned long)si);
+	if (ret)
+		return ret;
+	if (request == PTRACE_GETSIGINFO)
+		ret = copy_siginfo_to_user32(si32, si);
+	return ret;
+}
+
 asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
 {
 	struct task_struct *child;
@@ -208,9 +225,19 @@
 	__u32 val;
 
 	switch (request) { 
-	default:
+	case PTRACE_TRACEME:
+	case PTRACE_ATTACH:
+	case PTRACE_KILL:
+	case PTRACE_CONT:
+	case PTRACE_SINGLESTEP:
+	case PTRACE_DETACH:
+	case PTRACE_SYSCALL:
+	case PTRACE_SETOPTIONS:
 		return sys_ptrace(request, pid, addr, data); 
 
+	default:
+		return -EINVAL;
+
 	case PTRACE_PEEKTEXT:
 	case PTRACE_PEEKDATA:
 	case PTRACE_POKEDATA:
@@ -225,10 +252,11 @@
 	case PTRACE_GETFPXREGS:
 	case PTRACE_GETEVENTMSG:
 		break;
-	} 
 
-	if (request == PTRACE_TRACEME)
-		return ptrace_traceme();
+	case PTRACE_SETSIGINFO:
+	case PTRACE_GETSIGINFO:
+		return ptrace32_siginfo(request, pid, addr, data);
+	}
 
 	child = ptrace_get_task_struct(pid);
 	if (IS_ERR(child))
@@ -349,8 +377,7 @@
 		break;
 
 	default:
-		ret = -EINVAL;
-		break;
+		BUG();
 	}
 
  out:
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index f182b20..dc88154 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -508,19 +508,6 @@
 	return compat_sys_wait4(pid, stat_addr, options, NULL);
 }
 
-int sys32_ni_syscall(int call)
-{ 
-	struct task_struct *me = current;
-	static char lastcomm[sizeof(me->comm)];
-
-	if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
-		printk(KERN_INFO "IA32 syscall %d from %s not implemented\n",
-		       call, me->comm);
-		strncpy(lastcomm, me->comm, sizeof(lastcomm));
-	} 
-	return -ENOSYS;	       
-} 
-
 /* 32-bit timeval and related flotsam.  */
 
 asmlinkage long
@@ -916,7 +903,7 @@
 	struct task_struct *me = current;
 	static char lastcomm[sizeof(me->comm)];
 	if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
-		printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
+		compat_printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
 		       me->comm);
 		strncpy(lastcomm, me->comm, sizeof(lastcomm));
 	} 
@@ -929,13 +916,3 @@
 	return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
 }
 
-static int __init ia32_init (void)
-{
-	printk("IA32 emulation $Id: sys_ia32.c,v 1.32 2002/03/24 13:02:28 ak Exp $\n");  
-	return 0;
-}
-
-__initcall(ia32_init);
-
-extern unsigned long ia32_sys_call_table[];
-EXPORT_SYMBOL(ia32_sys_call_table);
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index 059c883..aeb9c56 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -8,7 +8,7 @@
 		ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
 		x8664_ksyms.o i387.o syscall.o vsyscall.o \
 		setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \
-		pci-dma.o pci-nommu.o
+		pci-dma.o pci-nommu.o alternative.o
 
 obj-$(CONFIG_X86_MCE)         += mce.o
 obj-$(CONFIG_X86_MCE_INTEL)	+= mce_intel.o
@@ -28,11 +28,13 @@
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend_asm.o
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
-obj-$(CONFIG_GART_IOMMU)	+= pci-gart.o aperture.o
+obj-$(CONFIG_IOMMU)		+= pci-gart.o aperture.o
+obj-$(CONFIG_CALGARY_IOMMU)	+= pci-calgary.o tce.o
 obj-$(CONFIG_SWIOTLB)		+= pci-swiotlb.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer.o
 obj-$(CONFIG_X86_VSMP)		+= vsmp.o
+obj-$(CONFIG_K8_NB)		+= k8.o
 
 obj-$(CONFIG_MODULES)		+= module.o
 
@@ -49,3 +51,5 @@
 quirks-y			+= ../../i386/kernel/quirks.o
 i8237-y				+= ../../i386/kernel/i8237.o
 msr-$(subst m,y,$(CONFIG_X86_MSR))  += ../../i386/kernel/msr.o
+alternative-y			+= ../../i386/kernel/alternative.o
+
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index 70b9d21..a195ef0 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -8,7 +8,6 @@
  * because only the bootmem allocator can allocate 32+MB. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: aperture.c,v 1.7 2003/08/01 03:36:18 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -24,6 +23,7 @@
 #include <asm/proto.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
+#include <asm/k8.h>
 
 int iommu_aperture;
 int iommu_aperture_disabled __initdata = 0;
@@ -37,8 +37,6 @@
 /* This code runs before the PCI subsystem is initialized, so just
    access the northbridge directly. */
 
-#define NB_ID_3 (PCI_VENDOR_ID_AMD | (0x1103<<16))
-
 static u32 __init allocate_aperture(void) 
 {
 	pg_data_t *nd0 = NODE_DATA(0);
@@ -68,20 +66,20 @@
 	return (u32)__pa(p); 
 }
 
-static int __init aperture_valid(char *name, u64 aper_base, u32 aper_size) 
+static int __init aperture_valid(u64 aper_base, u32 aper_size)
 { 
 	if (!aper_base) 
 		return 0;
 	if (aper_size < 64*1024*1024) { 
-		printk("Aperture from %s too small (%d MB)\n", name, aper_size>>20); 
+		printk("Aperture too small (%d MB)\n", aper_size>>20);
 		return 0;
 	}
 	if (aper_base + aper_size >= 0xffffffff) { 
-		printk("Aperture from %s beyond 4GB. Ignoring.\n",name);
+		printk("Aperture beyond 4GB. Ignoring.\n");
 		return 0; 
 	}
 	if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
-		printk("Aperture from %s pointing to e820 RAM. Ignoring.\n",name);
+		printk("Aperture pointing to e820 RAM. Ignoring.\n");
 		return 0; 
 	} 
 	return 1;
@@ -140,7 +138,7 @@
 	printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", 
 	       aper, 32 << *order, apsizereg);
 
-	if (!aperture_valid("AGP bridge", aper, (32*1024*1024) << *order))
+	if (!aperture_valid(aper, (32*1024*1024) << *order))
 	    return 0;
 	return (u32)aper; 
 } 
@@ -208,10 +206,10 @@
 
 	fix = 0;
 	for (num = 24; num < 32; num++) {		
-		char name[30];
-		if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
-			continue;	
+		if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
+			continue;
 
+		iommu_detected = 1;
 		iommu_aperture = 1; 
 
 		aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; 
@@ -222,9 +220,7 @@
 		printk("CPU %d: aperture @ %Lx size %u MB\n", num-24, 
 		       aper_base, aper_size>>20);
 		
-		sprintf(name, "northbridge cpu %d", num-24); 
-
-		if (!aperture_valid(name, aper_base, aper_size)) { 
+		if (!aperture_valid(aper_base, aper_size)) {
 			fix = 1; 
 			break; 
 		}
@@ -273,7 +269,7 @@
 
 	/* Fix up the north bridges */
 	for (num = 24; num < 32; num++) { 		
-		if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
+		if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
 			continue;	
 
 		/* Don't enable translation yet. That is done later. 
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 29ef990..b2ead91 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -100,7 +100,7 @@
 	maxlvt = get_maxlvt();
 
 	/*
-	 * Masking an LVT entry on a P6 can trigger a local APIC error
+	 * Masking an LVT entry can trigger a local APIC error
 	 * if the vector is zero. Mask LVTERR first to prevent this.
 	 */
 	if (maxlvt >= 3) {
@@ -851,7 +851,18 @@
 		unsigned long v;
 
 		v = apic_read(APIC_LVTT);
-		apic_write(APIC_LVTT, v | APIC_LVT_MASKED);
+		/*
+		 * When an illegal vector value (0-15) is written to an LVT
+		 * entry and delivery mode is Fixed, the APIC may signal an
+		 * illegal vector error, with out regard to whether the mask
+		 * bit is set or whether an interrupt is actually seen on input.
+		 *
+		 * Boot sequence might call this function when the LVTT has
+		 * '0' vector value. So make sure vector field is set to
+		 * valid value.
+		 */
+		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+		apic_write(APIC_LVTT, v);
 	}
 }
 
@@ -909,15 +920,13 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_X86_MCE_AMD
-void setup_threshold_lvt(unsigned long lvt_off)
+void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
+			    unsigned char msg_type, unsigned char mask)
 {
-	unsigned int v = 0;
-	unsigned long reg = (lvt_off << 4) + 0x500;
-	v |= THRESHOLD_APIC_VECTOR;
+	unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
+	unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
 	apic_write(reg, v);
 }
-#endif /* CONFIG_X86_MCE_AMD */
 
 #undef APIC_DIVISOR
 
@@ -983,7 +992,7 @@
 }
 
 /*
- * oem_force_hpet_timer -- force HPET mode for some boxes.
+ * apic_is_clustered_box() -- Check if we can expect good TSC
  *
  * Thus far, the major user of this is IBM's Summit2 series:
  *
@@ -991,7 +1000,7 @@
  * multi-chassis. Use available data to take a good guess.
  * If in doubt, go HPET.
  */
-__cpuinit int oem_force_hpet_timer(void)
+__cpuinit int apic_is_clustered_box(void)
 {
 	int i, clusters, zeros;
 	unsigned id;
@@ -1022,8 +1031,7 @@
 	}
 
 	/*
-	 * If clusters > 2, then should be multi-chassis.  Return 1 for HPET.
-	 * Else return 0 to use TSC.
+	 * If clusters > 2, then should be multi-chassis.
 	 * May have to revisit this when multi-core + hyperthreaded CPUs come
 	 * out, but AFAIK this will work even for them.
 	 */
diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c
index 38834bb..96687e2 100644
--- a/arch/x86_64/kernel/asm-offsets.c
+++ b/arch/x86_64/kernel/asm-offsets.c
@@ -4,6 +4,7 @@
  * and format the required data.
  */
 
+#include <linux/crypto.h>
 #include <linux/sched.h> 
 #include <linux/stddef.h>
 #include <linux/errno.h> 
@@ -68,5 +69,7 @@
 	DEFINE(pbe_next, offsetof(struct pbe, next));
 	BLANK();
 	DEFINE(TSS_ist, offsetof(struct tss_struct, ist));
+	BLANK();
+	DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
 	return 0;
 }
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
index 4e6c3b7..d8d5750 100644
--- a/arch/x86_64/kernel/crash.c
+++ b/arch/x86_64/kernel/crash.c
@@ -111,14 +111,14 @@
 	atomic_dec(&waiting_for_crash_ipi);
 	/* Assume hlt works */
 	for(;;)
-		asm("hlt");
+		halt();
 
 	return 1;
 }
 
 static void smp_send_nmi_allbutself(void)
 {
-	send_IPI_allbutself(APIC_DM_NMI);
+	send_IPI_allbutself(NMI_VECTOR);
 }
 
 /*
@@ -161,7 +161,7 @@
 {
 	/*
 	 * This function is only called after the system
-	 * has paniced or is otherwise in a critical state.
+	 * has panicked or is otherwise in a critical state.
 	 * The minimum amount of code to allow a kexec'd kernel
 	 * to run successfully needs to happen here.
 	 *
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 1ef6028..9e94d83 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -1,7 +1,6 @@
 /* 
  * Handle the memory map.
  * The functions here do the job until bootmem takes over.
- * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
  *
  *  Getting sanitize_e820_map() in sync with i386 version by applying change:
  *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
@@ -621,6 +620,7 @@
 }
 
 unsigned long pci_mem_start = 0xaeedbabe;
+EXPORT_SYMBOL(pci_mem_start);
 
 /*
  * Search for the biggest gap in the low 32 bits of the e820
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 586b34c..7290e72 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -154,6 +154,7 @@
 	GET_THREAD_INFO(%rcx)	
 	jmp rff_action
 	CFI_ENDPROC
+END(ret_from_fork)
 
 /*
  * System call entry. Upto 6 arguments in registers are supported.
@@ -188,7 +189,7 @@
 
 ENTRY(system_call)
 	CFI_STARTPROC	simple
-	CFI_DEF_CFA	rsp,0
+	CFI_DEF_CFA	rsp,PDA_STACKOFFSET
 	CFI_REGISTER	rip,rcx
 	/*CFI_REGISTER	rflags,r11*/
 	swapgs
@@ -285,6 +286,7 @@
 	/* Use IRET because user could have changed frame */
 	jmp int_ret_from_sys_call
 	CFI_ENDPROC
+END(system_call)
 		
 /* 
  * Syscall return path ending with IRET.
@@ -364,6 +366,7 @@
 	cli
 	jmp int_with_check
 	CFI_ENDPROC
+END(int_ret_from_sys_call)
 		
 /* 
  * Certain special system calls that need to save a complete full stack frame.
@@ -375,6 +378,7 @@
 	leaq	\func(%rip),%rax
 	leaq    -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
 	jmp	ptregscall_common
+END(\label)
 	.endm
 
 	CFI_STARTPROC
@@ -404,6 +408,7 @@
 	CFI_REL_OFFSET rip, 0
 	ret
 	CFI_ENDPROC
+END(ptregscall_common)
 	
 ENTRY(stub_execve)
 	CFI_STARTPROC
@@ -418,6 +423,7 @@
 	RESTORE_REST
 	jmp int_ret_from_sys_call
 	CFI_ENDPROC
+END(stub_execve)
 	
 /*
  * sigreturn is special because it needs to restore all registers on return.
@@ -435,6 +441,7 @@
 	RESTORE_REST
 	jmp int_ret_from_sys_call
 	CFI_ENDPROC
+END(stub_rt_sigreturn)
 
 /*
  * initial frame state for interrupts and exceptions
@@ -466,29 +473,18 @@
 /* 0(%rsp): interrupt number */ 
 	.macro interrupt func
 	cld
-#ifdef CONFIG_DEBUG_INFO
-	SAVE_ALL	
-	movq %rsp,%rdi
-	/*
-	 * Setup a stack frame pointer.  This allows gdb to trace
-	 * back to the original stack.
-	 */
-	movq %rsp,%rbp
-	CFI_DEF_CFA_REGISTER	rbp
-#else		
 	SAVE_ARGS
 	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
-#endif	
+	pushq %rbp
+	CFI_ADJUST_CFA_OFFSET	8
+	CFI_REL_OFFSET		rbp, 0
+	movq %rsp,%rbp
+	CFI_DEF_CFA_REGISTER	rbp
 	testl $3,CS(%rdi)
 	je 1f
 	swapgs	
 1:	incl	%gs:pda_irqcount	# RED-PEN should check preempt count
-	movq %gs:pda_irqstackptr,%rax
-	cmoveq %rax,%rsp /*todo This needs CFI annotation! */
-	pushq %rdi			# save old stack	
-#ifndef CONFIG_DEBUG_INFO
-	CFI_ADJUST_CFA_OFFSET	8
-#endif
+	cmoveq %gs:pda_irqstackptr,%rsp
 	call \func
 	.endm
 
@@ -497,17 +493,11 @@
 	interrupt do_IRQ
 	/* 0(%rsp): oldrsp-ARGOFFSET */
 ret_from_intr:
-	popq  %rdi
-#ifndef CONFIG_DEBUG_INFO
-	CFI_ADJUST_CFA_OFFSET	-8
-#endif
 	cli	
 	decl %gs:pda_irqcount
-#ifdef CONFIG_DEBUG_INFO
-	movq RBP(%rdi),%rbp
+	leaveq
 	CFI_DEF_CFA_REGISTER	rsp
-#endif
-	leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */
+	CFI_ADJUST_CFA_OFFSET	-8
 exit_intr:
 	GET_THREAD_INFO(%rcx)
 	testl $3,CS-ARGOFFSET(%rsp)
@@ -589,7 +579,9 @@
 	call preempt_schedule_irq
 	jmp exit_intr
 #endif	
+
 	CFI_ENDPROC
+END(common_interrupt)
 	
 /*
  * APIC interrupts.
@@ -605,17 +597,21 @@
 
 ENTRY(thermal_interrupt)
 	apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
+END(thermal_interrupt)
 
 ENTRY(threshold_interrupt)
 	apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
+END(threshold_interrupt)
 
 #ifdef CONFIG_SMP	
 ENTRY(reschedule_interrupt)
 	apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
+END(reschedule_interrupt)
 
 	.macro INVALIDATE_ENTRY num
 ENTRY(invalidate_interrupt\num)
 	apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt	
+END(invalidate_interrupt\num)
 	.endm
 
 	INVALIDATE_ENTRY 0
@@ -629,17 +625,21 @@
 
 ENTRY(call_function_interrupt)
 	apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
+END(call_function_interrupt)
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC	
 ENTRY(apic_timer_interrupt)
 	apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
+END(apic_timer_interrupt)
 
 ENTRY(error_interrupt)
 	apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
+END(error_interrupt)
 
 ENTRY(spurious_interrupt)
 	apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
+END(spurious_interrupt)
 #endif
 				
 /*
@@ -777,6 +777,7 @@
 	cmpq $gs_change,RIP(%rsp)
         je   error_swapgs
 	jmp  error_sti
+END(error_entry)
 	
        /* Reload gs selector with exception handling */
        /* edi:  new selector */ 
@@ -794,6 +795,7 @@
 	CFI_ADJUST_CFA_OFFSET -8
         ret
 	CFI_ENDPROC
+ENDPROC(load_gs_index)
        
         .section __ex_table,"a"
         .align 8
@@ -847,7 +849,7 @@
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
-
+ENDPROC(kernel_thread)
 	
 child_rip:
 	/*
@@ -860,6 +862,7 @@
 	# exit
 	xorl %edi, %edi
 	call do_exit
+ENDPROC(child_rip)
 
 /*
  * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
@@ -889,19 +892,24 @@
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
+ENDPROC(execve)
 
 KPROBE_ENTRY(page_fault)
 	errorentry do_page_fault
+END(page_fault)
 	.previous .text
 
 ENTRY(coprocessor_error)
 	zeroentry do_coprocessor_error
+END(coprocessor_error)
 
 ENTRY(simd_coprocessor_error)
 	zeroentry do_simd_coprocessor_error	
+END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
 	zeroentry math_state_restore
+END(device_not_available)
 
 	/* runs on exception stack */
 KPROBE_ENTRY(debug)
@@ -911,6 +919,7 @@
 	paranoidentry do_debug, DEBUG_STACK
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(debug)
 	.previous .text
 
 	/* runs on exception stack */	
@@ -961,6 +970,7 @@
 	cli
 	jmp paranoid_userspace
 	CFI_ENDPROC
+END(nmi)
 	.previous .text
 
 KPROBE_ENTRY(int3)
@@ -970,22 +980,28 @@
  	paranoidentry do_int3, DEBUG_STACK
  	jmp paranoid_exit
  	CFI_ENDPROC
+END(int3)
 	.previous .text
 
 ENTRY(overflow)
 	zeroentry do_overflow
+END(overflow)
 
 ENTRY(bounds)
 	zeroentry do_bounds
+END(bounds)
 
 ENTRY(invalid_op)
 	zeroentry do_invalid_op	
+END(invalid_op)
 
 ENTRY(coprocessor_segment_overrun)
 	zeroentry do_coprocessor_segment_overrun
+END(coprocessor_segment_overrun)
 
 ENTRY(reserved)
 	zeroentry do_reserved
+END(reserved)
 
 	/* runs on exception stack */
 ENTRY(double_fault)
@@ -993,12 +1009,15 @@
 	paranoidentry do_double_fault
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(double_fault)
 
 ENTRY(invalid_TSS)
 	errorentry do_invalid_TSS
+END(invalid_TSS)
 
 ENTRY(segment_not_present)
 	errorentry do_segment_not_present
+END(segment_not_present)
 
 	/* runs on exception stack */
 ENTRY(stack_segment)
@@ -1006,19 +1025,24 @@
 	paranoidentry do_stack_segment
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(stack_segment)
 
 KPROBE_ENTRY(general_protection)
 	errorentry do_general_protection
+END(general_protection)
 	.previous .text
 
 ENTRY(alignment_check)
 	errorentry do_alignment_check
+END(alignment_check)
 
 ENTRY(divide_error)
 	zeroentry do_divide_error
+END(divide_error)
 
 ENTRY(spurious_interrupt_bug)
 	zeroentry do_spurious_interrupt_bug
+END(spurious_interrupt_bug)
 
 #ifdef CONFIG_X86_MCE
 	/* runs on exception stack */
@@ -1029,6 +1053,7 @@
 	paranoidentry do_machine_check
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(machine_check)
 #endif
 
 ENTRY(call_softirq)
@@ -1046,3 +1071,37 @@
 	decl %gs:pda_irqcount
 	ret
 	CFI_ENDPROC
+ENDPROC(call_softirq)
+
+#ifdef CONFIG_STACK_UNWIND
+ENTRY(arch_unwind_init_running)
+	CFI_STARTPROC
+	movq	%r15, R15(%rdi)
+	movq	%r14, R14(%rdi)
+	xchgq	%rsi, %rdx
+	movq	%r13, R13(%rdi)
+	movq	%r12, R12(%rdi)
+	xorl	%eax, %eax
+	movq	%rbp, RBP(%rdi)
+	movq	%rbx, RBX(%rdi)
+	movq	(%rsp), %rcx
+	movq	%rax, R11(%rdi)
+	movq	%rax, R10(%rdi)
+	movq	%rax, R9(%rdi)
+	movq	%rax, R8(%rdi)
+	movq	%rax, RAX(%rdi)
+	movq	%rax, RCX(%rdi)
+	movq	%rax, RDX(%rdi)
+	movq	%rax, RSI(%rdi)
+	movq	%rax, RDI(%rdi)
+	movq	%rax, ORIG_RAX(%rdi)
+	movq	%rcx, RIP(%rdi)
+	leaq	8(%rsp), %rcx
+	movq	$__KERNEL_CS, CS(%rdi)
+	movq	%rax, EFLAGS(%rdi)
+	movq	%rcx, RSP(%rdi)
+	movq	$__KERNEL_DS, SS(%rdi)
+	jmpq	*%rdx
+	CFI_ENDPROC
+ENDPROC(arch_unwind_init_running)
+#endif
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
index 1a2ab82..21c7066 100644
--- a/arch/x86_64/kernel/genapic_flat.c
+++ b/arch/x86_64/kernel/genapic_flat.c
@@ -78,22 +78,29 @@
 
 static void flat_send_IPI_allbutself(int vector)
 {
-#ifndef CONFIG_HOTPLUG_CPU
-	if (((num_online_cpus()) - 1) >= 1)
-		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL);
+#ifdef	CONFIG_HOTPLUG_CPU
+	int hotplug = 1;
 #else
-	cpumask_t allbutme = cpu_online_map;
-
-	cpu_clear(smp_processor_id(), allbutme);
-
-	if (!cpus_empty(allbutme))
-		flat_send_IPI_mask(allbutme, vector);
+	int hotplug = 0;
 #endif
+	if (hotplug || vector == NMI_VECTOR) {
+		cpumask_t allbutme = cpu_online_map;
+
+		cpu_clear(smp_processor_id(), allbutme);
+
+		if (!cpus_empty(allbutme))
+			flat_send_IPI_mask(allbutme, vector);
+	} else if (num_online_cpus() > 1) {
+		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL);
+	}
 }
 
 static void flat_send_IPI_all(int vector)
 {
-	__send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
+	if (vector == NMI_VECTOR)
+		flat_send_IPI_mask(cpu_online_map, vector);
+	else
+		__send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
 }
 
 static int flat_apic_id_registered(void)
@@ -108,10 +115,7 @@
 
 static unsigned int phys_pkg_id(int index_msb)
 {
-	u32 ebx;
-
-	ebx = cpuid_ebx(1);
-	return ((ebx >> 24) & 0xFF) >> index_msb;
+	return hard_smp_processor_id() >> index_msb;
 }
 
 struct genapic apic_flat =  {
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
index cea20a6..e6a71c9 100644
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -2,8 +2,6 @@
  *  linux/arch/x86_64/kernel/head64.c -- prepare to run common code
  *
  *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
- *
- *  $Id: head64.c,v 1.22 2001/07/06 14:28:20 ak Exp $
  */
 
 #include <linux/init.h>
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 5ecd34a..86b2c1e 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -44,11 +44,11 @@
 	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
 	BI(x,c) BI(x,d) BI(x,e) BI(x,f)
 
-#define BUILD_14_IRQS(x) \
+#define BUILD_15_IRQS(x) \
 	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
 	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
 	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
-	BI(x,c) BI(x,d)
+	BI(x,c) BI(x,d) BI(x,e)
 
 /*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
@@ -73,13 +73,13 @@
 BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
 
 #ifdef CONFIG_PCI_MSI
-	BUILD_14_IRQS(0xe)
+	BUILD_15_IRQS(0xe)
 #endif
 
 #endif
 
 #undef BUILD_16_IRQS
-#undef BUILD_14_IRQS
+#undef BUILD_15_IRQS
 #undef BI
 
 
@@ -92,11 +92,11 @@
 	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
 	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
 
-#define IRQLIST_14(x) \
+#define IRQLIST_15(x) \
 	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
 	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
 	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
-	IRQ(x,c), IRQ(x,d)
+	IRQ(x,c), IRQ(x,d), IRQ(x,e)
 
 void (*interrupt[NR_IRQS])(void) = {
 	IRQLIST_16(0x0),
@@ -108,7 +108,7 @@
 	IRQLIST_16(0xc), IRQLIST_16(0xd)
 
 #ifdef CONFIG_PCI_MSI
-	, IRQLIST_14(0xe)
+	, IRQLIST_15(0xe)
 #endif
 
 #endif
@@ -278,7 +278,7 @@
 	 * Lightweight spurious IRQ detection. We do not want
 	 * to overdo spurious IRQ handling - it's usually a sign
 	 * of hardware problems, so we only do the checks we can
-	 * do without slowing down good hardware unnecesserily.
+	 * do without slowing down good hardware unnecessarily.
 	 *
 	 * Note that IRQ7 and IRQ15 (the two spurious IRQs
 	 * usually resulting from the 8259A-1|2 PICs) occur
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 9cc7031..c768d8a 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -41,6 +41,7 @@
 #include <asm/mach_apic.h>
 #include <asm/acpi.h>
 #include <asm/dma.h>
+#include <asm/nmi.h>
 
 #define __apicdebuginit  __init
 
@@ -56,6 +57,7 @@
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
 
 static DEFINE_SPINLOCK(ioapic_lock);
+static DEFINE_SPINLOCK(vector_lock);
 
 /*
  * # of IRQ routing registers
@@ -317,7 +319,7 @@
 				vendor &= 0xffff;
 				switch (vendor) { 
 				case PCI_VENDOR_ID_VIA:
-#ifdef CONFIG_GART_IOMMU
+#ifdef CONFIG_IOMMU
 					if ((end_pfn > MAX_DMA32_PFN ||
 					     force_iommu) &&
 					    !iommu_aperture_allowed) {
@@ -834,10 +836,17 @@
 int assign_irq_vector(int irq)
 {
 	static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+	unsigned long flags;
+	int vector;
 
 	BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
-	if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
+
+	spin_lock_irqsave(&vector_lock, flags);
+
+	if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+		spin_unlock_irqrestore(&vector_lock, flags);
 		return IO_APIC_VECTOR(irq);
+	}
 next:
 	current_vector += 8;
 	if (current_vector == IA32_SYSCALL_VECTOR)
@@ -849,11 +858,14 @@
 		current_vector = FIRST_DEVICE_VECTOR + offset;
 	}
 
-	vector_irq[current_vector] = irq;
+	vector = current_vector;
+	vector_irq[vector] = irq;
 	if (irq != AUTO_ASSIGN)
-		IO_APIC_VECTOR(irq) = current_vector;
+		IO_APIC_VECTOR(irq) = vector;
 
-	return current_vector;
+	spin_unlock_irqrestore(&vector_lock, flags);
+
+	return vector;
 }
 
 extern void (*interrupt[NR_IRQS])(void);
@@ -866,21 +878,14 @@
 
 static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-	if (use_pci_vector() && !platform_legacy_irq(irq)) {
-		if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-				trigger == IOAPIC_LEVEL)
-			irq_desc[vector].handler = &ioapic_level_type;
-		else
-			irq_desc[vector].handler = &ioapic_edge_type;
-		set_intr_gate(vector, interrupt[vector]);
-	} else	{
-		if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-				trigger == IOAPIC_LEVEL)
-			irq_desc[irq].handler = &ioapic_level_type;
-		else
-			irq_desc[irq].handler = &ioapic_edge_type;
-		set_intr_gate(vector, interrupt[irq]);
-	}
+	unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+
+	if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
+			trigger == IOAPIC_LEVEL)
+		irq_desc[idx].handler = &ioapic_level_type;
+	else
+		irq_desc[idx].handler = &ioapic_edge_type;
+	set_intr_gate(vector, interrupt[idx]);
 }
 
 static void __init setup_IO_APIC_irqs(void)
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index d8bd0b3..59518d4 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -26,6 +26,30 @@
 #endif
 #endif
 
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+/*
+ * Probabilistic stack overflow check:
+ *
+ * Only check the stack in process context, because everything else
+ * runs on the big interrupt stacks. Checking reliably is too expensive,
+ * so we just check from interrupts.
+ */
+static inline void stack_overflow_check(struct pt_regs *regs)
+{
+	u64 curbase = (u64) current->thread_info;
+	static unsigned long warned = -60*HZ;
+
+	if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE &&
+	    regs->rsp <  curbase + sizeof(struct thread_info) + 128 &&
+	    time_after(jiffies, warned + 60*HZ)) {
+		printk("do_IRQ: %s near stack overflow (cur:%Lx,rsp:%lx)\n",
+		       current->comm, curbase, regs->rsp);
+		show_stack(NULL,NULL);
+		warned = jiffies;
+	}
+}
+#endif
+
 /*
  * Generic, controller-independent functions:
  */
@@ -39,7 +63,7 @@
 	if (i == 0) {
 		seq_printf(p, "           ");
 		for_each_online_cpu(j)
-			seq_printf(p, "CPU%d       ",j);
+			seq_printf(p, "CPU%-8d",j);
 		seq_putc(p, '\n');
 	}
 
@@ -96,7 +120,9 @@
 
 	exit_idle();
 	irq_enter();
-
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+	stack_overflow_check(regs);
+#endif
 	__do_IRQ(irq, regs);
 	irq_exit();
 
diff --git a/arch/x86_64/kernel/k8.c b/arch/x86_64/kernel/k8.c
new file mode 100644
index 0000000..6416682
--- /dev/null
+++ b/arch/x86_64/kernel/k8.c
@@ -0,0 +1,118 @@
+/*
+ * Shared support code for AMD K8 northbridges and derivates.
+ * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
+ */
+#include <linux/gfp.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/k8.h>
+
+int num_k8_northbridges;
+EXPORT_SYMBOL(num_k8_northbridges);
+
+static u32 *flush_words;
+
+struct pci_device_id k8_nb_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) },
+	{}
+};
+EXPORT_SYMBOL(k8_nb_ids);
+
+struct pci_dev **k8_northbridges;
+EXPORT_SYMBOL(k8_northbridges);
+
+static struct pci_dev *next_k8_northbridge(struct pci_dev *dev)
+{
+	do {
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+		if (!dev)
+			break;
+	} while (!pci_match_id(&k8_nb_ids[0], dev));
+	return dev;
+}
+
+int cache_k8_northbridges(void)
+{
+	int i;
+	struct pci_dev *dev;
+	if (num_k8_northbridges)
+		return 0;
+
+	num_k8_northbridges = 0;
+	dev = NULL;
+	while ((dev = next_k8_northbridge(dev)) != NULL)
+		num_k8_northbridges++;
+
+	k8_northbridges = kmalloc((num_k8_northbridges + 1) * sizeof(void *),
+				  GFP_KERNEL);
+	if (!k8_northbridges)
+		return -ENOMEM;
+
+	flush_words = kmalloc(num_k8_northbridges * sizeof(u32), GFP_KERNEL);
+	if (!flush_words) {
+		kfree(k8_northbridges);
+		return -ENOMEM;
+	}
+
+	dev = NULL;
+	i = 0;
+	while ((dev = next_k8_northbridge(dev)) != NULL) {
+		k8_northbridges[i++] = dev;
+		pci_read_config_dword(dev, 0x9c, &flush_words[i]);
+	}
+	k8_northbridges[i] = NULL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cache_k8_northbridges);
+
+/* Ignores subdevice/subvendor but as far as I can figure out
+   they're useless anyways */
+int __init early_is_k8_nb(u32 device)
+{
+	struct pci_device_id *id;
+	u32 vendor = device & 0xffff;
+	device >>= 16;
+	for (id = k8_nb_ids; id->vendor; id++)
+		if (vendor == id->vendor && device == id->device)
+			return 1;
+	return 0;
+}
+
+void k8_flush_garts(void)
+{
+	int flushed, i;
+	unsigned long flags;
+	static DEFINE_SPINLOCK(gart_lock);
+
+	/* Avoid races between AGP and IOMMU. In theory it's not needed
+	   but I'm not sure if the hardware won't lose flush requests
+	   when another is pending. This whole thing is so expensive anyways
+	   that it doesn't matter to serialize more. -AK */
+	spin_lock_irqsave(&gart_lock, flags);
+	flushed = 0;
+	for (i = 0; i < num_k8_northbridges; i++) {
+		pci_write_config_dword(k8_northbridges[i], 0x9c,
+				       flush_words[i]|1);
+		flushed++;
+	}
+	for (i = 0; i < num_k8_northbridges; i++) {
+		u32 w;
+		/* Make sure the hardware actually executed the flush*/
+		for (;;) {
+			pci_read_config_dword(k8_northbridges[i],
+					      0x9c, &w);
+			if (!(w & 1))
+				break;
+			cpu_relax();
+		}
+	}
+	spin_unlock_irqrestore(&gart_lock, flags);
+	if (!flushed)
+		printk("nothing to flush?\n");
+}
+EXPORT_SYMBOL_GPL(k8_flush_garts);
+
diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
index 25ac8a3..83fb24a 100644
--- a/arch/x86_64/kernel/machine_kexec.c
+++ b/arch/x86_64/kernel/machine_kexec.c
@@ -149,8 +149,8 @@
 					unsigned long start_address,
 					unsigned long pgtable) ATTRIB_NORET;
 
-const extern unsigned char relocate_new_kernel[];
-const extern unsigned long relocate_new_kernel_size;
+extern const unsigned char relocate_new_kernel[];
+extern const unsigned long relocate_new_kernel_size;
 
 int machine_kexec_prepare(struct kimage *image)
 {
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index c69fc43..acd5816 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -562,7 +562,7 @@
 	set_kset_name("machinecheck"),
 };
 
-static DEFINE_PER_CPU(struct sys_device, device_mce);
+DEFINE_PER_CPU(struct sys_device, device_mce);
 
 /* Why are there no generic functions for this? */
 #define ACCESSOR(name, var, start) \
diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c
index d13b241..335200a 100644
--- a/arch/x86_64/kernel/mce_amd.c
+++ b/arch/x86_64/kernel/mce_amd.c
@@ -1,5 +1,5 @@
 /*
- *  (c) 2005 Advanced Micro Devices, Inc.
+ *  (c) 2005, 2006 Advanced Micro Devices, Inc.
  *  Your use of this code is subject to the terms and conditions of the
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
@@ -8,9 +8,10 @@
  *
  *  Support : jacob.shin@amd.com
  *
- *  MC4_MISC0 DRAM ECC Error Threshold available under AMD K8 Rev F.
- *  MC4_MISC0 exists per physical processor.
+ *  April 2006
+ *     - added support for AMD Family 0x10 processors
  *
+ *  All MC4_MISCi registers are shared between multi-cores
  */
 
 #include <linux/cpu.h>
@@ -29,32 +30,45 @@
 #include <asm/percpu.h>
 #include <asm/idle.h>
 
-#define PFX "mce_threshold: "
-#define VERSION "version 1.00.9"
-#define NR_BANKS 5
-#define THRESHOLD_MAX 0xFFF
-#define INT_TYPE_APIC 0x00020000
-#define MASK_VALID_HI 0x80000000
-#define MASK_LVTOFF_HI 0x00F00000
-#define MASK_COUNT_EN_HI 0x00080000
-#define MASK_INT_TYPE_HI 0x00060000
-#define MASK_OVERFLOW_HI 0x00010000
+#define PFX               "mce_threshold: "
+#define VERSION           "version 1.1.1"
+#define NR_BANKS          6
+#define NR_BLOCKS         9
+#define THRESHOLD_MAX     0xFFF
+#define INT_TYPE_APIC     0x00020000
+#define MASK_VALID_HI     0x80000000
+#define MASK_LVTOFF_HI    0x00F00000
+#define MASK_COUNT_EN_HI  0x00080000
+#define MASK_INT_TYPE_HI  0x00060000
+#define MASK_OVERFLOW_HI  0x00010000
 #define MASK_ERR_COUNT_HI 0x00000FFF
-#define MASK_OVERFLOW 0x0001000000000000L
+#define MASK_BLKPTR_LO    0xFF000000
+#define MCG_XBLK_ADDR     0xC0000400
 
-struct threshold_bank {
+struct threshold_block {
+	unsigned int block;
+	unsigned int bank;
 	unsigned int cpu;
-	u8 bank;
-	u8 interrupt_enable;
+	u32 address;
+	u16 interrupt_enable;
 	u16 threshold_limit;
 	struct kobject kobj;
+	struct list_head miscj;
 };
 
-static struct threshold_bank threshold_defaults = {
+/* defaults used early on boot */
+static struct threshold_block threshold_defaults = {
 	.interrupt_enable = 0,
 	.threshold_limit = THRESHOLD_MAX,
 };
 
+struct threshold_bank {
+	struct kobject kobj;
+	struct threshold_block *blocks;
+	cpumask_t cpus;
+};
+static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
+
 #ifdef CONFIG_SMP
 static unsigned char shared_bank[NR_BANKS] = {
 	0, 0, 0, 0, 1
@@ -68,12 +82,12 @@
  */
 
 /* must be called with correct cpu affinity */
-static void threshold_restart_bank(struct threshold_bank *b,
+static void threshold_restart_bank(struct threshold_block *b,
 				   int reset, u16 old_limit)
 {
 	u32 mci_misc_hi, mci_misc_lo;
 
-	rdmsr(MSR_IA32_MC0_MISC + b->bank * 4, mci_misc_lo, mci_misc_hi);
+	rdmsr(b->address, mci_misc_lo, mci_misc_hi);
 
 	if (b->threshold_limit < (mci_misc_hi & THRESHOLD_MAX))
 		reset = 1;	/* limit cannot be lower than err count */
@@ -94,35 +108,57 @@
 	    (mci_misc_hi &= ~MASK_INT_TYPE_HI);
 
 	mci_misc_hi |= MASK_COUNT_EN_HI;
-	wrmsr(MSR_IA32_MC0_MISC + b->bank * 4, mci_misc_lo, mci_misc_hi);
+	wrmsr(b->address, mci_misc_lo, mci_misc_hi);
 }
 
+/* cpu init entry point, called from mce.c with preempt off */
 void __cpuinit mce_amd_feature_init(struct cpuinfo_x86 *c)
 {
-	int bank;
-	u32 mci_misc_lo, mci_misc_hi;
+	unsigned int bank, block;
 	unsigned int cpu = smp_processor_id();
+	u32 low = 0, high = 0, address = 0;
 
 	for (bank = 0; bank < NR_BANKS; ++bank) {
-		rdmsr(MSR_IA32_MC0_MISC + bank * 4, mci_misc_lo, mci_misc_hi);
+		for (block = 0; block < NR_BLOCKS; ++block) {
+			if (block == 0)
+				address = MSR_IA32_MC0_MISC + bank * 4;
+			else if (block == 1)
+				address = MCG_XBLK_ADDR
+					+ ((low & MASK_BLKPTR_LO) >> 21);
+			else
+				++address;
 
-		/* !valid, !counter present, bios locked */
-		if (!(mci_misc_hi & MASK_VALID_HI) ||
-		    !(mci_misc_hi & MASK_VALID_HI >> 1) ||
-		    (mci_misc_hi & MASK_VALID_HI >> 2))
-			continue;
+			if (rdmsr_safe(address, &low, &high))
+				continue;
 
-		per_cpu(bank_map, cpu) |= (1 << bank);
+			if (!(high & MASK_VALID_HI)) {
+				if (block)
+					continue;
+				else
+					break;
+			}
 
+			if (!(high & MASK_VALID_HI >> 1)  ||
+			     (high & MASK_VALID_HI >> 2))
+				continue;
+
+			if (!block)
+				per_cpu(bank_map, cpu) |= (1 << bank);
 #ifdef CONFIG_SMP
-		if (shared_bank[bank] && cpu_core_id[cpu])
-			continue;
+			if (shared_bank[bank] && c->cpu_core_id)
+				break;
 #endif
+			high &= ~MASK_LVTOFF_HI;
+			high |= K8_APIC_EXT_LVT_ENTRY_THRESHOLD << 20;
+			wrmsr(address, low, high);
 
-		setup_threshold_lvt((mci_misc_hi & MASK_LVTOFF_HI) >> 20);
-		threshold_defaults.cpu = cpu;
-		threshold_defaults.bank = bank;
-		threshold_restart_bank(&threshold_defaults, 0, 0);
+			setup_APIC_extened_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
+					       THRESHOLD_APIC_VECTOR,
+					       K8_APIC_EXT_INT_MSG_FIX, 0);
+
+			threshold_defaults.address = address;
+			threshold_restart_bank(&threshold_defaults, 0, 0);
+		}
 	}
 }
 
@@ -137,8 +173,9 @@
  */
 asmlinkage void mce_threshold_interrupt(void)
 {
-	int bank;
+	unsigned int bank, block;
 	struct mce m;
+	u32 low = 0, high = 0, address = 0;
 
 	ack_APIC_irq();
 	exit_idle();
@@ -150,15 +187,42 @@
 
 	/* assume first bank caused it */
 	for (bank = 0; bank < NR_BANKS; ++bank) {
-		m.bank = MCE_THRESHOLD_BASE + bank;
-		rdmsrl(MSR_IA32_MC0_MISC + bank * 4, m.misc);
+		for (block = 0; block < NR_BLOCKS; ++block) {
+			if (block == 0)
+				address = MSR_IA32_MC0_MISC + bank * 4;
+			else if (block == 1)
+				address = MCG_XBLK_ADDR
+					+ ((low & MASK_BLKPTR_LO) >> 21);
+			else
+				++address;
 
-		if (m.misc & MASK_OVERFLOW) {
-			mce_log(&m);
-			goto out;
+			if (rdmsr_safe(address, &low, &high))
+				continue;
+
+			if (!(high & MASK_VALID_HI)) {
+				if (block)
+					continue;
+				else
+					break;
+			}
+
+			if (!(high & MASK_VALID_HI >> 1)  ||
+			     (high & MASK_VALID_HI >> 2))
+				continue;
+
+			if (high & MASK_OVERFLOW_HI) {
+				rdmsrl(address, m.misc);
+				rdmsrl(MSR_IA32_MC0_STATUS + bank * 4,
+				       m.status);
+				m.bank = K8_MCE_THRESHOLD_BASE
+				       + bank * NR_BLOCKS
+				       + block;
+				mce_log(&m);
+				goto out;
+			}
 		}
 	}
-      out:
+out:
 	irq_exit();
 }
 
@@ -166,20 +230,12 @@
  * Sysfs Interface
  */
 
-static struct sysdev_class threshold_sysclass = {
-	set_kset_name("threshold"),
-};
-
-static DEFINE_PER_CPU(struct sys_device, device_threshold);
-
 struct threshold_attr {
-        struct attribute attr;
-        ssize_t(*show) (struct threshold_bank *, char *);
-        ssize_t(*store) (struct threshold_bank *, const char *, size_t count);
+	struct attribute attr;
+	ssize_t(*show) (struct threshold_block *, char *);
+	ssize_t(*store) (struct threshold_block *, const char *, size_t count);
 };
 
-static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
-
 static cpumask_t affinity_set(unsigned int cpu)
 {
 	cpumask_t oldmask = current->cpus_allowed;
@@ -194,15 +250,15 @@
 	set_cpus_allowed(current, oldmask);
 }
 
-#define SHOW_FIELDS(name) \
-        static ssize_t show_ ## name(struct threshold_bank * b, char *buf) \
-        { \
-                return sprintf(buf, "%lx\n", (unsigned long) b->name); \
-        }
+#define SHOW_FIELDS(name)                                           \
+static ssize_t show_ ## name(struct threshold_block * b, char *buf) \
+{                                                                   \
+        return sprintf(buf, "%lx\n", (unsigned long) b->name);      \
+}
 SHOW_FIELDS(interrupt_enable)
 SHOW_FIELDS(threshold_limit)
 
-static ssize_t store_interrupt_enable(struct threshold_bank *b,
+static ssize_t store_interrupt_enable(struct threshold_block *b,
 				      const char *buf, size_t count)
 {
 	char *end;
@@ -219,7 +275,7 @@
 	return end - buf;
 }
 
-static ssize_t store_threshold_limit(struct threshold_bank *b,
+static ssize_t store_threshold_limit(struct threshold_block *b,
 				     const char *buf, size_t count)
 {
 	char *end;
@@ -242,18 +298,18 @@
 	return end - buf;
 }
 
-static ssize_t show_error_count(struct threshold_bank *b, char *buf)
+static ssize_t show_error_count(struct threshold_block *b, char *buf)
 {
 	u32 high, low;
 	cpumask_t oldmask;
 	oldmask = affinity_set(b->cpu);
-	rdmsr(MSR_IA32_MC0_MISC + b->bank * 4, low, high); /* ignore low 32 */
+	rdmsr(b->address, low, high);
 	affinity_restore(oldmask);
 	return sprintf(buf, "%x\n",
 		       (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit));
 }
 
-static ssize_t store_error_count(struct threshold_bank *b,
+static ssize_t store_error_count(struct threshold_block *b,
 				 const char *buf, size_t count)
 {
 	cpumask_t oldmask;
@@ -269,13 +325,13 @@
         .store = _store,                                      \
 };
 
-#define ATTR_FIELDS(name) \
-        static struct threshold_attr name = \
+#define RW_ATTR(name)                                           \
+static struct threshold_attr name =                             \
         THRESHOLD_ATTR(name, 0644, show_## name, store_## name)
 
-ATTR_FIELDS(interrupt_enable);
-ATTR_FIELDS(threshold_limit);
-ATTR_FIELDS(error_count);
+RW_ATTR(interrupt_enable);
+RW_ATTR(threshold_limit);
+RW_ATTR(error_count);
 
 static struct attribute *default_attrs[] = {
 	&interrupt_enable.attr,
@@ -284,12 +340,12 @@
 	NULL
 };
 
-#define to_bank(k) container_of(k,struct threshold_bank,kobj)
-#define to_attr(a) container_of(a,struct threshold_attr,attr)
+#define to_block(k) container_of(k, struct threshold_block, kobj)
+#define to_attr(a) container_of(a, struct threshold_attr, attr)
 
 static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
 {
-	struct threshold_bank *b = to_bank(kobj);
+	struct threshold_block *b = to_block(kobj);
 	struct threshold_attr *a = to_attr(attr);
 	ssize_t ret;
 	ret = a->show ? a->show(b, buf) : -EIO;
@@ -299,7 +355,7 @@
 static ssize_t store(struct kobject *kobj, struct attribute *attr,
 		     const char *buf, size_t count)
 {
-	struct threshold_bank *b = to_bank(kobj);
+	struct threshold_block *b = to_block(kobj);
 	struct threshold_attr *a = to_attr(attr);
 	ssize_t ret;
 	ret = a->store ? a->store(b, buf, count) : -EIO;
@@ -316,69 +372,174 @@
 	.default_attrs = default_attrs,
 };
 
-/* symlinks sibling shared banks to first core.  first core owns dir/files. */
-static __cpuinit int threshold_create_bank(unsigned int cpu, int bank)
+static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
+					       unsigned int bank,
+					       unsigned int block,
+					       u32 address)
 {
-	int err = 0;
+	int err;
+	u32 low, high;
+	struct threshold_block *b = NULL;
+
+	if ((bank >= NR_BANKS) || (block >= NR_BLOCKS))
+		return 0;
+
+	if (rdmsr_safe(address, &low, &high))
+		goto recurse;
+
+	if (!(high & MASK_VALID_HI)) {
+		if (block)
+			goto recurse;
+		else
+			return 0;
+	}
+
+	if (!(high & MASK_VALID_HI >> 1)  ||
+	     (high & MASK_VALID_HI >> 2))
+		goto recurse;
+
+	b = kzalloc(sizeof(struct threshold_block), GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
+	memset(b, 0, sizeof(struct threshold_block));
+
+	b->block = block;
+	b->bank = bank;
+	b->cpu = cpu;
+	b->address = address;
+	b->interrupt_enable = 0;
+	b->threshold_limit = THRESHOLD_MAX;
+
+	INIT_LIST_HEAD(&b->miscj);
+
+	if (per_cpu(threshold_banks, cpu)[bank]->blocks)
+		list_add(&b->miscj,
+			 &per_cpu(threshold_banks, cpu)[bank]->blocks->miscj);
+	else
+		per_cpu(threshold_banks, cpu)[bank]->blocks = b;
+
+	kobject_set_name(&b->kobj, "misc%i", block);
+	b->kobj.parent = &per_cpu(threshold_banks, cpu)[bank]->kobj;
+	b->kobj.ktype = &threshold_ktype;
+	err = kobject_register(&b->kobj);
+	if (err)
+		goto out_free;
+recurse:
+	if (!block) {
+		address = (low & MASK_BLKPTR_LO) >> 21;
+		if (!address)
+			return 0;
+		address += MCG_XBLK_ADDR;
+	} else
+		++address;
+
+	err = allocate_threshold_blocks(cpu, bank, ++block, address);
+	if (err)
+		goto out_free;
+
+	return err;
+
+out_free:
+	if (b) {
+		kobject_unregister(&b->kobj);
+		kfree(b);
+	}
+	return err;
+}
+
+/* symlinks sibling shared banks to first core.  first core owns dir/files. */
+static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
+{
+	int i, err = 0;
 	struct threshold_bank *b = NULL;
+	cpumask_t oldmask = CPU_MASK_NONE;
+	char name[32];
+
+	sprintf(name, "threshold_bank%i", bank);
 
 #ifdef CONFIG_SMP
-	if (cpu_core_id[cpu] && shared_bank[bank]) {	/* symlink */
-		char name[16];
-		unsigned lcpu = first_cpu(cpu_core_map[cpu]);
-		if (cpu_core_id[lcpu])
-			goto out;	/* first core not up yet */
+	if (cpu_data[cpu].cpu_core_id && shared_bank[bank]) {	/* symlink */
+		i = first_cpu(cpu_core_map[cpu]);
 
-		b = per_cpu(threshold_banks, lcpu)[bank];
+		/* first core not up yet */
+		if (cpu_data[i].cpu_core_id)
+			goto out;
+
+		/* already linked */
+		if (per_cpu(threshold_banks, cpu)[bank])
+			goto out;
+
+		b = per_cpu(threshold_banks, i)[bank];
+
 		if (!b)
 			goto out;
-		sprintf(name, "bank%i", bank);
-		err = sysfs_create_link(&per_cpu(device_threshold, cpu).kobj,
+
+		err = sysfs_create_link(&per_cpu(device_mce, cpu).kobj,
 					&b->kobj, name);
 		if (err)
 			goto out;
+
+		b->cpus = cpu_core_map[cpu];
 		per_cpu(threshold_banks, cpu)[bank] = b;
 		goto out;
 	}
 #endif
 
-	b = kmalloc(sizeof(struct threshold_bank), GFP_KERNEL);
+	b = kzalloc(sizeof(struct threshold_bank), GFP_KERNEL);
 	if (!b) {
 		err = -ENOMEM;
 		goto out;
 	}
 	memset(b, 0, sizeof(struct threshold_bank));
 
-	b->cpu = cpu;
-	b->bank = bank;
-	b->interrupt_enable = 0;
-	b->threshold_limit = THRESHOLD_MAX;
-	kobject_set_name(&b->kobj, "bank%i", bank);
-	b->kobj.parent = &per_cpu(device_threshold, cpu).kobj;
-	b->kobj.ktype = &threshold_ktype;
-
+	kobject_set_name(&b->kobj, "threshold_bank%i", bank);
+	b->kobj.parent = &per_cpu(device_mce, cpu).kobj;
+#ifndef CONFIG_SMP
+	b->cpus = CPU_MASK_ALL;
+#else
+	b->cpus = cpu_core_map[cpu];
+#endif
 	err = kobject_register(&b->kobj);
-	if (err) {
-		kfree(b);
-		goto out;
-	}
+	if (err)
+		goto out_free;
+
 	per_cpu(threshold_banks, cpu)[bank] = b;
-      out:
+
+	oldmask = affinity_set(cpu);
+	err = allocate_threshold_blocks(cpu, bank, 0,
+					MSR_IA32_MC0_MISC + bank * 4);
+	affinity_restore(oldmask);
+
+	if (err)
+		goto out_free;
+
+	for_each_cpu_mask(i, b->cpus) {
+		if (i == cpu)
+			continue;
+
+		err = sysfs_create_link(&per_cpu(device_mce, i).kobj,
+					&b->kobj, name);
+		if (err)
+			goto out;
+
+		per_cpu(threshold_banks, i)[bank] = b;
+	}
+
+	goto out;
+
+out_free:
+	per_cpu(threshold_banks, cpu)[bank] = NULL;
+	kfree(b);
+out:
 	return err;
 }
 
 /* create dir/files for all valid threshold banks */
 static __cpuinit int threshold_create_device(unsigned int cpu)
 {
-	int bank;
+	unsigned int bank;
 	int err = 0;
 
-	per_cpu(device_threshold, cpu).id = cpu;
-	per_cpu(device_threshold, cpu).cls = &threshold_sysclass;
-	err = sysdev_register(&per_cpu(device_threshold, cpu));
-	if (err)
-		goto out;
-
 	for (bank = 0; bank < NR_BANKS; ++bank) {
 		if (!(per_cpu(bank_map, cpu) & 1 << bank))
 			continue;
@@ -386,7 +547,7 @@
 		if (err)
 			goto out;
 	}
-      out:
+out:
 	return err;
 }
 
@@ -397,92 +558,85 @@
  *   of shared sysfs dir/files, and rest of the cores will be symlinked to it.
  */
 
-/* cpu hotplug call removes all symlinks before first core dies */
+static __cpuinit void deallocate_threshold_block(unsigned int cpu,
+						 unsigned int bank)
+{
+	struct threshold_block *pos = NULL;
+	struct threshold_block *tmp = NULL;
+	struct threshold_bank *head = per_cpu(threshold_banks, cpu)[bank];
+
+	if (!head)
+		return;
+
+	list_for_each_entry_safe(pos, tmp, &head->blocks->miscj, miscj) {
+		kobject_unregister(&pos->kobj);
+		list_del(&pos->miscj);
+		kfree(pos);
+	}
+
+	kfree(per_cpu(threshold_banks, cpu)[bank]->blocks);
+	per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
+}
+
 static __cpuinit void threshold_remove_bank(unsigned int cpu, int bank)
 {
+	int i = 0;
 	struct threshold_bank *b;
-	char name[16];
+	char name[32];
 
 	b = per_cpu(threshold_banks, cpu)[bank];
+
 	if (!b)
 		return;
-	if (shared_bank[bank] && atomic_read(&b->kobj.kref.refcount) > 2) {
-		sprintf(name, "bank%i", bank);
-		sysfs_remove_link(&per_cpu(device_threshold, cpu).kobj, name);
-		per_cpu(threshold_banks, cpu)[bank] = NULL;
-	} else {
-		kobject_unregister(&b->kobj);
-		kfree(per_cpu(threshold_banks, cpu)[bank]);
+
+	if (!b->blocks)
+		goto free_out;
+
+	sprintf(name, "threshold_bank%i", bank);
+
+	/* sibling symlink */
+	if (shared_bank[bank] && b->blocks->cpu != cpu) {
+		sysfs_remove_link(&per_cpu(device_mce, cpu).kobj, name);
+		per_cpu(threshold_banks, i)[bank] = NULL;
+		return;
 	}
+
+	/* remove all sibling symlinks before unregistering */
+	for_each_cpu_mask(i, b->cpus) {
+		if (i == cpu)
+			continue;
+
+		sysfs_remove_link(&per_cpu(device_mce, i).kobj, name);
+		per_cpu(threshold_banks, i)[bank] = NULL;
+	}
+
+	deallocate_threshold_block(cpu, bank);
+
+free_out:
+	kobject_unregister(&b->kobj);
+	kfree(b);
+	per_cpu(threshold_banks, cpu)[bank] = NULL;
 }
 
 static __cpuinit void threshold_remove_device(unsigned int cpu)
 {
-	int bank;
+	unsigned int bank;
 
 	for (bank = 0; bank < NR_BANKS; ++bank) {
 		if (!(per_cpu(bank_map, cpu) & 1 << bank))
 			continue;
 		threshold_remove_bank(cpu, bank);
 	}
-	sysdev_unregister(&per_cpu(device_threshold, cpu));
 }
 
-/* link all existing siblings when first core comes up */
-static __cpuinit int threshold_create_symlinks(unsigned int cpu)
-{
-	int bank, err = 0;
-	unsigned int lcpu = 0;
-
-	if (cpu_core_id[cpu])
-		return 0;
-	for_each_cpu_mask(lcpu, cpu_core_map[cpu]) {
-		if (lcpu == cpu)
-			continue;
-		for (bank = 0; bank < NR_BANKS; ++bank) {
-			if (!(per_cpu(bank_map, cpu) & 1 << bank))
-				continue;
-			if (!shared_bank[bank])
-				continue;
-			err = threshold_create_bank(lcpu, bank);
-		}
-	}
-	return err;
-}
-
-/* remove all symlinks before first core dies. */
-static __cpuinit void threshold_remove_symlinks(unsigned int cpu)
-{
-	int bank;
-	unsigned int lcpu = 0;
-	if (cpu_core_id[cpu])
-		return;
-	for_each_cpu_mask(lcpu, cpu_core_map[cpu]) {
-		if (lcpu == cpu)
-			continue;
-		for (bank = 0; bank < NR_BANKS; ++bank) {
-			if (!(per_cpu(bank_map, cpu) & 1 << bank))
-				continue;
-			if (!shared_bank[bank])
-				continue;
-			threshold_remove_bank(lcpu, bank);
-		}
-	}
-}
 #else /* !CONFIG_HOTPLUG_CPU */
-static __cpuinit void threshold_create_symlinks(unsigned int cpu)
-{
-}
-static __cpuinit void threshold_remove_symlinks(unsigned int cpu)
-{
-}
 static void threshold_remove_device(unsigned int cpu)
 {
 }
 #endif
 
 /* get notified when a cpu comes on/off */
-static int threshold_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit threshold_cpu_callback(struct notifier_block *nfb,
 					    unsigned long action, void *hcpu)
 {
 	/* cpu was unsigned int to begin with */
@@ -494,13 +648,6 @@
 	switch (action) {
 	case CPU_ONLINE:
 		threshold_create_device(cpu);
-		threshold_create_symlinks(cpu);
-		break;
-	case CPU_DOWN_PREPARE:
-		threshold_remove_symlinks(cpu);
-		break;
-	case CPU_DOWN_FAILED:
-		threshold_create_symlinks(cpu);
 		break;
 	case CPU_DEAD:
 		threshold_remove_device(cpu);
@@ -512,29 +659,22 @@
 	return NOTIFY_OK;
 }
 
-static struct notifier_block threshold_cpu_notifier = {
+static struct notifier_block threshold_cpu_notifier __cpuinitdata = {
 	.notifier_call = threshold_cpu_callback,
 };
 
 static __init int threshold_init_device(void)
 {
-	int err;
-	int lcpu = 0;
-
-	err = sysdev_class_register(&threshold_sysclass);
-	if (err)
-		goto out;
+	unsigned lcpu = 0;
 
 	/* to hit CPUs online before the notifier is up */
 	for_each_online_cpu(lcpu) {
-		err = threshold_create_device(lcpu);
+		int err = threshold_create_device(lcpu);
 		if (err)
-			goto out;
+			return err;
 	}
 	register_cpu_notifier(&threshold_cpu_notifier);
-
-      out:
-	return err;
+	return 0;
 }
 
 device_initcall(threshold_init_device);
diff --git a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c
index bac195c..9d0958f 100644
--- a/arch/x86_64/kernel/module.c
+++ b/arch/x86_64/kernel/module.c
@@ -145,26 +145,38 @@
 	return -ENOSYS;
 } 
 
-extern void apply_alternatives(void *start, void *end); 
-
 int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *me)
+                    const Elf_Shdr *sechdrs,
+                    struct module *me)
 {
-	const Elf_Shdr *s;
+	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL;
 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
-	/* look for .altinstructions to patch */ 
-	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 
-		void *seg; 		
-		if (strcmp(".altinstructions", secstrings + s->sh_name))
-			continue;
-		seg = (void *)s->sh_addr; 
-		apply_alternatives(seg, seg + s->sh_size); 
-	} 	
+	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+		if (!strcmp(".text", secstrings + s->sh_name))
+			text = s;
+		if (!strcmp(".altinstructions", secstrings + s->sh_name))
+			alt = s;
+		if (!strcmp(".smp_locks", secstrings + s->sh_name))
+			locks= s;
+	}
+
+	if (alt) {
+		/* patch .altinstructions */
+		void *aseg = (void *)alt->sh_addr;
+		apply_alternatives(aseg, aseg + alt->sh_size);
+	}
+	if (locks && text) {
+		void *lseg = (void *)locks->sh_addr;
+		void *tseg = (void *)text->sh_addr;
+		alternatives_smp_module_add(me, me->name,
+					    lseg, lseg + locks->sh_size,
+					    tseg, tseg + text->sh_size);
+	}
 	return 0;
 }
 
 void module_arch_cleanup(struct module *mod)
 {
+	alternatives_smp_module_del(mod);
 }
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 4e6357f..399489c 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -15,11 +15,7 @@
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
-#include <linux/mc146818rtc.h>
-#include <linux/kernel_stat.h>
 #include <linux/module.h>
 #include <linux/sysdev.h>
 #include <linux/nmi.h>
@@ -27,14 +23,11 @@
 #include <linux/kprobes.h>
 
 #include <asm/smp.h>
-#include <asm/mtrr.h>
-#include <asm/mpspec.h>
 #include <asm/nmi.h>
-#include <asm/msr.h>
 #include <asm/proto.h>
 #include <asm/kdebug.h>
-#include <asm/local.h>
 #include <asm/mce.h>
+#include <asm/intel_arch_perfmon.h>
 
 /*
  * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
@@ -74,6 +67,9 @@
 #define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING	0x76
 #define K7_NMI_EVENT		K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
 
+#define ARCH_PERFMON_NMI_EVENT_SEL	ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
+#define ARCH_PERFMON_NMI_EVENT_UMASK	ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
+
 #define MSR_P4_MISC_ENABLE	0x1A0
 #define MSR_P4_MISC_ENABLE_PERF_AVAIL	(1<<7)
 #define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL	(1<<12)
@@ -105,7 +101,10 @@
 	case X86_VENDOR_AMD:
 		return boot_cpu_data.x86 == 15;
 	case X86_VENDOR_INTEL:
-		return boot_cpu_data.x86 == 15;
+		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
+			return 1;
+		else
+			return (boot_cpu_data.x86 == 15);
 	}
 	return 0;
 }
@@ -211,6 +210,8 @@
 
 __setup("nmi_watchdog=", setup_nmi_watchdog);
 
+static void disable_intel_arch_watchdog(void);
+
 static void disable_lapic_nmi_watchdog(void)
 {
 	if (nmi_active <= 0)
@@ -223,6 +224,8 @@
 		if (boot_cpu_data.x86 == 15) {
 			wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
 			wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+		} else if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+			disable_intel_arch_watchdog();
 		}
 		break;
 	}
@@ -375,6 +378,53 @@
 	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
 }
 
+static void disable_intel_arch_watchdog(void)
+{
+	unsigned ebx;
+
+	/*
+	 * Check whether the Architectural PerfMon supports
+	 * Unhalted Core Cycles Event or not.
+	 * NOTE: Corresponding bit = 0 in ebp indicates event present.
+	 */
+	ebx = cpuid_ebx(10);
+	if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+		wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
+}
+
+static int setup_intel_arch_watchdog(void)
+{
+	unsigned int evntsel;
+	unsigned ebx;
+
+	/*
+	 * Check whether the Architectural PerfMon supports
+	 * Unhalted Core Cycles Event or not.
+	 * NOTE: Corresponding bit = 0 in ebp indicates event present.
+	 */
+	ebx = cpuid_ebx(10);
+	if ((ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+		return 0;
+
+	nmi_perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
+
+	clear_msr_range(MSR_ARCH_PERFMON_EVENTSEL0, 2);
+	clear_msr_range(MSR_ARCH_PERFMON_PERFCTR0, 2);
+
+	evntsel = ARCH_PERFMON_EVENTSEL_INT
+		| ARCH_PERFMON_EVENTSEL_OS
+		| ARCH_PERFMON_EVENTSEL_USR
+		| ARCH_PERFMON_NMI_EVENT_SEL
+		| ARCH_PERFMON_NMI_EVENT_UMASK;
+
+	wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
+	wrmsrl(MSR_ARCH_PERFMON_PERFCTR0, -((u64)cpu_khz * 1000 / nmi_hz));
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+	wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, evntsel, 0);
+	return 1;
+}
+
 
 static int setup_p4_watchdog(void)
 {
@@ -428,10 +478,16 @@
 		setup_k7_watchdog();
 		break;
 	case X86_VENDOR_INTEL:
-		if (boot_cpu_data.x86 != 15)
+		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+			if (!setup_intel_arch_watchdog())
+				return;
+		} else if (boot_cpu_data.x86 == 15) {
+			if (!setup_p4_watchdog())
+				return;
+		} else {
 			return;
-		if (!setup_p4_watchdog())
-			return;
+		}
+
 		break;
 
 	default:
@@ -516,7 +572,14 @@
  			 */
  			wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
  			apic_write(APIC_LVTPC, APIC_DM_NMI);
- 		}
+ 		} else if (nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
+			/*
+			 * For Intel based architectural perfmon
+			 * - LVTPC is masked on interrupt and must be
+			 *   unmasked by the LVTPC handler.
+			 */
+			apic_write(APIC_LVTPC, APIC_DM_NMI);
+		}
 		wrmsrl(nmi_perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
 	}
 }
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
new file mode 100644
index 0000000..d91cb84
--- /dev/null
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -0,0 +1,1018 @@
+/*
+ * Derived from arch/powerpc/kernel/iommu.c
+ *
+ * Copyright (C) 2006 Jon Mason <jdmason@us.ibm.com>, IBM Corporation
+ * Copyright (C) 2006 Muli Ben-Yehuda <muli@il.ibm.com>, 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/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/pci_ids.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/proto.h>
+#include <asm/calgary.h>
+#include <asm/tce.h>
+#include <asm/pci-direct.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+
+#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
+#define PCI_VENDOR_DEVICE_ID_CALGARY \
+	(PCI_VENDOR_ID_IBM | PCI_DEVICE_ID_IBM_CALGARY << 16)
+
+/* we need these for register space address calculation */
+#define START_ADDRESS           0xfe000000
+#define CHASSIS_BASE            0
+#define ONE_BASED_CHASSIS_NUM   1
+
+/* register offsets inside the host bridge space */
+#define PHB_CSR_OFFSET		0x0110
+#define PHB_PLSSR_OFFSET	0x0120
+#define PHB_CONFIG_RW_OFFSET	0x0160
+#define PHB_IOBASE_BAR_LOW	0x0170
+#define PHB_IOBASE_BAR_HIGH	0x0180
+#define PHB_MEM_1_LOW		0x0190
+#define PHB_MEM_1_HIGH		0x01A0
+#define PHB_IO_ADDR_SIZE	0x01B0
+#define PHB_MEM_1_SIZE		0x01C0
+#define PHB_MEM_ST_OFFSET	0x01D0
+#define PHB_AER_OFFSET		0x0200
+#define PHB_CONFIG_0_HIGH	0x0220
+#define PHB_CONFIG_0_LOW	0x0230
+#define PHB_CONFIG_0_END	0x0240
+#define PHB_MEM_2_LOW		0x02B0
+#define PHB_MEM_2_HIGH		0x02C0
+#define PHB_MEM_2_SIZE_HIGH	0x02D0
+#define PHB_MEM_2_SIZE_LOW	0x02E0
+#define PHB_DOSHOLE_OFFSET	0x08E0
+
+/* PHB_CONFIG_RW */
+#define PHB_TCE_ENABLE		0x20000000
+#define PHB_SLOT_DISABLE	0x1C000000
+#define PHB_DAC_DISABLE		0x01000000
+#define PHB_MEM2_ENABLE		0x00400000
+#define PHB_MCSR_ENABLE		0x00100000
+/* TAR (Table Address Register) */
+#define TAR_SW_BITS		0x0000ffffffff800fUL
+#define TAR_VALID		0x0000000000000008UL
+/* CSR (Channel/DMA Status Register) */
+#define CSR_AGENT_MASK		0xffe0ffff
+
+#define MAX_NUM_OF_PHBS		8 /* how many PHBs in total? */
+#define MAX_PHB_BUS_NUM		(MAX_NUM_OF_PHBS * 2) /* max dev->bus->number */
+#define PHBS_PER_CALGARY	4
+
+/* register offsets in Calgary's internal register space */
+static const unsigned long tar_offsets[] = {
+	0x0580 /* TAR0 */,
+	0x0588 /* TAR1 */,
+	0x0590 /* TAR2 */,
+	0x0598 /* TAR3 */
+};
+
+static const unsigned long split_queue_offsets[] = {
+	0x4870 /* SPLIT QUEUE 0 */,
+	0x5870 /* SPLIT QUEUE 1 */,
+	0x6870 /* SPLIT QUEUE 2 */,
+	0x7870 /* SPLIT QUEUE 3 */
+};
+
+static const unsigned long phb_offsets[] = {
+	0x8000 /* PHB0 */,
+	0x9000 /* PHB1 */,
+	0xA000 /* PHB2 */,
+	0xB000 /* PHB3 */
+};
+
+void* tce_table_kva[MAX_NUM_OF_PHBS * MAX_NUMNODES];
+unsigned int specified_table_size = TCE_TABLE_SIZE_UNSPECIFIED;
+static int translate_empty_slots __read_mostly = 0;
+static int calgary_detected __read_mostly = 0;
+
+/*
+ * the bitmap of PHBs the user requested that we disable
+ * translation on.
+ */
+static DECLARE_BITMAP(translation_disabled, MAX_NUMNODES * MAX_PHB_BUS_NUM);
+
+static void tce_cache_blast(struct iommu_table *tbl);
+
+/* enable this to stress test the chip's TCE cache */
+#ifdef CONFIG_IOMMU_DEBUG
+static inline void tce_cache_blast_stress(struct iommu_table *tbl)
+{
+	tce_cache_blast(tbl);
+}
+#else
+static inline void tce_cache_blast_stress(struct iommu_table *tbl)
+{
+}
+#endif /* BLAST_TCE_CACHE_ON_UNMAP */
+
+static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
+{
+	unsigned int npages;
+
+	npages = PAGE_ALIGN(dma + dmalen) - (dma & PAGE_MASK);
+	npages >>= PAGE_SHIFT;
+
+	return npages;
+}
+
+static inline int translate_phb(struct pci_dev* dev)
+{
+	int disabled = test_bit(dev->bus->number, translation_disabled);
+	return !disabled;
+}
+
+static void iommu_range_reserve(struct iommu_table *tbl,
+        unsigned long start_addr, unsigned int npages)
+{
+	unsigned long index;
+	unsigned long end;
+
+	index = start_addr >> PAGE_SHIFT;
+
+	/* bail out if we're asked to reserve a region we don't cover */
+	if (index >= tbl->it_size)
+		return;
+
+	end = index + npages;
+	if (end > tbl->it_size) /* don't go off the table */
+		end = tbl->it_size;
+
+	while (index < end) {
+		if (test_bit(index, tbl->it_map))
+			printk(KERN_ERR "Calgary: entry already allocated at "
+			       "0x%lx tbl %p dma 0x%lx npages %u\n",
+			       index, tbl, start_addr, npages);
+		++index;
+	}
+	set_bit_string(tbl->it_map, start_addr >> PAGE_SHIFT, npages);
+}
+
+static unsigned long iommu_range_alloc(struct iommu_table *tbl,
+	unsigned int npages)
+{
+	unsigned long offset;
+
+	BUG_ON(npages == 0);
+
+	offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
+				       tbl->it_size, npages);
+	if (offset == ~0UL) {
+		tce_cache_blast(tbl);
+		offset = find_next_zero_string(tbl->it_map, 0,
+					       tbl->it_size, npages);
+		if (offset == ~0UL) {
+			printk(KERN_WARNING "Calgary: IOMMU full.\n");
+			if (panic_on_overflow)
+				panic("Calgary: fix the allocator.\n");
+			else
+				return bad_dma_address;
+		}
+	}
+
+	set_bit_string(tbl->it_map, offset, npages);
+	tbl->it_hint = offset + npages;
+	BUG_ON(tbl->it_hint > tbl->it_size);
+
+	return offset;
+}
+
+static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
+	unsigned int npages, int direction)
+{
+	unsigned long entry, flags;
+	dma_addr_t ret = bad_dma_address;
+
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
+	entry = iommu_range_alloc(tbl, npages);
+
+	if (unlikely(entry == bad_dma_address))
+		goto error;
+
+	/* set the return dma address */
+	ret = (entry << PAGE_SHIFT) | ((unsigned long)vaddr & ~PAGE_MASK);
+
+	/* put the TCEs in the HW table */
+	tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK,
+		  direction);
+
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+
+	return ret;
+
+error:
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+	printk(KERN_WARNING "Calgary: failed to allocate %u pages in "
+	       "iommu %p\n", npages, tbl);
+	return bad_dma_address;
+}
+
+static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
+	unsigned int npages)
+{
+	unsigned long entry;
+	unsigned long i;
+
+	entry = dma_addr >> PAGE_SHIFT;
+
+	BUG_ON(entry + npages > tbl->it_size);
+
+	tce_free(tbl, entry, npages);
+
+	for (i = 0; i < npages; ++i) {
+		if (!test_bit(entry + i, tbl->it_map))
+			printk(KERN_ERR "Calgary: bit is off at 0x%lx "
+			       "tbl %p dma 0x%Lx entry 0x%lx npages %u\n",
+			       entry + i, tbl, dma_addr, entry, npages);
+	}
+
+	__clear_bit_string(tbl->it_map, entry, npages);
+
+	tce_cache_blast_stress(tbl);
+}
+
+static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
+	unsigned int npages)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
+	__iommu_free(tbl, dma_addr, npages);
+
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+}
+
+static void __calgary_unmap_sg(struct iommu_table *tbl,
+	struct scatterlist *sglist, int nelems, int direction)
+{
+	while (nelems--) {
+		unsigned int npages;
+		dma_addr_t dma = sglist->dma_address;
+		unsigned int dmalen = sglist->dma_length;
+
+		if (dmalen == 0)
+			break;
+
+		npages = num_dma_pages(dma, dmalen);
+		__iommu_free(tbl, dma, npages);
+		sglist++;
+	}
+}
+
+void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
+		      int nelems, int direction)
+{
+	unsigned long flags;
+	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+
+	if (!translate_phb(to_pci_dev(dev)))
+		return;
+
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
+	__calgary_unmap_sg(tbl, sglist, nelems, direction);
+
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+}
+
+static int calgary_nontranslate_map_sg(struct device* dev,
+	struct scatterlist *sg, int nelems, int direction)
+{
+	int i;
+
+ 	for (i = 0; i < nelems; i++ ) {
+		struct scatterlist *s = &sg[i];
+		BUG_ON(!s->page);
+		s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
+		s->dma_length = s->length;
+	}
+	return nelems;
+}
+
+int calgary_map_sg(struct device *dev, struct scatterlist *sg,
+	int nelems, int direction)
+{
+	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+	unsigned long flags;
+	unsigned long vaddr;
+	unsigned int npages;
+	unsigned long entry;
+	int i;
+
+	if (!translate_phb(to_pci_dev(dev)))
+		return calgary_nontranslate_map_sg(dev, sg, nelems, direction);
+
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
+	for (i = 0; i < nelems; i++ ) {
+		struct scatterlist *s = &sg[i];
+		BUG_ON(!s->page);
+
+		vaddr = (unsigned long)page_address(s->page) + s->offset;
+		npages = num_dma_pages(vaddr, s->length);
+
+		entry = iommu_range_alloc(tbl, npages);
+		if (entry == bad_dma_address) {
+			/* makes sure unmap knows to stop */
+			s->dma_length = 0;
+			goto error;
+		}
+
+		s->dma_address = (entry << PAGE_SHIFT) | s->offset;
+
+		/* insert into HW table */
+		tce_build(tbl, entry, npages, vaddr & PAGE_MASK,
+			  direction);
+
+		s->dma_length = s->length;
+	}
+
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+
+	return nelems;
+error:
+	__calgary_unmap_sg(tbl, sg, nelems, direction);
+	for (i = 0; i < nelems; i++) {
+		sg[i].dma_address = bad_dma_address;
+		sg[i].dma_length = 0;
+	}
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+	return 0;
+}
+
+dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
+	size_t size, int direction)
+{
+	dma_addr_t dma_handle = bad_dma_address;
+	unsigned long uaddr;
+	unsigned int npages;
+	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+
+	uaddr = (unsigned long)vaddr;
+	npages = num_dma_pages(uaddr, size);
+
+	if (translate_phb(to_pci_dev(dev)))
+		dma_handle = iommu_alloc(tbl, vaddr, npages, direction);
+	else
+		dma_handle = virt_to_bus(vaddr);
+
+	return dma_handle;
+}
+
+void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
+	size_t size, int direction)
+{
+	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+	unsigned int npages;
+
+	if (!translate_phb(to_pci_dev(dev)))
+		return;
+
+	npages = num_dma_pages(dma_handle, size);
+	iommu_free(tbl, dma_handle, npages);
+}
+
+void* calgary_alloc_coherent(struct device *dev, size_t size,
+	dma_addr_t *dma_handle, gfp_t flag)
+{
+	void *ret = NULL;
+	dma_addr_t mapping;
+	unsigned int npages, order;
+	struct iommu_table *tbl;
+
+	tbl = to_pci_dev(dev)->bus->self->sysdata;
+
+	size = PAGE_ALIGN(size); /* size rounded up to full pages */
+	npages = size >> PAGE_SHIFT;
+	order = get_order(size);
+
+	/* alloc enough pages (and possibly more) */
+	ret = (void *)__get_free_pages(flag, order);
+	if (!ret)
+		goto error;
+	memset(ret, 0, size);
+
+	if (translate_phb(to_pci_dev(dev))) {
+		/* set up tces to cover the allocated range */
+		mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL);
+		if (mapping == bad_dma_address)
+			goto free;
+
+		*dma_handle = mapping;
+	} else /* non translated slot */
+		*dma_handle = virt_to_bus(ret);
+
+	return ret;
+
+free:
+	free_pages((unsigned long)ret, get_order(size));
+	ret = NULL;
+error:
+	return ret;
+}
+
+static struct dma_mapping_ops calgary_dma_ops = {
+	.alloc_coherent = calgary_alloc_coherent,
+	.map_single = calgary_map_single,
+	.unmap_single = calgary_unmap_single,
+	.map_sg = calgary_map_sg,
+	.unmap_sg = calgary_unmap_sg,
+};
+
+static inline int busno_to_phbid(unsigned char num)
+{
+	return bus_to_phb(num) % PHBS_PER_CALGARY;
+}
+
+static inline unsigned long split_queue_offset(unsigned char num)
+{
+	size_t idx = busno_to_phbid(num);
+
+	return split_queue_offsets[idx];
+}
+
+static inline unsigned long tar_offset(unsigned char num)
+{
+	size_t idx = busno_to_phbid(num);
+
+	return tar_offsets[idx];
+}
+
+static inline unsigned long phb_offset(unsigned char num)
+{
+	size_t idx = busno_to_phbid(num);
+
+	return phb_offsets[idx];
+}
+
+static inline void __iomem* calgary_reg(void __iomem *bar, unsigned long offset)
+{
+	unsigned long target = ((unsigned long)bar) | offset;
+	return (void __iomem*)target;
+}
+
+static void tce_cache_blast(struct iommu_table *tbl)
+{
+	u64 val;
+	u32 aer;
+	int i = 0;
+	void __iomem *bbar = tbl->bbar;
+	void __iomem *target;
+
+	/* disable arbitration on the bus */
+	target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_AER_OFFSET);
+	aer = readl(target);
+	writel(0, target);
+
+	/* read plssr to ensure it got there */
+	target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_PLSSR_OFFSET);
+	val = readl(target);
+
+	/* poll split queues until all DMA activity is done */
+	target = calgary_reg(bbar, split_queue_offset(tbl->it_busno));
+	do {
+		val = readq(target);
+		i++;
+	} while ((val & 0xff) != 0xff && i < 100);
+	if (i == 100)
+		printk(KERN_WARNING "Calgary: PCI bus not quiesced, "
+		       "continuing anyway\n");
+
+	/* invalidate TCE cache */
+	target = calgary_reg(bbar, tar_offset(tbl->it_busno));
+	writeq(tbl->tar_val, target);
+
+	/* enable arbitration */
+	target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_AER_OFFSET);
+	writel(aer, target);
+	(void)readl(target); /* flush */
+}
+
+static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
+	u64 limit)
+{
+	unsigned int numpages;
+
+	limit = limit | 0xfffff;
+	limit++;
+
+	numpages = ((limit - start) >> PAGE_SHIFT);
+	iommu_range_reserve(dev->sysdata, start, numpages);
+}
+
+static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
+{
+	void __iomem *target;
+	u64 low, high, sizelow;
+	u64 start, limit;
+	struct iommu_table *tbl = dev->sysdata;
+	unsigned char busnum = dev->bus->number;
+	void __iomem *bbar = tbl->bbar;
+
+	/* peripheral MEM_1 region */
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_1_LOW);
+	low = be32_to_cpu(readl(target));
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_1_HIGH);
+	high = be32_to_cpu(readl(target));
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_1_SIZE);
+	sizelow = be32_to_cpu(readl(target));
+
+	start = (high << 32) | low;
+	limit = sizelow;
+
+	calgary_reserve_mem_region(dev, start, limit);
+}
+
+static void __init calgary_reserve_peripheral_mem_2(struct pci_dev *dev)
+{
+	void __iomem *target;
+	u32 val32;
+	u64 low, high, sizelow, sizehigh;
+	u64 start, limit;
+	struct iommu_table *tbl = dev->sysdata;
+	unsigned char busnum = dev->bus->number;
+	void __iomem *bbar = tbl->bbar;
+
+	/* is it enabled? */
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_CONFIG_RW_OFFSET);
+	val32 = be32_to_cpu(readl(target));
+	if (!(val32 & PHB_MEM2_ENABLE))
+		return;
+
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_2_LOW);
+	low = be32_to_cpu(readl(target));
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_2_HIGH);
+	high = be32_to_cpu(readl(target));
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_2_SIZE_LOW);
+	sizelow = be32_to_cpu(readl(target));
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_MEM_2_SIZE_HIGH);
+	sizehigh = be32_to_cpu(readl(target));
+
+	start = (high << 32) | low;
+	limit = (sizehigh << 32) | sizelow;
+
+	calgary_reserve_mem_region(dev, start, limit);
+}
+
+/*
+ * some regions of the IO address space do not get translated, so we
+ * must not give devices IO addresses in those regions. The regions
+ * are the 640KB-1MB region and the two PCI peripheral memory holes.
+ * Reserve all of them in the IOMMU bitmap to avoid giving them out
+ * later.
+ */
+static void __init calgary_reserve_regions(struct pci_dev *dev)
+{
+	unsigned int npages;
+	void __iomem *bbar;
+	unsigned char busnum;
+	u64 start;
+	struct iommu_table *tbl = dev->sysdata;
+
+	bbar = tbl->bbar;
+	busnum = dev->bus->number;
+
+	/* reserve bad_dma_address in case it's a legal address */
+	iommu_range_reserve(tbl, bad_dma_address, 1);
+
+	/* avoid the BIOS/VGA first 640KB-1MB region */
+	start = (640 * 1024);
+	npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+	iommu_range_reserve(tbl, start, npages);
+
+	/* reserve the two PCI peripheral memory regions in IO space */
+	calgary_reserve_peripheral_mem_1(dev);
+	calgary_reserve_peripheral_mem_2(dev);
+}
+
+static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
+{
+	u64 val64;
+	u64 table_phys;
+	void __iomem *target;
+	int ret;
+	struct iommu_table *tbl;
+
+	/* build TCE tables for each PHB */
+	ret = build_tce_table(dev, bbar);
+	if (ret)
+		return ret;
+
+	calgary_reserve_regions(dev);
+
+	/* set TARs for each PHB */
+	target = calgary_reg(bbar, tar_offset(dev->bus->number));
+	val64 = be64_to_cpu(readq(target));
+
+	/* zero out all TAR bits under sw control */
+	val64 &= ~TAR_SW_BITS;
+
+	tbl = dev->sysdata;
+	table_phys = (u64)__pa(tbl->it_base);
+	val64 |= table_phys;
+
+	BUG_ON(specified_table_size > TCE_TABLE_SIZE_8M);
+	val64 |= (u64) specified_table_size;
+
+	tbl->tar_val = cpu_to_be64(val64);
+	writeq(tbl->tar_val, target);
+	readq(target); /* flush */
+
+	return 0;
+}
+
+static void __init calgary_free_tar(struct pci_dev *dev)
+{
+	u64 val64;
+	struct iommu_table *tbl = dev->sysdata;
+	void __iomem *target;
+
+	target = calgary_reg(tbl->bbar, tar_offset(dev->bus->number));
+	val64 = be64_to_cpu(readq(target));
+	val64 &= ~TAR_SW_BITS;
+	writeq(cpu_to_be64(val64), target);
+	readq(target); /* flush */
+
+	kfree(tbl);
+	dev->sysdata = NULL;
+}
+
+static void calgary_watchdog(unsigned long data)
+{
+	struct pci_dev *dev = (struct pci_dev *)data;
+	struct iommu_table *tbl = dev->sysdata;
+	void __iomem *bbar = tbl->bbar;
+	u32 val32;
+	void __iomem *target;
+
+	target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
+	val32 = be32_to_cpu(readl(target));
+
+	/* If no error, the agent ID in the CSR is not valid */
+	if (val32 & CSR_AGENT_MASK) {
+		printk(KERN_EMERG "calgary_watchdog: DMA error on bus %d, "
+				  "CSR = %#x\n", dev->bus->number, val32);
+		writel(0, target);
+
+		/* Disable bus that caused the error */
+		target = calgary_reg(bbar, phb_offset(tbl->it_busno) |
+					   PHB_CONFIG_RW_OFFSET);
+		val32 = be32_to_cpu(readl(target));
+		val32 |= PHB_SLOT_DISABLE;
+		writel(cpu_to_be32(val32), target);
+		readl(target); /* flush */
+	} else {
+		/* Reset the timer */
+		mod_timer(&tbl->watchdog_timer, jiffies + 2 * HZ);
+	}
+}
+
+static void __init calgary_enable_translation(struct pci_dev *dev)
+{
+	u32 val32;
+	unsigned char busnum;
+	void __iomem *target;
+	void __iomem *bbar;
+	struct iommu_table *tbl;
+
+	busnum = dev->bus->number;
+	tbl = dev->sysdata;
+	bbar = tbl->bbar;
+
+	/* enable TCE in PHB Config Register */
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_CONFIG_RW_OFFSET);
+	val32 = be32_to_cpu(readl(target));
+	val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;
+
+	printk(KERN_INFO "Calgary: enabling translation on PHB %d\n", busnum);
+	printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
+	       "bus.\n");
+
+	writel(cpu_to_be32(val32), target);
+	readl(target); /* flush */
+
+	init_timer(&tbl->watchdog_timer);
+	tbl->watchdog_timer.function = &calgary_watchdog;
+	tbl->watchdog_timer.data = (unsigned long)dev;
+	mod_timer(&tbl->watchdog_timer, jiffies);
+}
+
+static void __init calgary_disable_translation(struct pci_dev *dev)
+{
+	u32 val32;
+	unsigned char busnum;
+	void __iomem *target;
+	void __iomem *bbar;
+	struct iommu_table *tbl;
+
+	busnum = dev->bus->number;
+	tbl = dev->sysdata;
+	bbar = tbl->bbar;
+
+	/* disable TCE in PHB Config Register */
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_CONFIG_RW_OFFSET);
+	val32 = be32_to_cpu(readl(target));
+	val32 &= ~(PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE);
+
+	printk(KERN_INFO "Calgary: disabling translation on PHB %d!\n", busnum);
+	writel(cpu_to_be32(val32), target);
+	readl(target); /* flush */
+
+	del_timer_sync(&tbl->watchdog_timer);
+}
+
+static inline unsigned int __init locate_register_space(struct pci_dev *dev)
+{
+	int rionodeid;
+	u32 address;
+
+	rionodeid = (dev->bus->number % 15 > 4) ? 3 : 2;
+	/*
+	 * register space address calculation as follows:
+	 * FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase)
+	 * ChassisBase is always zero for x366/x260/x460
+	 * RioNodeId is 2 for first Calgary, 3 for second Calgary
+	 */
+	address = START_ADDRESS	-
+		(0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 15)) +
+		(0x100000) * (rionodeid - CHASSIS_BASE);
+	return address;
+}
+
+static int __init calgary_init_one_nontraslated(struct pci_dev *dev)
+{
+	dev->sysdata = NULL;
+	dev->bus->self = dev;
+
+	return 0;
+}
+
+static int __init calgary_init_one(struct pci_dev *dev)
+{
+	u32 address;
+	void __iomem *bbar;
+	int ret;
+
+	address = locate_register_space(dev);
+	/* map entire 1MB of Calgary config space */
+	bbar = ioremap_nocache(address, 1024 * 1024);
+	if (!bbar) {
+		ret = -ENODATA;
+		goto done;
+	}
+
+	ret = calgary_setup_tar(dev, bbar);
+	if (ret)
+		goto iounmap;
+
+	dev->bus->self = dev;
+	calgary_enable_translation(dev);
+
+	return 0;
+
+iounmap:
+	iounmap(bbar);
+done:
+	return ret;
+}
+
+static int __init calgary_init(void)
+{
+	int i, ret = -ENODEV;
+	struct pci_dev *dev = NULL;
+
+	for (i = 0; i <= num_online_nodes() * MAX_NUM_OF_PHBS; i++) {
+		dev = pci_get_device(PCI_VENDOR_ID_IBM,
+				     PCI_DEVICE_ID_IBM_CALGARY,
+				     dev);
+		if (!dev)
+			break;
+		if (!translate_phb(dev)) {
+			calgary_init_one_nontraslated(dev);
+			continue;
+		}
+		if (!tce_table_kva[i] && !translate_empty_slots) {
+			pci_dev_put(dev);
+			continue;
+		}
+		ret = calgary_init_one(dev);
+		if (ret)
+			goto error;
+	}
+
+	return ret;
+
+error:
+	for (i--; i >= 0; i--) {
+		dev = pci_find_device_reverse(PCI_VENDOR_ID_IBM,
+					      PCI_DEVICE_ID_IBM_CALGARY,
+					      dev);
+		if (!translate_phb(dev)) {
+			pci_dev_put(dev);
+			continue;
+		}
+		if (!tce_table_kva[i] && !translate_empty_slots)
+			continue;
+		calgary_disable_translation(dev);
+		calgary_free_tar(dev);
+		pci_dev_put(dev);
+	}
+
+	return ret;
+}
+
+static inline int __init determine_tce_table_size(u64 ram)
+{
+	int ret;
+
+	if (specified_table_size != TCE_TABLE_SIZE_UNSPECIFIED)
+		return specified_table_size;
+
+	/*
+	 * Table sizes are from 0 to 7 (TCE_TABLE_SIZE_64K to
+	 * TCE_TABLE_SIZE_8M). Table size 0 has 8K entries and each
+	 * larger table size has twice as many entries, so shift the
+	 * max ram address by 13 to divide by 8K and then look at the
+	 * order of the result to choose between 0-7.
+	 */
+	ret = get_order(ram >> 13);
+	if (ret > TCE_TABLE_SIZE_8M)
+		ret = TCE_TABLE_SIZE_8M;
+
+	return ret;
+}
+
+void __init detect_calgary(void)
+{
+	u32 val;
+	int bus, table_idx;
+	void *tbl;
+	int detected = 0;
+
+	/*
+	 * if the user specified iommu=off or iommu=soft or we found
+	 * another HW IOMMU already, bail out.
+	 */
+	if (swiotlb || no_iommu || iommu_detected)
+		return;
+
+	specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
+
+	for (bus = 0, table_idx = 0;
+	     bus <= num_online_nodes() * MAX_PHB_BUS_NUM;
+	     bus++) {
+		BUG_ON(bus > MAX_NUMNODES * MAX_PHB_BUS_NUM);
+		if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
+			continue;
+		if (test_bit(bus, translation_disabled)) {
+			printk(KERN_INFO "Calgary: translation is disabled for "
+			       "PHB 0x%x\n", bus);
+			/* skip this phb, don't allocate a tbl for it */
+			tce_table_kva[table_idx] = NULL;
+			table_idx++;
+			continue;
+		}
+		/*
+		 * scan the first slot of the PCI bus to see if there
+		 * are any devices present
+		 */
+		val = read_pci_config(bus, 1, 0, 0);
+		if (val != 0xffffffff || translate_empty_slots) {
+			tbl = alloc_tce_table();
+			if (!tbl)
+				goto cleanup;
+			detected = 1;
+		} else
+			tbl = NULL;
+
+		tce_table_kva[table_idx] = tbl;
+		table_idx++;
+	}
+
+	if (detected) {
+		iommu_detected = 1;
+		calgary_detected = 1;
+		printk(KERN_INFO "PCI-DMA: Calgary IOMMU detected. "
+		       "TCE table spec is %d.\n", specified_table_size);
+	}
+	return;
+
+cleanup:
+	for (--table_idx; table_idx >= 0; --table_idx)
+		if (tce_table_kva[table_idx])
+			free_tce_table(tce_table_kva[table_idx]);
+}
+
+int __init calgary_iommu_init(void)
+{
+	int ret;
+
+	if (no_iommu || swiotlb)
+		return -ENODEV;
+
+	if (!calgary_detected)
+		return -ENODEV;
+
+	/* ok, we're trying to use Calgary - let's roll */
+	printk(KERN_INFO "PCI-DMA: Using Calgary IOMMU\n");
+
+	ret = calgary_init();
+	if (ret) {
+		printk(KERN_ERR "PCI-DMA: Calgary init failed %d, "
+		       "falling back to no_iommu\n", ret);
+		if (end_pfn > MAX_DMA32_PFN)
+			printk(KERN_ERR "WARNING more than 4GB of memory, "
+					"32bit PCI may malfunction.\n");
+		return ret;
+	}
+
+	force_iommu = 1;
+	dma_ops = &calgary_dma_ops;
+
+	return 0;
+}
+
+static int __init calgary_parse_options(char *p)
+{
+	unsigned int bridge;
+	size_t len;
+	char* endp;
+
+	while (*p) {
+		if (!strncmp(p, "64k", 3))
+			specified_table_size = TCE_TABLE_SIZE_64K;
+		else if (!strncmp(p, "128k", 4))
+			specified_table_size = TCE_TABLE_SIZE_128K;
+		else if (!strncmp(p, "256k", 4))
+			specified_table_size = TCE_TABLE_SIZE_256K;
+		else if (!strncmp(p, "512k", 4))
+			specified_table_size = TCE_TABLE_SIZE_512K;
+		else if (!strncmp(p, "1M", 2))
+			specified_table_size = TCE_TABLE_SIZE_1M;
+		else if (!strncmp(p, "2M", 2))
+			specified_table_size = TCE_TABLE_SIZE_2M;
+		else if (!strncmp(p, "4M", 2))
+			specified_table_size = TCE_TABLE_SIZE_4M;
+		else if (!strncmp(p, "8M", 2))
+			specified_table_size = TCE_TABLE_SIZE_8M;
+
+		len = strlen("translate_empty_slots");
+		if (!strncmp(p, "translate_empty_slots", len))
+			translate_empty_slots = 1;
+
+		len = strlen("disable");
+		if (!strncmp(p, "disable", len)) {
+			p += len;
+			if (*p == '=')
+				++p;
+			if (*p == '\0')
+				break;
+			bridge = simple_strtol(p, &endp, 0);
+			if (p == endp)
+				break;
+
+			if (bridge <= (num_online_nodes() * MAX_PHB_BUS_NUM)) {
+				printk(KERN_INFO "Calgary: disabling "
+				       "translation for PHB 0x%x\n", bridge);
+				set_bit(bridge, translation_disabled);
+			}
+		}
+
+		p = strpbrk(p, ",");
+		if (!p)
+			break;
+
+		p++; /* skip ',' */
+	}
+	return 1;
+}
+__setup("calgary=", calgary_parse_options);
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index a9275c95..9c44f4f 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <asm/io.h>
 #include <asm/proto.h>
+#include <asm/calgary.h>
 
 int iommu_merge __read_mostly = 0;
 EXPORT_SYMBOL(iommu_merge);
@@ -33,12 +34,15 @@
 int force_iommu __read_mostly= 0;
 #endif
 
+/* Set this to 1 if there is a HW IOMMU in the system */
+int iommu_detected __read_mostly = 0;
+
 /* Dummy device used for NULL arguments (normally ISA). Better would
    be probably a smaller DMA mask, but this is bug-to-bug compatible
    to i386. */
 struct device fallback_dev = {
 	.bus_id = "fallback device",
-	.coherent_dma_mask = 0xffffffff,
+	.coherent_dma_mask = DMA_32BIT_MASK,
 	.dma_mask = &fallback_dev.coherent_dma_mask,
 };
 
@@ -77,7 +81,7 @@
 		dev = &fallback_dev;
 	dma_mask = dev->coherent_dma_mask;
 	if (dma_mask == 0)
-		dma_mask = 0xffffffff;
+		dma_mask = DMA_32BIT_MASK;
 
 	/* Don't invoke OOM killer */
 	gfp |= __GFP_NORETRY;
@@ -90,7 +94,7 @@
 	   larger than 16MB and in this case we have a chance of
 	   finding fitting memory in the next higher zone first. If
 	   not retry with true GFP_DMA. -AK */
-	if (dma_mask <= 0xffffffff)
+	if (dma_mask <= DMA_32BIT_MASK)
 		gfp |= GFP_DMA32;
 
  again:
@@ -111,7 +115,7 @@
 
 			/* Don't use the 16MB ZONE_DMA unless absolutely
 			   needed. It's better to use remapping first. */
-			if (dma_mask < 0xffffffff && !(gfp & GFP_DMA)) {
+			if (dma_mask < DMA_32BIT_MASK && !(gfp & GFP_DMA)) {
 				gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
 				goto again;
 			}
@@ -174,7 +178,7 @@
 	/* Copied from i386. Doesn't make much sense, because it will
 	   only work for pci_alloc_coherent.
 	   The caller just has to use GFP_DMA in this case. */
-        if (mask < 0x00ffffff)
+        if (mask < DMA_24BIT_MASK)
                 return 0;
 
 	/* Tell the device to use SAC when IOMMU force is on.  This
@@ -189,7 +193,7 @@
 	   SAC for these.  Assume all masks <= 40 bits are of this
 	   type. Normally this doesn't make any difference, but gives
 	   more gentle handling of IOMMU overflow. */
-	if (iommu_sac_force && (mask >= 0xffffffffffULL)) {
+	if (iommu_sac_force && (mask >= DMA_40BIT_MASK)) {
 		printk(KERN_INFO "%s: Force SAC with mask %Lx\n", dev->bus_id,mask);
 		return 0;
 	}
@@ -266,7 +270,7 @@
 		    swiotlb = 1;
 #endif
 
-#ifdef CONFIG_GART_IOMMU
+#ifdef CONFIG_IOMMU
 	    gart_parse_options(p);
 #endif
 
@@ -276,3 +280,40 @@
     }
     return 1;
 }
+__setup("iommu=", iommu_setup);
+
+void __init pci_iommu_alloc(void)
+{
+	/*
+	 * The order of these functions is important for
+	 * fall-back/fail-over reasons
+	 */
+#ifdef CONFIG_IOMMU
+	iommu_hole_init();
+#endif
+
+#ifdef CONFIG_CALGARY_IOMMU
+	detect_calgary();
+#endif
+
+#ifdef CONFIG_SWIOTLB
+	pci_swiotlb_init();
+#endif
+}
+
+static int __init pci_iommu_init(void)
+{
+#ifdef CONFIG_CALGARY_IOMMU
+	calgary_iommu_init();
+#endif
+
+#ifdef CONFIG_IOMMU
+	gart_iommu_init();
+#endif
+
+	no_iommu_init();
+	return 0;
+}
+
+/* Must execute after PCI subsystem */
+fs_initcall(pci_iommu_init);
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 82a7c9b..4ca674d 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -32,6 +32,7 @@
 #include <asm/kdebug.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
+#include <asm/k8.h>
 
 unsigned long iommu_bus_base;	/* GART remapping area (physical) */
 static unsigned long iommu_size; 	/* size of remapping area bytes */
@@ -46,8 +47,6 @@
    also seen with Qlogic at least). */
 int iommu_fullflush = 1;
 
-#define MAX_NB 8
-
 /* Allocation bitmap for the remapping area */ 
 static DEFINE_SPINLOCK(iommu_bitmap_lock);
 static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
@@ -63,13 +62,6 @@
 #define to_pages(addr,size) \
 	(round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
 
-#define for_all_nb(dev) \
-	dev = NULL;	\
-	while ((dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, dev))!=NULL)
-
-static struct pci_dev *northbridges[MAX_NB];
-static u32 northbridge_flush_word[MAX_NB];
-
 #define EMERGENCY_PAGES 32 /* = 128KB */ 
 
 #ifdef CONFIG_AGP
@@ -93,7 +85,7 @@
 	offset = find_next_zero_string(iommu_gart_bitmap,next_bit,iommu_pages,size);
 	if (offset == -1) {
 		need_flush = 1;
-	       	offset = find_next_zero_string(iommu_gart_bitmap,0,next_bit,size);
+		offset = find_next_zero_string(iommu_gart_bitmap,0,iommu_pages,size);
 	}
 	if (offset != -1) { 
 		set_bit_string(iommu_gart_bitmap, offset, size); 
@@ -120,44 +112,17 @@
 /* 
  * Use global flush state to avoid races with multiple flushers.
  */
-static void flush_gart(struct device *dev)
+static void flush_gart(void)
 { 
 	unsigned long flags;
-	int flushed = 0;
-	int i, max;
-
 	spin_lock_irqsave(&iommu_bitmap_lock, flags);
-	if (need_flush) { 
-		max = 0;
-		for (i = 0; i < MAX_NB; i++) {
-			if (!northbridges[i]) 
-				continue;
-			pci_write_config_dword(northbridges[i], 0x9c, 
-					       northbridge_flush_word[i] | 1); 
-			flushed++;
-			max = i;
-		}
-		for (i = 0; i <= max; i++) {
-			u32 w;
-			if (!northbridges[i])
-				continue;
-			/* Make sure the hardware actually executed the flush. */
-			for (;;) { 
-				pci_read_config_dword(northbridges[i], 0x9c, &w);
-				if (!(w & 1))
-					break;
-				cpu_relax();
-			}
-		} 
-		if (!flushed) 
-			printk("nothing to flush?\n");
+	if (need_flush) {
+		k8_flush_garts();
 		need_flush = 0;
 	} 
 	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
 } 
 
-
-
 #ifdef CONFIG_IOMMU_LEAK
 
 #define SET_LEAK(x) if (iommu_leak_tab) \
@@ -266,7 +231,7 @@
 				 size_t size, int dir)
 {
 	dma_addr_t map = dma_map_area(dev, virt_to_bus(buf), size, dir);
-	flush_gart(dev);
+	flush_gart();
 	return map;
 }
 
@@ -289,6 +254,28 @@
 }
 
 /*
+ * Free a DMA mapping.
+ */
+void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
+		      size_t size, int direction)
+{
+	unsigned long iommu_page;
+	int npages;
+	int i;
+
+	if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE ||
+	    dma_addr >= iommu_bus_base + iommu_size)
+		return;
+	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
+	npages = to_pages(dma_addr, size);
+	for (i = 0; i < npages; i++) {
+		iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
+		CLEAR_LEAK(iommu_page + i);
+	}
+	free_iommu(iommu_page, npages);
+}
+
+/*
  * Wrapper for pci_unmap_single working with scatterlists.
  */
 void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
@@ -299,7 +286,7 @@
 		struct scatterlist *s = &sg[i];
 		if (!s->dma_length || !s->length)
 			break;
-		dma_unmap_single(dev, s->dma_address, s->dma_length, dir);
+		gart_unmap_single(dev, s->dma_address, s->dma_length, dir);
 	}
 }
 
@@ -329,7 +316,7 @@
 		s->dma_address = addr;
 		s->dma_length = s->length;
 	}
-	flush_gart(dev);
+	flush_gart();
 	return nents;
 }
 
@@ -436,13 +423,13 @@
 	if (dma_map_cont(sg, start, i, sg+out, pages, need) < 0)
 		goto error;
 	out++;
-	flush_gart(dev);
+	flush_gart();
 	if (out < nents) 
 		sg[out].dma_length = 0; 
 	return out;
 
 error:
-	flush_gart(NULL);
+	flush_gart();
 	gart_unmap_sg(dev, sg, nents, dir);
 	/* When it was forced or merged try again in a dumb way */
 	if (force_iommu || iommu_merge) {
@@ -458,28 +445,6 @@
 	return 0;
 } 
 
-/*
- * Free a DMA mapping.
- */ 
-void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
-		      size_t size, int direction)
-{
-	unsigned long iommu_page; 
-	int npages;
-	int i;
-
-	if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || 
-	    dma_addr >= iommu_bus_base + iommu_size)
-		return;
-	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;	
-	npages = to_pages(dma_addr, size);
-	for (i = 0; i < npages; i++) { 
-		iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; 
-		CLEAR_LEAK(iommu_page + i);
-	}
-	free_iommu(iommu_page, npages);
-}
-
 static int no_agp;
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
@@ -532,10 +497,13 @@
 	void *gatt;
 	unsigned aper_base, new_aper_base;
 	unsigned aper_size, gatt_size, new_aper_size;
-	
+	int i;
+
 	printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
 	aper_size = aper_base = info->aper_size = 0;
-	for_all_nb(dev) { 
+	dev = NULL;
+	for (i = 0; i < num_k8_northbridges; i++) {
+		dev = k8_northbridges[i];
 		new_aper_base = read_aperture(dev, &new_aper_size); 
 		if (!new_aper_base) 
 			goto nommu; 
@@ -558,11 +526,12 @@
 		panic("Cannot allocate GATT table"); 
 	memset(gatt, 0, gatt_size); 
 	agp_gatt_table = gatt;
-	
-	for_all_nb(dev) { 
+
+	for (i = 0; i < num_k8_northbridges; i++) {
 		u32 ctl; 
 		u32 gatt_reg; 
 
+		dev = k8_northbridges[i];
 		gatt_reg = __pa(gatt) >> 12; 
 		gatt_reg <<= 4; 
 		pci_write_config_dword(dev, 0x98, gatt_reg);
@@ -573,7 +542,7 @@
 
 		pci_write_config_dword(dev, 0x90, ctl); 
 	}
-	flush_gart(NULL); 
+	flush_gart();
 	
 	printk("PCI-DMA: aperture base @ %x size %u KB\n",aper_base, aper_size>>10); 
 	return 0;
@@ -602,15 +571,19 @@
 	.unmap_sg = gart_unmap_sg,
 };
 
-static int __init pci_iommu_init(void)
+void __init gart_iommu_init(void)
 { 
 	struct agp_kern_info info;
 	unsigned long aper_size;
 	unsigned long iommu_start;
-	struct pci_dev *dev;
 	unsigned long scratch;
 	long i;
 
+	if (cache_k8_northbridges() < 0 || num_k8_northbridges == 0) {
+		printk(KERN_INFO "PCI-GART: No AMD northbridge found.\n");
+		return;
+	}
+
 #ifndef CONFIG_AGP_AMD64
 	no_agp = 1; 
 #else
@@ -622,7 +595,11 @@
 #endif	
 
 	if (swiotlb)
-		return -1; 
+		return;
+
+	/* Did we detect a different HW IOMMU? */
+	if (iommu_detected && !iommu_aperture)
+		return;
 
 	if (no_iommu ||
 	    (!force_iommu && end_pfn <= MAX_DMA32_PFN) ||
@@ -634,15 +611,7 @@
 					"but IOMMU not available.\n"
 			       KERN_ERR "WARNING 32bit PCI may malfunction.\n");
 		}
-		return -1;
-	}
-
-	i = 0;
-	for_all_nb(dev)
-		i++;
-	if (i > MAX_NB) {
-		printk(KERN_ERR "PCI-GART: Too many northbridges (%ld). Disabled\n", i);
-		return -1;
+		return;
 	}
 
 	printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
@@ -707,26 +676,10 @@
 	for (i = EMERGENCY_PAGES; i < iommu_pages; i++) 
 		iommu_gatt_base[i] = gart_unmapped_entry;
 
-	for_all_nb(dev) {
-		u32 flag; 
-		int cpu = PCI_SLOT(dev->devfn) - 24;
-		if (cpu >= MAX_NB)
-			continue;
-		northbridges[cpu] = dev;
-		pci_read_config_dword(dev, 0x9c, &flag); /* cache flush word */
-		northbridge_flush_word[cpu] = flag; 
-	}
-		     
-	flush_gart(NULL);
-
+	flush_gart();
 	dma_ops = &gart_dma_ops;
-
-	return 0;
 } 
 
-/* Must execute after PCI subsystem */
-fs_initcall(pci_iommu_init);
-
 void gart_parse_options(char *p)
 {
 	int arg;
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index 1f6ecc6..c4c3cc3 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -4,6 +4,8 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/string.h>
+#include <linux/dma-mapping.h>
+
 #include <asm/proto.h>
 #include <asm/processor.h>
 #include <asm/dma.h>
@@ -12,10 +14,11 @@
 check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size)
 {
         if (hwdev && bus + size > *hwdev->dma_mask) {
-		if (*hwdev->dma_mask >= 0xffffffffULL)
+		if (*hwdev->dma_mask >= DMA_32BIT_MASK)
 			printk(KERN_ERR
-			    "nommu_%s: overflow %Lx+%lu of device mask %Lx\n",
-	       			name, (long long)bus, size, (long long)*hwdev->dma_mask);
+			    "nommu_%s: overflow %Lx+%zu of device mask %Lx\n",
+				name, (long long)bus, size,
+				(long long)*hwdev->dma_mask);
 		return 0;
 	}
 	return 1;
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 990ed67..ebdb77f 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -31,7 +31,7 @@
 void pci_swiotlb_init(void)
 {
 	/* don't initialize swiotlb if iommu=off (no_iommu=1) */
-	if (!iommu_aperture && !no_iommu &&
+	if (!iommu_detected && !no_iommu &&
 	    (end_pfn > MAX_DMA32_PFN || force_iommu))
 	       swiotlb = 1;
 	if (swiotlb) {
diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c
index bf421ed..7554458 100644
--- a/arch/x86_64/kernel/pmtimer.c
+++ b/arch/x86_64/kernel/pmtimer.c
@@ -27,7 +27,7 @@
 /* The I/O port the PMTMR resides at.
  * The location is detected during setup_arch(),
  * in arch/i386/kernel/acpi/boot.c */
-u32 pmtmr_ioport;
+u32 pmtmr_ioport __read_mostly;
 
 /* value of the Power timer at last timer interrupt */
 static u32 offset_delay;
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index fb903e6..ca56e19 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -10,7 +10,6 @@
  *	Andi Kleen.
  *
  *	CPU hotplug support - ashok.raj@intel.com
- *  $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $
  */
 
 /*
@@ -64,6 +63,7 @@
  * Powermanagement idle function, if any..
  */
 void (*pm_idle)(void);
+EXPORT_SYMBOL(pm_idle);
 static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
 static ATOMIC_NOTIFIER_HEAD(idle_notifier);
@@ -111,7 +111,7 @@
 {
 	local_irq_enable();
 
-	clear_thread_flag(TIF_POLLING_NRFLAG);
+	current_thread_info()->status &= ~TS_POLLING;
 	smp_mb__after_clear_bit();
 	while (!need_resched()) {
 		local_irq_disable();
@@ -120,7 +120,7 @@
 		else
 			local_irq_enable();
 	}
-	set_thread_flag(TIF_POLLING_NRFLAG);
+	current_thread_info()->status |= TS_POLLING;
 }
 
 /*
@@ -203,8 +203,7 @@
  */
 void cpu_idle (void)
 {
-	set_thread_flag(TIF_POLLING_NRFLAG);
-
+	current_thread_info()->status |= TS_POLLING;
 	/* endless idle loop with no priority at all */
 	while (1) {
 		while (!need_resched()) {
@@ -335,7 +334,7 @@
 {
 	printk("CPU %d:", smp_processor_id());
 	__show_regs(regs);
-	show_trace(&regs->rsp);
+	show_trace(NULL, regs, (void *)(regs + 1));
 }
 
 /*
@@ -365,8 +364,11 @@
 	struct task_struct *tsk = current;
 	struct thread_info *t = current_thread_info();
 
-	if (t->flags & _TIF_ABI_PENDING)
+	if (t->flags & _TIF_ABI_PENDING) {
 		t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
+		if (t->flags & _TIF_IA32)
+			current_thread_info()->status |= TS_COMPAT;
+	}
 
 	tsk->thread.debugreg0 = 0;
 	tsk->thread.debugreg1 = 0;
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 57117b8..2d67698 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -20,6 +20,7 @@
  * Power off function, if any
  */
 void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
 
 static long no_idt[3];
 static enum { 
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index b8d5116..1129918 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -5,8 +5,6 @@
  *
  *  Nov 2001 Dave Jones <davej@suse.de>
  *  Forked from i386 setup code.
- *
- *  $Id$
  */
 
 /*
@@ -47,7 +45,6 @@
 #include <linux/dmi.h>
 #include <linux/dma-mapping.h>
 #include <linux/ctype.h>
-#include <linux/suspend.h>
 
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
@@ -66,9 +63,7 @@
 #include <asm/setup.h>
 #include <asm/mach_apic.h>
 #include <asm/numa.h>
-#include <asm/swiotlb.h>
 #include <asm/sections.h>
-#include <asm/gart-mapping.h>
 #include <asm/dmi.h>
 
 /*
@@ -76,6 +71,7 @@
  */
 
 struct cpuinfo_x86 boot_cpu_data __read_mostly;
+EXPORT_SYMBOL(boot_cpu_data);
 
 unsigned long mmu_cr4_features;
 
@@ -104,12 +100,14 @@
  * Setup options
  */
 struct screen_info screen_info;
+EXPORT_SYMBOL(screen_info);
 struct sys_desc_table_struct {
 	unsigned short length;
 	unsigned char table[0];
 };
 
 struct edid_info edid_info;
+EXPORT_SYMBOL_GPL(edid_info);
 struct e820map e820;
 
 extern int root_mountflags;
@@ -474,80 +472,6 @@
 } 
 #endif
 
-/* Use inline assembly to define this because the nops are defined 
-   as inline assembly strings in the include files and we cannot 
-   get them easily into strings. */
-asm("\t.data\nk8nops: " 
-    K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
-    K8_NOP7 K8_NOP8); 
-    
-extern unsigned char k8nops[];
-static unsigned char *k8_nops[ASM_NOP_MAX+1] = { 
-     NULL,
-     k8nops,
-     k8nops + 1,
-     k8nops + 1 + 2,
-     k8nops + 1 + 2 + 3,
-     k8nops + 1 + 2 + 3 + 4,
-     k8nops + 1 + 2 + 3 + 4 + 5,
-     k8nops + 1 + 2 + 3 + 4 + 5 + 6,
-     k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
-}; 
-
-extern char __vsyscall_0;
-
-/* Replace instructions with better alternatives for this CPU type.
-
-   This runs before SMP is initialized to avoid SMP problems with
-   self modifying code. This implies that assymetric systems where
-   APs have less capabilities than the boot processor are not handled. 
-   In this case boot with "noreplacement". */ 
-void apply_alternatives(void *start, void *end) 
-{ 
-	struct alt_instr *a; 
-	int diff, i, k;
-	for (a = start; (void *)a < end; a++) { 
-		u8 *instr;
-
-		if (!boot_cpu_has(a->cpuid))
-			continue;
-
-		BUG_ON(a->replacementlen > a->instrlen); 
-		instr = a->instr;
-		/* vsyscall code is not mapped yet. resolve it manually. */
-		if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END)
-			instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0));
-		__inline_memcpy(instr, a->replacement, a->replacementlen);
-		diff = a->instrlen - a->replacementlen; 
-
-		/* Pad the rest with nops */
-		for (i = a->replacementlen; diff > 0; diff -= k, i += k) {
-			k = diff;
-			if (k > ASM_NOP_MAX)
-				k = ASM_NOP_MAX;
-			__inline_memcpy(instr + i, k8_nops[k], k);
-		} 
-	}
-} 
-
-static int no_replacement __initdata = 0; 
- 
-void __init alternative_instructions(void)
-{
-	extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
-	if (no_replacement) 
-		return;
-	apply_alternatives(__alt_instructions, __alt_instructions_end);
-}
-
-static int __init noreplacement_setup(char *s)
-{ 
-     no_replacement = 1; 
-     return 1;
-} 
-
-__setup("noreplacement", noreplacement_setup); 
-
 #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
 struct edd edd;
 #ifdef CONFIG_EDD_MODULE
@@ -596,100 +520,6 @@
 		ebda_size = 64*1024;
 }
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
-static void __init mark_nosave_page_range(unsigned long start, unsigned long end)
-{
-	struct page *page;
-	while (start <= end) {
-		page = pfn_to_page(start);
-		SetPageNosave(page);
-		start++;
-	}
-}
-
-static void __init e820_nosave_reserved_pages(void)
-{
-	int i;
-	unsigned long r_start = 0, r_end = 0;
-
-	/* Assume e820 map is sorted */
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		unsigned long start, end;
-
-		start = round_down(ei->addr, PAGE_SIZE);
-		end = round_up(ei->addr + ei->size, PAGE_SIZE);
-		if (start >= end)
-			continue;
-		if (ei->type == E820_RESERVED)
-			continue;
-		r_end = start>>PAGE_SHIFT;
-		/* swsusp ignores invalid pfn, ignore these pages here */
-		if (r_end > end_pfn)
-			r_end = end_pfn;
-		if (r_end > r_start)
-			mark_nosave_page_range(r_start, r_end-1);
-		if (r_end >= end_pfn)
-			break;
-		r_start = end>>PAGE_SHIFT;
-	}
-}
-
-static void __init e820_save_acpi_pages(void)
-{
-	int i;
-
-	/* Assume e820 map is sorted */
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		unsigned long start, end;
-
-		start = ei->addr, PAGE_SIZE;
-		end = ei->addr + ei->size;
-		if (start >= end)
-			continue;
-		if (ei->type != E820_ACPI && ei->type != E820_NVS)
-			continue;
-		/*
-		 * If the region is below end_pfn, it will be
-		 * saved/restored by swsusp follow 'RAM' type.
-		 */
-		if (start < (end_pfn << PAGE_SHIFT))
-			start = end_pfn << PAGE_SHIFT;
-		if (end > start)
-			swsusp_add_arch_pages(start, end);
-	}
-}
-
-extern char __start_rodata, __end_rodata;
-/*
- * BIOS reserved region/hole - no save/restore
- * ACPI NVS - save/restore
- * ACPI Data - this is a little tricky, the mem could be used by OS after OS
- * reads tables from the region, but anyway save/restore the memory hasn't any
- * side effect and Linux runtime module load/unload might use it.
- * kernel rodata - no save/restore (kernel rodata isn't changed)
- */
-static int __init mark_nosave_pages(void)
-{
-	unsigned long pfn_start, pfn_end;
-
-	/* BIOS reserved regions & holes */
-	e820_nosave_reserved_pages();
-
-	/* kernel rodata */
-	pfn_start = round_up(__pa_symbol(&__start_rodata), PAGE_SIZE) >> PAGE_SHIFT;
-	pfn_end = round_down(__pa_symbol(&__end_rodata), PAGE_SIZE) >> PAGE_SHIFT;
-	mark_nosave_page_range(pfn_start, pfn_end-1);
-
-	/* record ACPI Data/NVS as saveable */
-	e820_save_acpi_pages();
-
-	return 0;
-}
-core_initcall(mark_nosave_pages);
-#endif
-
 void __init setup_arch(char **cmdline_p)
 {
 	unsigned long kernel_end;
@@ -823,7 +653,7 @@
 #endif
 #ifdef CONFIG_KEXEC
 	if (crashk_res.start != crashk_res.end) {
-		reserve_bootmem(crashk_res.start,
+		reserve_bootmem_generic(crashk_res.start,
 			crashk_res.end - crashk_res.start + 1);
 	}
 #endif
@@ -874,10 +704,6 @@
 
 	e820_setup_gap();
 
-#ifdef CONFIG_GART_IOMMU
-	iommu_hole_init();
-#endif
-
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
 	conswitchp = &vga_con;
@@ -962,24 +788,32 @@
 static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
-	int cpu = smp_processor_id();
 	unsigned bits;
 #ifdef CONFIG_NUMA
+	int cpu = smp_processor_id();
 	int node = 0;
 	unsigned apicid = hard_smp_processor_id();
 #endif
+	unsigned ecx = cpuid_ecx(0x80000008);
 
-	bits = 0;
-	while ((1 << bits) < c->x86_max_cores)
-		bits++;
+	c->x86_max_cores = (ecx & 0xff) + 1;
+
+	/* CPU telling us the core id bits shift? */
+	bits = (ecx >> 12) & 0xF;
+
+	/* Otherwise recompute */
+	if (bits == 0) {
+		while ((1 << bits) < c->x86_max_cores)
+			bits++;
+	}
 
 	/* Low order bits define the core id (index of core in socket) */
-	cpu_core_id[cpu] = phys_proc_id[cpu] & ((1 << bits)-1);
+	c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1);
 	/* Convert the APIC ID into the socket ID */
-	phys_proc_id[cpu] = phys_pkg_id(bits);
+	c->phys_proc_id = phys_pkg_id(bits);
 
 #ifdef CONFIG_NUMA
-  	node = phys_proc_id[cpu];
+  	node = c->phys_proc_id;
  	if (apicid_to_node[apicid] != NUMA_NO_NODE)
  		node = apicid_to_node[apicid];
  	if (!node_online(node)) {
@@ -992,7 +826,7 @@
  		   but in the same order as the HT nodeids.
  		   If that doesn't result in a usable node fall back to the
  		   path for the previous case.  */
- 		int ht_nodeid = apicid - (phys_proc_id[0] << bits);
+ 		int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits);
  		if (ht_nodeid >= 0 &&
  		    apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
  			node = apicid_to_node[ht_nodeid];
@@ -1002,15 +836,13 @@
  	}
 	numa_set_node(cpu, node);
 
-  	printk(KERN_INFO "CPU %d/%x(%d) -> Node %d -> Core %d\n",
-  			cpu, apicid, c->x86_max_cores, node, cpu_core_id[cpu]);
+	printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
 #endif
 #endif
 }
 
-static int __init init_amd(struct cpuinfo_x86 *c)
+static void __init init_amd(struct cpuinfo_x86 *c)
 {
-	int r;
 	unsigned level;
 
 #ifdef CONFIG_SMP
@@ -1043,8 +875,8 @@
 	if (c->x86 >= 6)
 		set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability);
 
-	r = get_model_name(c);
-	if (!r) { 
+	level = get_model_name(c);
+	if (!level) {
 		switch (c->x86) { 
 		case 15:
 			/* Should distinguish Models here, but this is only
@@ -1059,13 +891,12 @@
 	if (c->x86_power & (1<<8))
 		set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
 
-	if (c->extended_cpuid_level >= 0x80000008) {
-		c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
-
+	/* Multi core CPU? */
+	if (c->extended_cpuid_level >= 0x80000008)
 		amd_detect_cmp(c);
-	}
 
-	return r;
+	/* Fix cpuid4 emulation for more */
+	num_cache_leaves = 3;
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
@@ -1073,13 +904,14 @@
 #ifdef CONFIG_SMP
 	u32 	eax, ebx, ecx, edx;
 	int 	index_msb, core_bits;
-	int 	cpu = smp_processor_id();
 
 	cpuid(1, &eax, &ebx, &ecx, &edx);
 
 
-	if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
+	if (!cpu_has(c, X86_FEATURE_HT))
 		return;
+ 	if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
+		goto out;
 
 	smp_num_siblings = (ebx & 0xff0000) >> 16;
 
@@ -1094,10 +926,7 @@
 		}
 
 		index_msb = get_count_order(smp_num_siblings);
-		phys_proc_id[cpu] = phys_pkg_id(index_msb);
-
-		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-		       phys_proc_id[cpu]);
+		c->phys_proc_id = phys_pkg_id(index_msb);
 
 		smp_num_siblings = smp_num_siblings / c->x86_max_cores;
 
@@ -1105,13 +934,15 @@
 
 		core_bits = get_count_order(c->x86_max_cores);
 
-		cpu_core_id[cpu] = phys_pkg_id(index_msb) &
+		c->cpu_core_id = phys_pkg_id(index_msb) &
 					       ((1 << core_bits) - 1);
-
-		if (c->x86_max_cores > 1)
-			printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-			       cpu_core_id[cpu]);
 	}
+out:
+	if ((c->x86_max_cores * smp_num_siblings) > 1) {
+		printk(KERN_INFO  "CPU: Physical Processor ID: %d\n", c->phys_proc_id);
+		printk(KERN_INFO  "CPU: Processor Core ID: %d\n", c->cpu_core_id);
+	}
+
 #endif
 }
 
@@ -1120,15 +951,12 @@
  */
 static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
 {
-	unsigned int eax;
+	unsigned int eax, t;
 
 	if (c->cpuid_level < 4)
 		return 1;
 
-	__asm__("cpuid"
-		: "=a" (eax)
-		: "0" (4), "c" (0)
-		: "bx", "dx");
+	cpuid_count(4, 0, &eax, &t, &t, &t);
 
 	if (eax & 0x1f)
 		return ((eax >> 26) + 1);
@@ -1141,16 +969,17 @@
 #ifdef CONFIG_NUMA
 	unsigned node;
 	int cpu = smp_processor_id();
+	int apicid = hard_smp_processor_id();
 
 	/* Don't do the funky fallback heuristics the AMD version employs
 	   for now. */
-	node = apicid_to_node[hard_smp_processor_id()];
+	node = apicid_to_node[apicid];
 	if (node == NUMA_NO_NODE)
 		node = first_node(node_online_map);
 	numa_set_node(cpu, node);
 
 	if (acpi_numa > 0)
-		printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node);
+		printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
 #endif
 }
 
@@ -1160,6 +989,13 @@
 	unsigned n;
 
 	init_intel_cacheinfo(c);
+	if (c->cpuid_level > 9 ) {
+		unsigned eax = cpuid_eax(10);
+		/* Check for version and the number of counters */
+		if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
+			set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability);
+	}
+
 	n = c->extended_cpuid_level;
 	if (n >= 0x80000008) {
 		unsigned eax = cpuid_eax(0x80000008);
@@ -1251,7 +1087,7 @@
 	}
 
 #ifdef CONFIG_SMP
-	phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff;
+	c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
 #endif
 }
 
@@ -1378,7 +1214,7 @@
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
-		NULL, "fxsr_opt", "rdtscp", NULL, NULL, "lm", "3dnowext", "3dnow",
+		NULL, "fxsr_opt", NULL, "rdtscp", NULL, "lm", "3dnowext", "3dnow",
 
 		/* Transmeta-defined */
 		"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
@@ -1389,7 +1225,7 @@
 		/* Other (Linux-defined) */
 		"cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
 		"constant_tsc", NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		"up", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
@@ -1459,9 +1295,9 @@
 #ifdef CONFIG_SMP
 	if (smp_num_siblings * c->x86_max_cores > 1) {
 		int cpu = c - cpu_data;
-		seq_printf(m, "physical id\t: %d\n", phys_proc_id[cpu]);
+		seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
 		seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu]));
-		seq_printf(m, "core id\t\t: %d\n", cpu_core_id[cpu]);
+		seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
 		seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
 	}
 #endif	
@@ -1535,7 +1371,7 @@
 	.show =	show_cpuinfo,
 };
 
-#ifdef CONFIG_INPUT_PCSPKR
+#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE)
 #include <linux/platform_device.h>
 static __init int add_pcspkr(void)
 {
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 8a691fa..f5934cb 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -3,7 +3,6 @@
  * Copyright (C) 1995  Linus Torvalds
  * Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen.
  * See setup.c for older changelog.
- * $Id: setup64.c,v 1.12 2002/03/21 10:09:17 ak Exp $
  */ 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -31,6 +30,7 @@
 cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
 
 struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(_cpu_pda);
 struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned;
 
 struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
@@ -38,6 +38,7 @@
 char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
 
 unsigned long __supported_pte_mask __read_mostly = ~0UL;
+EXPORT_SYMBOL(__supported_pte_mask);
 static int do_not_nx __cpuinitdata = 0;
 
 /* noexec=on|off
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index e5f5ce79..2816117 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -7,8 +7,6 @@
  *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-2002   x86-64 support by Andi Kleen
- * 
- *  $Id: signal.c,v 1.18 2001/10/17 22:30:37 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -239,7 +237,6 @@
 	rsp = regs->rsp - 128;
 
 	/* This is the X/Open sanctioned signal stack switching.  */
-	/* RED-PEN: redzone on that stack? */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
 		if (sas_ss_flags(rsp) == 0)
 			rsp = current->sas_ss_sp + current->sas_ss_size;
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index 4a6628b..acee4bc 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -224,6 +224,7 @@
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
 	preempt_enable();
 }
+EXPORT_SYMBOL(flush_tlb_current_task);
 
 void flush_tlb_mm (struct mm_struct * mm)
 {
@@ -244,6 +245,7 @@
 
 	preempt_enable();
 }
+EXPORT_SYMBOL(flush_tlb_mm);
 
 void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
 {
@@ -266,6 +268,7 @@
 
 	preempt_enable();
 }
+EXPORT_SYMBOL(flush_tlb_page);
 
 static void do_flush_tlb_all(void* info)
 {
@@ -443,6 +446,7 @@
 	spin_unlock(&call_lock);
 	return 0;
 }
+EXPORT_SYMBOL(smp_call_function);
 
 void smp_stop_cpu(void)
 {
@@ -460,7 +464,7 @@
 {
 	smp_stop_cpu(); 
 	for (;;) 
-		asm("hlt"); 
+		halt();
 } 
 
 void smp_send_stop(void)
@@ -470,7 +474,7 @@
 		return;
 	/* Don't deadlock on the call lock in panic */
 	if (!spin_trylock(&call_lock)) {
-		/* ignore locking because we have paniced anyways */
+		/* ignore locking because we have panicked anyways */
 		nolock = 1;
 	}
 	__smp_call_function(smp_really_stop_cpu, NULL, 0, 0);
@@ -520,13 +524,13 @@
 
 int safe_smp_processor_id(void)
 {
-	int apicid, i;
+	unsigned apicid, i;
 
 	if (disable_apic)
 		return 0;
 
 	apicid = hard_smp_processor_id();
-	if (x86_cpu_to_apicid[apicid] == apicid)
+	if (apicid < NR_CPUS && x86_cpu_to_apicid[apicid] == apicid)
 		return apicid;
 
 	for (i = 0; i < NR_CPUS; ++i) {
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 71a7222..4e97551 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -63,13 +63,11 @@
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
-/* Package ID of each logical CPU */
-u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
-/* core ID of each logical CPU */
-u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
+EXPORT_SYMBOL(smp_num_siblings);
 
 /* Last level cache ID of each logical CPU */
 u8 cpu_llc_id[NR_CPUS] __cpuinitdata  = {[0 ... NR_CPUS-1] = BAD_APICID};
+EXPORT_SYMBOL(cpu_llc_id);
 
 /* Bitmask of currently online CPUs */
 cpumask_t cpu_online_map __read_mostly;
@@ -82,18 +80,21 @@
  */
 cpumask_t cpu_callin_map;
 cpumask_t cpu_callout_map;
+EXPORT_SYMBOL(cpu_callout_map);
 
 cpumask_t cpu_possible_map;
 EXPORT_SYMBOL(cpu_possible_map);
 
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_data);
 
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
 /* representing HT siblings of each logical CPU */
 cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(cpu_sibling_map);
 
 /* representing HT and core siblings of each logical CPU */
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
@@ -472,8 +473,8 @@
 
 	if (smp_num_siblings > 1) {
 		for_each_cpu_mask(i, cpu_sibling_setup_map) {
-			if (phys_proc_id[cpu] == phys_proc_id[i] &&
-			    cpu_core_id[cpu] == cpu_core_id[i]) {
+			if (c[cpu].phys_proc_id == c[i].phys_proc_id &&
+			    c[cpu].cpu_core_id == c[i].cpu_core_id) {
 				cpu_set(i, cpu_sibling_map[cpu]);
 				cpu_set(cpu, cpu_sibling_map[i]);
 				cpu_set(i, cpu_core_map[cpu]);
@@ -500,7 +501,7 @@
 			cpu_set(i, c[cpu].llc_shared_map);
 			cpu_set(cpu, c[i].llc_shared_map);
 		}
-		if (phys_proc_id[cpu] == phys_proc_id[i]) {
+		if (c[cpu].phys_proc_id == c[i].phys_proc_id) {
 			cpu_set(i, cpu_core_map[cpu]);
 			cpu_set(cpu, cpu_core_map[i]);
 			/*
@@ -797,6 +798,8 @@
 	}
 
 
+	alternatives_smp_switch(1);
+
 	c_idle.idle = get_idle_for_cpu(cpu);
 
 	if (c_idle.idle) {
@@ -1199,8 +1202,8 @@
 		cpu_clear(cpu, cpu_sibling_map[sibling]);
 	cpus_clear(cpu_sibling_map[cpu]);
 	cpus_clear(cpu_core_map[cpu]);
-	phys_proc_id[cpu] = BAD_APICID;
-	cpu_core_id[cpu] = BAD_APICID;
+	c[cpu].phys_proc_id = 0;
+	c[cpu].cpu_core_id = 0;
 	cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
@@ -1259,6 +1262,8 @@
 		/* They ack this in play_dead by setting CPU_DEAD */
 		if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
 			printk ("CPU %d is now offline\n", cpu);
+			if (1 == num_online_cpus())
+				alternatives_smp_switch(0);
 			return;
 		}
 		msleep(100);
diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
new file mode 100644
index 0000000..8d4c67f
--- /dev/null
+++ b/arch/x86_64/kernel/tce.c
@@ -0,0 +1,202 @@
+/*
+ * Derived from arch/powerpc/platforms/pseries/iommu.c
+ *
+ * Copyright (C) 2006 Jon Mason <jdmason@us.ibm.com>, IBM Corporation
+ * Copyright (C) 2006 Muli Ben-Yehuda <muli@il.ibm.com>, 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/config.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/bootmem.h>
+#include <asm/tce.h>
+#include <asm/calgary.h>
+#include <asm/proto.h>
+
+/* flush a tce at 'tceaddr' to main memory */
+static inline void flush_tce(void* tceaddr)
+{
+	/* a single tce can't cross a cache line */
+	if (cpu_has_clflush)
+		asm volatile("clflush (%0)" :: "r" (tceaddr));
+	else
+		asm volatile("wbinvd":::"memory");
+}
+
+void tce_build(struct iommu_table *tbl, unsigned long index,
+	unsigned int npages, unsigned long uaddr, int direction)
+{
+	u64* tp;
+	u64 t;
+	u64 rpn;
+
+	t = (1 << TCE_READ_SHIFT);
+	if (direction != DMA_TO_DEVICE)
+		t |= (1 << TCE_WRITE_SHIFT);
+
+	tp = ((u64*)tbl->it_base) + index;
+
+	while (npages--) {
+		rpn = (virt_to_bus((void*)uaddr)) >> PAGE_SHIFT;
+		t &= ~TCE_RPN_MASK;
+		t |= (rpn << TCE_RPN_SHIFT);
+
+		*tp = cpu_to_be64(t);
+		flush_tce(tp);
+
+		uaddr += PAGE_SIZE;
+		tp++;
+	}
+}
+
+void tce_free(struct iommu_table *tbl, long index, unsigned int npages)
+{
+	u64* tp;
+
+	tp  = ((u64*)tbl->it_base) + index;
+
+	while (npages--) {
+		*tp = cpu_to_be64(0);
+		flush_tce(tp);
+		tp++;
+	}
+}
+
+static inline unsigned int table_size_to_number_of_entries(unsigned char size)
+{
+	/*
+	 * size is the order of the table, 0-7
+	 * smallest table is 8K entries, so shift result by 13 to
+	 * multiply by 8K
+	 */
+	return (1 << size) << 13;
+}
+
+static int tce_table_setparms(struct pci_dev *dev, struct iommu_table *tbl)
+{
+	unsigned int bitmapsz;
+	unsigned int tce_table_index;
+	unsigned long bmppages;
+	int ret;
+
+	tbl->it_busno = dev->bus->number;
+
+	/* set the tce table size - measured in entries */
+	tbl->it_size = table_size_to_number_of_entries(specified_table_size);
+
+	tce_table_index = bus_to_phb(tbl->it_busno);
+	tbl->it_base = (unsigned long)tce_table_kva[tce_table_index];
+	if (!tbl->it_base) {
+		printk(KERN_ERR "Calgary: iommu_table_setparms: "
+		       "no table allocated?!\n");
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	/*
+	 * number of bytes needed for the bitmap size in number of
+	 * entries; we need one bit per entry
+	 */
+	bitmapsz = tbl->it_size / BITS_PER_BYTE;
+	bmppages = __get_free_pages(GFP_KERNEL, get_order(bitmapsz));
+	if (!bmppages) {
+		printk(KERN_ERR "Calgary: cannot allocate bitmap\n");
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	tbl->it_map = (unsigned long*)bmppages;
+
+	memset(tbl->it_map, 0, bitmapsz);
+
+	tbl->it_hint = 0;
+
+	spin_lock_init(&tbl->it_lock);
+
+	return 0;
+
+done:
+	return ret;
+}
+
+int build_tce_table(struct pci_dev *dev, void __iomem *bbar)
+{
+	struct iommu_table *tbl;
+	int ret;
+
+	if (dev->sysdata) {
+		printk(KERN_ERR "Calgary: dev %p has sysdata %p\n",
+		       dev, dev->sysdata);
+		BUG();
+	}
+
+	tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL);
+	if (!tbl) {
+		printk(KERN_ERR "Calgary: error allocating iommu_table\n");
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	ret = tce_table_setparms(dev, tbl);
+	if (ret)
+		goto free_tbl;
+
+	tce_free(tbl, 0, tbl->it_size);
+
+	tbl->bbar = bbar;
+
+	/*
+	 * NUMA is already using the bus's sysdata pointer, so we use
+	 * the bus's pci_dev's sysdata instead.
+	 */
+	dev->sysdata = tbl;
+
+	return 0;
+
+free_tbl:
+	kfree(tbl);
+done:
+	return ret;
+}
+
+void* alloc_tce_table(void)
+{
+	unsigned int size;
+
+	size = table_size_to_number_of_entries(specified_table_size);
+	size *= TCE_ENTRY_SIZE;
+
+	return __alloc_bootmem_low(size, size, 0);
+}
+
+void free_tce_table(void *tbl)
+{
+	unsigned int size;
+
+	if (!tbl)
+		return;
+
+	size = table_size_to_number_of_entries(specified_table_size);
+	size *= TCE_ENTRY_SIZE;
+
+	free_bootmem(__pa(tbl), size);
+}
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 7392570..ebbee6f 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -8,7 +8,7 @@
  *  Copyright (c) 1995  Markus Kuhn
  *  Copyright (c) 1996  Ingo Molnar
  *  Copyright (c) 1998  Andrea Arcangeli
- *  Copyright (c) 2002  Vojtech Pavlik
+ *  Copyright (c) 2002,2006  Vojtech Pavlik
  *  Copyright (c) 2003  Andi Kleen
  *  RTC support code taken from arch/i386/kernel/timers/time_hpet.c
  */
@@ -51,14 +51,21 @@
 static char *time_init_gtod(void);
 
 DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL(rtc_lock);
 DEFINE_SPINLOCK(i8253_lock);
 
 int nohpet __initdata = 0;
 static int notsc __initdata = 0;
 
-#undef HPET_HACK_ENABLE_DANGEROUS
+#define USEC_PER_TICK (USEC_PER_SEC / HZ)
+#define NSEC_PER_TICK (NSEC_PER_SEC / HZ)
+#define FSEC_PER_TICK (FSEC_PER_SEC / HZ)
+
+#define NS_SCALE	10 /* 2^10, carefully chosen */
+#define US_SCALE	32 /* 2^32, arbitralrily chosen */
 
 unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
+EXPORT_SYMBOL(cpu_khz);
 static unsigned long hpet_period;			/* fsecs / HPET clock */
 unsigned long hpet_tick;				/* HPET clocks / interrupt */
 int hpet_use_timer;				/* Use counter of hpet for time keeping, otherwise PIT */
@@ -90,7 +97,7 @@
 	t = get_cycles_sync();
 	if (t < vxtime.last_tsc) 
 		t = vxtime.last_tsc; /* hack */
-	x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> 32;
+	x = ((t - vxtime.last_tsc) * vxtime.tsc_quot) >> US_SCALE;
 	return x;
 }
 
@@ -98,7 +105,7 @@
 {
 	/* cap counter read to one tick to avoid inconsistencies */
 	unsigned long counter = hpet_readl(HPET_COUNTER) - vxtime.last;
-	return (min(counter,hpet_tick) * vxtime.quot) >> 32;
+	return (min(counter,hpet_tick) * vxtime.quot) >> US_SCALE;
 }
 
 unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc;
@@ -118,7 +125,7 @@
 		seq = read_seqbegin(&xtime_lock);
 
 		sec = xtime.tv_sec;
-		usec = xtime.tv_nsec / 1000;
+		usec = xtime.tv_nsec / NSEC_PER_USEC;
 
 		/* i386 does some correction here to keep the clock 
 		   monotonous even when ntpd is fixing drift.
@@ -129,14 +136,14 @@
 		   in arch/x86_64/kernel/vsyscall.c and export all needed
 		   variables in vmlinux.lds. -AK */ 
 
-		t = (jiffies - wall_jiffies) * (1000000L / HZ) +
+		t = (jiffies - wall_jiffies) * USEC_PER_TICK +
 			do_gettimeoffset();
 		usec += t;
 
 	} while (read_seqretry(&xtime_lock, seq));
 
-	tv->tv_sec = sec + usec / 1000000;
-	tv->tv_usec = usec % 1000000;
+	tv->tv_sec = sec + usec / USEC_PER_SEC;
+	tv->tv_usec = usec % USEC_PER_SEC;
 }
 
 EXPORT_SYMBOL(do_gettimeofday);
@@ -157,8 +164,8 @@
 
 	write_seqlock_irq(&xtime_lock);
 
-	nsec -= do_gettimeoffset() * 1000 +
-		(jiffies - wall_jiffies) * (NSEC_PER_SEC/HZ);
+	nsec -= do_gettimeoffset() * NSEC_PER_USEC +
+		(jiffies - wall_jiffies) * NSEC_PER_TICK;
 
 	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
 	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -288,7 +295,7 @@
 			this_offset = hpet_readl(HPET_COUNTER);
 		} while (read_seqretry(&xtime_lock, seq));
 		offset = (this_offset - last_offset);
-		offset *= (NSEC_PER_SEC/HZ) / hpet_tick;
+		offset *= NSEC_PER_TICK / hpet_tick;
 	} else {
 		do {
 			seq = read_seqbegin(&xtime_lock);
@@ -297,7 +304,8 @@
 			base = monotonic_base;
 		} while (read_seqretry(&xtime_lock, seq));
 		this_offset = get_cycles_sync();
-		offset = (this_offset - last_offset)*1000 / cpu_khz; 
+		/* FIXME: 1000 or 1000000? */
+		offset = (this_offset - last_offset)*1000 / cpu_khz;
 	}
 	return base + offset;
 }
@@ -382,7 +390,7 @@
 		}
 
 		monotonic_base += 
-			(offset - vxtime.last)*(NSEC_PER_SEC/HZ) / hpet_tick;
+			(offset - vxtime.last) * NSEC_PER_TICK / hpet_tick;
 
 		vxtime.last = offset;
 #ifdef CONFIG_X86_PM_TIMER
@@ -391,24 +399,25 @@
 #endif
 	} else {
 		offset = (((tsc - vxtime.last_tsc) *
-			   vxtime.tsc_quot) >> 32) - (USEC_PER_SEC / HZ);
+			   vxtime.tsc_quot) >> US_SCALE) - USEC_PER_TICK;
 
 		if (offset < 0)
 			offset = 0;
 
-		if (offset > (USEC_PER_SEC / HZ)) {
-			lost = offset / (USEC_PER_SEC / HZ);
-			offset %= (USEC_PER_SEC / HZ);
+		if (offset > USEC_PER_TICK) {
+			lost = offset / USEC_PER_TICK;
+			offset %= USEC_PER_TICK;
 		}
 
-		monotonic_base += (tsc - vxtime.last_tsc)*1000000/cpu_khz ;
+		/* FIXME: 1000 or 1000000? */
+		monotonic_base += (tsc - vxtime.last_tsc) * 1000000 / cpu_khz;
 
 		vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot;
 
 		if ((((tsc - vxtime.last_tsc) *
-		      vxtime.tsc_quot) >> 32) < offset)
+		      vxtime.tsc_quot) >> US_SCALE) < offset)
 			vxtime.last_tsc = tsc -
-				(((long) offset << 32) / vxtime.tsc_quot) - 1;
+				(((long) offset << US_SCALE) / vxtime.tsc_quot) - 1;
 	}
 
 	if (lost > 0) {
@@ -468,16 +477,15 @@
 }
 
 static unsigned int cyc2ns_scale __read_mostly;
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
 static inline void set_cyc2ns_scale(unsigned long cpu_khz)
 {
-	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
+	cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / cpu_khz;
 }
 
 static inline unsigned long long cycles_2_ns(unsigned long long cyc)
 {
-	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+	return (cyc * cyc2ns_scale) >> NS_SCALE;
 }
 
 unsigned long long sched_clock(void)
@@ -490,7 +498,7 @@
            Disadvantage is a small drift between CPUs in some configurations,
 	   but that should be tolerable. */
 	if (__vxtime.mode == VXTIME_HPET)
-		return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> 32;
+		return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> US_SCALE;
 #endif
 
 	/* Could do CPU core sync here. Opteron can execute rdtsc speculatively,
@@ -633,7 +641,7 @@
 
 		cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
 		if (!(freq->flags & CPUFREQ_CONST_LOOPS))
-			vxtime.tsc_quot = (1000L << 32) / cpu_khz;
+			vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
 	}
 	
 	set_cyc2ns_scale(cpu_khz_ref);
@@ -789,8 +797,8 @@
 	if (hpet_use_timer) {
 		hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
 		    HPET_TN_32BIT, HPET_T0_CFG);
-		hpet_writel(hpet_tick, HPET_T0_CMP);
-		hpet_writel(hpet_tick, HPET_T0_CMP); /* AK: why twice? */
+		hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
+		hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
 		cfg |= HPET_CFG_LEGACY;
 	}
 /*
@@ -825,8 +833,7 @@
 	if (hpet_period < 100000 || hpet_period > 100000000)
 		return -1;
 
-	hpet_tick = (1000000000L * (USEC_PER_SEC / HZ) + hpet_period / 2) /
-		hpet_period;
+	hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
 
 	hpet_use_timer = (id & HPET_ID_LEGSUP);
 
@@ -890,18 +897,6 @@
 	char *timename;
 	char *gtod;
 
-#ifdef HPET_HACK_ENABLE_DANGEROUS
-        if (!vxtime.hpet_address) {
-		printk(KERN_WARNING "time.c: WARNING: Enabling HPET base "
-		       "manually!\n");
-                outl(0x800038a0, 0xcf8);
-                outl(0xff000001, 0xcfc);
-                outl(0x800038a0, 0xcf8);
-                vxtime.hpet_address = inl(0xcfc) & 0xfffffffe;
-		printk(KERN_WARNING "time.c: WARNING: Enabled HPET "
-		       "at %#lx.\n", vxtime.hpet_address);
-        }
-#endif
 	if (nohpet)
 		vxtime.hpet_address = 0;
 
@@ -912,7 +907,7 @@
 	                        -xtime.tv_sec, -xtime.tv_nsec);
 
 	if (!hpet_init())
-                vxtime_hz = (1000000000000000L + hpet_period / 2) / hpet_period;
+                vxtime_hz = (FSEC_PER_SEC + hpet_period / 2) / hpet_period;
 	else
 		vxtime.hpet_address = 0;
 
@@ -941,8 +936,8 @@
 	       vxtime_hz / 1000000, vxtime_hz % 1000000, timename, gtod);
 	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
 		cpu_khz / 1000, cpu_khz % 1000);
-	vxtime.quot = (1000000L << 32) / vxtime_hz;
-	vxtime.tsc_quot = (1000L << 32) / cpu_khz;
+	vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz;
+	vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
 	vxtime.last_tsc = get_cycles_sync();
 	setup_irq(0, &irq0);
 
@@ -956,10 +951,10 @@
 __cpuinit int unsynchronized_tsc(void)
 {
 #ifdef CONFIG_SMP
-	if (oem_force_hpet_timer())
+	if (apic_is_clustered_box())
 		return 1;
  	/* Intel systems are normally all synchronized. Exceptions
- 	   are handled in the OEM check above. */
+ 	   are handled in the check above. */
  	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
  		return 0;
 #endif
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index cea335e..3d11a2f 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -6,8 +6,6 @@
  *
  *  Pentium III FXSR, SSE support
  *	Gareth Hughes <gareth@valinux.com>, May 2000
- *
- *  $Id: traps.c,v 1.36 2002/03/24 11:09:10 ak Exp $
  */
 
 /*
@@ -31,6 +29,7 @@
 #include <linux/nmi.h>
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
+#include <linux/unwind.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -41,7 +40,7 @@
 #include <asm/i387.h>
 #include <asm/kdebug.h>
 #include <asm/processor.h>
-
+#include <asm/unwind.h>
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
 #include <asm/pda.h>
@@ -71,6 +70,7 @@
 asmlinkage void spurious_interrupt_bug(void);
 
 ATOMIC_NOTIFIER_HEAD(die_chain);
+EXPORT_SYMBOL(die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
@@ -107,7 +107,8 @@
 	preempt_enable_no_resched();
 }
 
-static int kstack_depth_to_print = 10;
+static int kstack_depth_to_print = 12;
+static int call_trace = 1;
 
 #ifdef CONFIG_KALLSYMS
 #include <linux/kallsyms.h> 
@@ -191,6 +192,25 @@
 	return NULL;
 }
 
+static int show_trace_unwind(struct unwind_frame_info *info, void *context)
+{
+	int i = 11, n = 0;
+
+	while (unwind(info) == 0 && UNW_PC(info)) {
+		++n;
+		if (i > 50) {
+			printk("\n       ");
+			i = 7;
+		} else
+			i += printk(" ");
+		i += printk_address(UNW_PC(info));
+		if (arch_unw_user_mode(info))
+			break;
+	}
+	printk("\n");
+	return n;
+}
+
 /*
  * x86-64 can have upto three kernel stacks: 
  * process stack
@@ -198,15 +218,39 @@
  * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
  */
 
-void show_trace(unsigned long *stack)
+void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack)
 {
 	const unsigned cpu = safe_smp_processor_id();
 	unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
-	int i;
+	int i = 11;
 	unsigned used = 0;
 
 	printk("\nCall Trace:");
 
+	if (!tsk)
+		tsk = current;
+
+	if (call_trace >= 0) {
+		int unw_ret = 0;
+		struct unwind_frame_info info;
+
+		if (regs) {
+			if (unwind_init_frame_info(&info, tsk, regs) == 0)
+				unw_ret = show_trace_unwind(&info, NULL);
+		} else if (tsk == current)
+			unw_ret = unwind_init_running(&info, show_trace_unwind, NULL);
+		else {
+			if (unwind_init_blocked(&info, tsk) == 0)
+				unw_ret = show_trace_unwind(&info, NULL);
+		}
+		if (unw_ret > 0) {
+			if (call_trace > 0)
+				return;
+			printk("Legacy call trace:");
+			i = 18;
+		}
+	}
+
 #define HANDLE_STACK(cond) \
 	do while (cond) { \
 		unsigned long addr = *stack++; \
@@ -229,7 +273,7 @@
 		} \
 	} while (0)
 
-	for(i = 11; ; ) {
+	for(; ; ) {
 		const char *id;
 		unsigned long *estack_end;
 		estack_end = in_exception_stack(cpu, (unsigned long)stack,
@@ -264,7 +308,7 @@
 	printk("\n");
 }
 
-void show_stack(struct task_struct *tsk, unsigned long * rsp)
+static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp)
 {
 	unsigned long *stack;
 	int i;
@@ -298,7 +342,12 @@
 		printk("%016lx ", *stack++);
 		touch_nmi_watchdog();
 	}
-	show_trace((unsigned long *)rsp);
+	show_trace(tsk, regs, rsp);
+}
+
+void show_stack(struct task_struct *tsk, unsigned long * rsp)
+{
+	_show_stack(tsk, NULL, rsp);
 }
 
 /*
@@ -307,7 +356,7 @@
 void dump_stack(void)
 {
 	unsigned long dummy;
-	show_trace(&dummy);
+	show_trace(NULL, NULL, &dummy);
 }
 
 EXPORT_SYMBOL(dump_stack);
@@ -334,7 +383,7 @@
 	if (in_kernel) {
 
 		printk("Stack: ");
-		show_stack(NULL, (unsigned long*)rsp);
+		_show_stack(NULL, regs, (unsigned long*)rsp);
 
 		printk("\nCode: ");
 		if (regs->rip < PAGE_OFFSET)
@@ -383,6 +432,7 @@
 { 
 	BUG(); 
 } 
+EXPORT_SYMBOL(out_of_line_bug);
 #endif
 
 static DEFINE_SPINLOCK(die_lock);
@@ -1012,3 +1062,14 @@
 }
 __setup("kstack=", kstack_setup);
 
+static int __init call_trace_setup(char *s)
+{
+	if (strcmp(s, "old") == 0)
+		call_trace = -1;
+	else if (strcmp(s, "both") == 0)
+		call_trace = 0;
+	else if (strcmp(s, "new") == 0)
+		call_trace = 1;
+	return 1;
+}
+__setup("call_trace=", call_trace_setup);
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index b81f473..1c6a5f3 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -45,6 +45,15 @@
 
   RODATA
 
+#ifdef CONFIG_STACK_UNWIND
+  . = ALIGN(8);
+  .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) {
+	__start_unwind = .;
+  	*(.eh_frame)
+	__end_unwind = .;
+  }
+#endif
+
 				/* Data */
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
 	*(.data)
@@ -131,6 +140,26 @@
 	*(.data.page_aligned)
   }
 
+  /* might get freed after init */
+  . = ALIGN(4096);
+  __smp_alt_begin = .;
+  __smp_alt_instructions = .;
+  .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
+	*(.smp_altinstructions)
+  }
+  __smp_alt_instructions_end = .;
+  . = ALIGN(8);
+  __smp_locks = .;
+  .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
+	*(.smp_locks)
+  }
+  __smp_locks_end = .;
+  .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
+	*(.smp_altinstr_replacement)
+  }
+  . = ALIGN(4096);
+  __smp_alt_end = .;
+
   . = ALIGN(4096);		/* Init code and data */
   __init_begin = .;
   .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 9468fb2..f603037 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -107,7 +107,7 @@
 
 int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
-	if (unlikely(!__sysctl_vsyscall))
+	if (!__sysctl_vsyscall)
 		return gettimeofday(tv,tz);
 	if (tv)
 		do_vgettimeofday(tv);
@@ -120,7 +120,7 @@
  * unlikely */
 time_t __vsyscall(1) vtime(time_t *t)
 {
-	if (unlikely(!__sysctl_vsyscall))
+	if (!__sysctl_vsyscall)
 		return time_syscall(t);
 	else if (t)
 		*t = __xtime.tv_sec;		
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index 1def21c..370952c 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -1,66 +1,21 @@
+/* Exports for assembly files.
+   All C exports should go in the respective C files. */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/smp.h>
-#include <linux/user.h>
-#include <linux/sched.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
-#include <linux/pm.h>
-#include <linux/pci.h>
-#include <linux/apm_bios.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/syscalls.h>
-#include <linux/tty.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
-#include <asm/i387.h>
 #include <asm/uaccess.h>
-#include <asm/checksum.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/mmx.h>
-#include <asm/desc.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/nmi.h>
-#include <asm/kdebug.h>
-#include <asm/unistd.h>
-#include <asm/tlbflush.h>
-#include <asm/kdebug.h>
 
-extern spinlock_t rtc_lock;
-
-#ifdef CONFIG_SMP
-extern void __write_lock_failed(rwlock_t *rw);
-extern void __read_lock_failed(rwlock_t *rw);
-#endif
-
-/* platform dependent support */
-EXPORT_SYMBOL(boot_cpu_data);
-//EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(ioremap_nocache);
-EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(pm_idle);
-EXPORT_SYMBOL(pm_power_off);
 
 EXPORT_SYMBOL(__down_failed);
 EXPORT_SYMBOL(__down_failed_interruptible);
 EXPORT_SYMBOL(__down_failed_trylock);
 EXPORT_SYMBOL(__up_wakeup);
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-EXPORT_SYMBOL(ip_compute_csum);
-/* Delay loops */
-EXPORT_SYMBOL(__udelay);
-EXPORT_SYMBOL(__ndelay);
-EXPORT_SYMBOL(__delay);
-EXPORT_SYMBOL(__const_udelay);
 
 EXPORT_SYMBOL(__get_user_1);
 EXPORT_SYMBOL(__get_user_2);
@@ -71,42 +26,20 @@
 EXPORT_SYMBOL(__put_user_4);
 EXPORT_SYMBOL(__put_user_8);
 
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(clear_user);
-EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(copy_user_generic);
 EXPORT_SYMBOL(copy_from_user);
 EXPORT_SYMBOL(copy_to_user);
-EXPORT_SYMBOL(copy_in_user);
-EXPORT_SYMBOL(strnlen_user);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_mem_start);
-#endif
 
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(clear_page);
 
-EXPORT_SYMBOL(_cpu_pda);
 #ifdef CONFIG_SMP
-EXPORT_SYMBOL(cpu_data);
+extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
+extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
 EXPORT_SYMBOL(__write_lock_failed);
 EXPORT_SYMBOL(__read_lock_failed);
-
-EXPORT_SYMBOL(smp_call_function);
-EXPORT_SYMBOL(cpu_callout_map);
 #endif
 
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
-EXPORT_SYMBOL(rtc_lock);
-
-EXPORT_SYMBOL_GPL(set_nmi_callback);
-EXPORT_SYMBOL_GPL(unset_nmi_callback);
-
 /* Export string functions. We normally rely on gcc builtin for most of these,
    but gcc sometimes decides not to inline them. */    
 #undef memcpy
@@ -114,51 +47,14 @@
 #undef memmove
 
 extern void * memset(void *,int,__kernel_size_t);
-extern size_t strlen(const char *);
-extern void * memmove(void * dest,const void *src,size_t count);
 extern void * memcpy(void *,const void *,__kernel_size_t);
 extern void * __memcpy(void *,const void *,__kernel_size_t);
 
 EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(__memcpy);
 
-#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
-/* prototypes are wrong, these are assembly with custom calling functions */
-extern void rwsem_down_read_failed_thunk(void);
-extern void rwsem_wake_thunk(void);
-extern void rwsem_downgrade_thunk(void);
-extern void rwsem_down_write_failed_thunk(void);
-EXPORT_SYMBOL(rwsem_down_read_failed_thunk);
-EXPORT_SYMBOL(rwsem_wake_thunk);
-EXPORT_SYMBOL(rwsem_downgrade_thunk);
-EXPORT_SYMBOL(rwsem_down_write_failed_thunk);
-#endif
-
 EXPORT_SYMBOL(empty_zero_page);
-
-EXPORT_SYMBOL(die_chain);
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(cpu_sibling_map);
-EXPORT_SYMBOL(smp_num_siblings);
-#endif
-
-#ifdef CONFIG_BUG
-EXPORT_SYMBOL(out_of_line_bug);
-#endif
-
 EXPORT_SYMBOL(init_level4_pgt);
-
-extern unsigned long __supported_pte_mask;
-EXPORT_SYMBOL(__supported_pte_mask);
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(flush_tlb_page);
-#endif
-
-EXPORT_SYMBOL(cpu_khz);
-
 EXPORT_SYMBOL(load_gs_index);
 
diff --git a/arch/x86_64/lib/csum-partial.c b/arch/x86_64/lib/csum-partial.c
index 5384e22..c493735 100644
--- a/arch/x86_64/lib/csum-partial.c
+++ b/arch/x86_64/lib/csum-partial.c
@@ -147,4 +147,5 @@
 {
 	return csum_fold(csum_partial(buff,len,0));
 }
+EXPORT_SYMBOL(ip_compute_csum);
 
diff --git a/arch/x86_64/lib/csum-wrappers.c b/arch/x86_64/lib/csum-wrappers.c
index 94323f2..b1320ec 100644
--- a/arch/x86_64/lib/csum-wrappers.c
+++ b/arch/x86_64/lib/csum-wrappers.c
@@ -109,6 +109,7 @@
 { 
 	return csum_partial_copy_generic(src,dst,len,sum,NULL,NULL);
 } 
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
 
 unsigned short csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
 			       __u32 len, unsigned short proto, unsigned int sum) 
diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
index 03c460c..b6cd3cc 100644
--- a/arch/x86_64/lib/delay.c
+++ b/arch/x86_64/lib/delay.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <asm/delay.h>
@@ -36,18 +37,22 @@
 	}
 	while((now-bclock) < loops);
 }
+EXPORT_SYMBOL(__delay);
 
 inline void __const_udelay(unsigned long xloops)
 {
 	__delay((xloops * HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy) >> 32);
 }
+EXPORT_SYMBOL(__const_udelay);
 
 void __udelay(unsigned long usecs)
 {
 	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
 }
+EXPORT_SYMBOL(__udelay);
 
 void __ndelay(unsigned long nsecs)
 {
 	__const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
 }
+EXPORT_SYMBOL(__ndelay);
diff --git a/arch/x86_64/lib/memmove.c b/arch/x86_64/lib/memmove.c
index e93d525..751ebae 100644
--- a/arch/x86_64/lib/memmove.c
+++ b/arch/x86_64/lib/memmove.c
@@ -3,12 +3,13 @@
  */
 #define _STRING_C
 #include <linux/string.h>
+#include <linux/module.h>
 
 #undef memmove
 void *memmove(void * dest,const void *src,size_t count)
 {
 	if (dest < src) { 
-		__inline_memcpy(dest,src,count);
+		return memcpy(dest,src,count);
 	} else {
 		char *p = (char *) dest + count;
 		char *s = (char *) src + count;
@@ -17,3 +18,4 @@
 	}
 	return dest;
 } 
+EXPORT_SYMBOL(memmove);
diff --git a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy.c
index 9bc2c29..893d43f 100644
--- a/arch/x86_64/lib/usercopy.c
+++ b/arch/x86_64/lib/usercopy.c
@@ -5,6 +5,7 @@
  * Copyright 1997 Linus Torvalds
  * Copyright 2002 Andi Kleen <ak@suse.de>
  */
+#include <linux/module.h>
 #include <asm/uaccess.h>
 
 /*
@@ -47,15 +48,17 @@
 	__do_strncpy_from_user(dst, src, count, res);
 	return res;
 }
+EXPORT_SYMBOL(__strncpy_from_user);
 
 long
 strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res = -EFAULT;
 	if (access_ok(VERIFY_READ, src, 1))
-		__do_strncpy_from_user(dst, src, count, res);
+		return __strncpy_from_user(dst, src, count);
 	return res;
 }
+EXPORT_SYMBOL(strncpy_from_user);
 
 /*
  * Zero Userspace
@@ -94,7 +97,7 @@
 		  [zero] "r" (0UL), [eight] "r" (8UL));
 	return size;
 }
-
+EXPORT_SYMBOL(__clear_user);
 
 unsigned long clear_user(void __user *to, unsigned long n)
 {
@@ -102,6 +105,7 @@
 		return __clear_user(to, n);
 	return n;
 }
+EXPORT_SYMBOL(clear_user);
 
 /*
  * Return the size of a string (including the ending 0)
@@ -125,6 +129,7 @@
 		s++;
 	}
 }
+EXPORT_SYMBOL(__strnlen_user);
 
 long strnlen_user(const char __user *s, long n)
 {
@@ -132,6 +137,7 @@
 		return 0;
 	return __strnlen_user(s, n);
 }
+EXPORT_SYMBOL(strnlen_user);
 
 long strlen_user(const char __user *s)
 {
@@ -147,6 +153,7 @@
 		s++;
 	}
 }
+EXPORT_SYMBOL(strlen_user);
 
 unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
 {
@@ -155,3 +162,5 @@
 	} 
 	return len;		
 }
+EXPORT_SYMBOL(copy_in_user);
+
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 5525059..08dc696 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -41,6 +41,41 @@
 #define PF_RSVD	(1<<3)
 #define PF_INSTR	(1<<4)
 
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+/* Hook to register for page fault notifications */
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+	vmalloc_sync_all();
+	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	struct die_args args = {
+		.regs = regs,
+		.str = str,
+		.err = err,
+		.trapnr = trap,
+		.signr = sig
+	};
+	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, const char *str,
+			struct pt_regs *regs, long err, int trap, int sig)
+{
+	return NOTIFY_DONE;
+}
+#endif
+
 void bust_spinlocks(int yes)
 {
 	int loglevel_save = console_loglevel;
@@ -160,7 +195,7 @@
 	printk("PGD %lx ", pgd_val(*pgd));
 	if (!pgd_present(*pgd)) goto ret; 
 
-	pud = __pud_offset_k((pud_t *)pgd_page(*pgd), address);
+	pud = pud_offset(pgd, address);
 	if (bad_address(pud)) goto bad;
 	printk("PUD %lx ", pud_val(*pud));
 	if (!pud_present(*pud))	goto ret;
@@ -348,7 +383,7 @@
 			if (vmalloc_fault(address) >= 0)
 				return;
 		}
-		if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
+		if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 						SIGSEGV) == NOTIFY_STOP)
 			return;
 		/*
@@ -358,7 +393,7 @@
 		goto bad_area_nosemaphore;
 	}
 
-	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
+	if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 					SIGSEGV) == NOTIFY_STOP)
 		return;
 
@@ -410,8 +445,10 @@
 	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
 	if (error_code & 4) {
-		// XXX: align red zone size with ABI 
-		if (address + 128 < regs->rsp)
+		/* Allow userspace just enough access below the stack pointer
+		 * to let the 'enter' instruction work.
+		 */
+		if (address + 65536 + 32 * sizeof(unsigned long) < regs->rsp)
 			goto bad_area;
 	}
 	if (expand_stack(vma, address))
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 4ba34e9..02add1d 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -41,8 +41,6 @@
 #include <asm/proto.h>
 #include <asm/smp.h>
 #include <asm/sections.h>
-#include <asm/dma-mapping.h>
-#include <asm/swiotlb.h>
 
 #ifndef Dprintk
 #define Dprintk(x...)
@@ -90,8 +88,6 @@
 	printk(KERN_INFO "%lu pages swap cached\n",cached);
 }
 
-/* References to section boundaries */
-
 int after_bootmem;
 
 static __init void *spp_getpage(void)
@@ -261,9 +257,10 @@
 	for (i = 0; i < PTRS_PER_PMD; pmd++, i++, address += PMD_SIZE) {
 		unsigned long entry;
 
-		if (address > end) {
-			for (; i < PTRS_PER_PMD; i++, pmd++)
-				set_pmd(pmd, __pmd(0));
+		if (address >= end) {
+			if (!after_bootmem)
+				for (; i < PTRS_PER_PMD; i++, pmd++)
+					set_pmd(pmd, __pmd(0));
 			break;
 		}
 		entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
@@ -341,7 +338,8 @@
 	table_end = table_start;
 
 	early_printk("kernel direct mapping tables up to %lx @ %lx-%lx\n",
-		end, table_start << PAGE_SHIFT, table_end << PAGE_SHIFT);
+		end, table_start << PAGE_SHIFT,
+		(table_start << PAGE_SHIFT) + tables);
 }
 
 /* Setup the direct mapping of the physical memory at PAGE_OFFSET.
@@ -372,7 +370,7 @@
 		pud_t *pud;
 
 		if (after_bootmem)
-			pud = pud_offset_k(pgd, start & PGDIR_MASK);
+			pud = pud_offset(pgd, start & PGDIR_MASK);
 		else
 			pud = alloc_low_page(&map, &pud_phys);
 
@@ -587,10 +585,7 @@
 {
 	long codesize, reservedpages, datasize, initsize;
 
-#ifdef CONFIG_SWIOTLB
-	pci_swiotlb_init();
-#endif
-	no_iommu_init();
+	pci_iommu_alloc();
 
 	/* How many end-of-memory variables you have, grandma! */
 	max_low_pfn = end_pfn;
@@ -644,20 +639,29 @@
 #endif
 }
 
-void free_initmem(void)
+void free_init_pages(char *what, unsigned long begin, unsigned long end)
 {
 	unsigned long addr;
 
-	addr = (unsigned long)(&__init_begin);
-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+	if (begin >= end)
+		return;
+
+	printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+	for (addr = begin; addr < end; addr += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(addr));
 		init_page_count(virt_to_page(addr));
 		memset((void *)(addr & ~(PAGE_SIZE-1)), 0xcc, PAGE_SIZE); 
 		free_page(addr);
 		totalram_pages++;
 	}
+}
+
+void free_initmem(void)
+{
 	memset(__initdata_begin, 0xba, __initdata_end - __initdata_begin);
-	printk ("Freeing unused kernel memory: %luk freed\n", (__init_end - __init_begin) >> 10);
+	free_init_pages("unused kernel memory",
+			(unsigned long)(&__init_begin),
+			(unsigned long)(&__init_end));
 }
 
 #ifdef CONFIG_DEBUG_RODATA
@@ -686,15 +690,7 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-	if (start >= end)
-		return;
-	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
-	for (; start < end; start += PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(start));
-		init_page_count(virt_to_page(start));
-		free_page(start);
-		totalram_pages++;
-	}
+	free_init_pages("initrd memory", start, end);
 }
 #endif
 
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
index ae20706..45d7d82 100644
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -11,6 +11,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 #include <asm/fixmap.h>
@@ -219,6 +220,7 @@
 	}
 	return (__force void __iomem *) (offset + (char *)addr);
 }
+EXPORT_SYMBOL(__ioremap);
 
 /**
  * ioremap_nocache     -   map bus memory into CPU space
@@ -246,6 +248,7 @@
 {
 	return __ioremap(phys_addr, size, _PAGE_PCD);
 }
+EXPORT_SYMBOL(ioremap_nocache);
 
 /**
  * iounmap - Free a IO remapping
@@ -291,3 +294,5 @@
 	BUG_ON(p != o || o == NULL);
 	kfree(p); 
 }
+EXPORT_SYMBOL(iounmap);
+
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
index 3acf60d..b50a7c7 100644
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -2,6 +2,7 @@
 #include <linux/pci.h>
 #include <asm/mpspec.h>
 #include <linux/cpumask.h>
+#include <asm/k8.h>
 
 /*
  * This discovers the pcibus <-> node mapping on AMD K8.
@@ -18,7 +19,6 @@
 #define NR_LDT_BUS_NUMBER_REGISTERS 3
 #define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
 #define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
-#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
 
 /**
  * fill_mp_bus_to_cpumask()
@@ -28,8 +28,7 @@
 __init static int
 fill_mp_bus_to_cpumask(void)
 {
-	struct pci_dev *nb_dev = NULL;
-	int i, j;
+	int i, j, k;
 	u32 ldtbus, nid;
 	static int lbnr[3] = {
 		LDT_BUS_NUMBER_REGISTER_0,
@@ -37,8 +36,9 @@
 		LDT_BUS_NUMBER_REGISTER_2
 	};
 
-	while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
-			PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
+	cache_k8_northbridges();
+	for (k = 0; k < num_k8_northbridges; k++) {
+		struct pci_dev *nb_dev = k8_northbridges[k];
 		pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
 
 		for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 98fac84..3a3a4c6 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -71,7 +71,7 @@
 # Update machine cpu and platform symlinks if something which affects
 # them changed.
 
-$(archinc)/.platform: $(wildcard include/config/arch/*.h) include/config/MARKER
+$(archinc)/.platform: $(wildcard include/config/arch/*.h) include/config/auto.conf
 	@echo '  SYMLINK $(archinc)/xtensa/config -> $(archinc)/xtensa/config-$(CPU)'
 	$(Q)mkdir -p $(archinc)
 	$(Q)mkdir -p $(archinc)/xtensa
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index de19501..c6f471b 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -350,17 +350,6 @@
 }
 
 /*
- * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
- * mapping.
- */
-static __inline__ void
-__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
-		     enum pci_mmap_state mmap_state)
-{
-	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
-}
-
-/*
  * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
  * device mapping.
  */
@@ -399,7 +388,6 @@
 	if (ret < 0)
 		return ret;
 
-	__pci_mmap_set_flags(dev, vma, mmap_state);
 	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
 
 	ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 1ec5df4..3af31ed 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -892,7 +892,7 @@
 }
 
 /*
- * as_can_anticipate indicates weather we should either run arq
+ * as_can_anticipate indicates whether we should either run arq
  * or keep anticipating a better request.
  */
 static int as_can_anticipate(struct as_data *ad, struct as_rq *arq)
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 0603ab2..c04422a 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -2745,7 +2745,7 @@
 		return 0;
 
 	/*
-	 * not contigious
+	 * not contiguous
 	 */
 	if (req->sector + req->nr_sectors != next->sector)
 		return 0;
@@ -3415,7 +3415,7 @@
  *
  * Description:
  *     Ends all I/O on a request. It does not handle partial completions,
- *     unless the driver actually implements this in its completionc callback
+ *     unless the driver actually implements this in its completion callback
  *     through requeueing. Theh actual completion happens out-of-order,
  *     through a softirq handler. The user must have registered a completion
  *     callback through blk_queue_softirq_done().
diff --git a/crypto/Kconfig b/crypto/Kconfig
index c442f2e..ba133d5 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -337,7 +337,7 @@
 
 config CRYPTO_TEST
 	tristate "Testing module"
-	depends on CRYPTO
+	depends on CRYPTO && m
 	help
 	  Quick & dirty crypto test module.
 
diff --git a/crypto/aes.c b/crypto/aes.c
index a501729..a038711 100644
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -248,10 +248,10 @@
     t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t;   \
 }
 
-static int
-aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len, u32 *flags)
 {
-	struct aes_ctx *ctx = ctx_arg;
+	struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 	u32 i, t, u, v, w;
 
@@ -318,9 +318,9 @@
     f_rl(bo, bi, 2, k);     \
     f_rl(bo, bi, 3, k)
 
-static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in)
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	const struct aes_ctx *ctx = ctx_arg;
+	const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *src = (const __le32 *)in;
 	__le32 *dst = (__le32 *)out;
 	u32 b0[4], b1[4];
@@ -373,9 +373,9 @@
     i_rl(bo, bi, 2, k);     \
     i_rl(bo, bi, 3, k)
 
-static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in)
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	const struct aes_ctx *ctx = ctx_arg;
+	const struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *src = (const __le32 *)in;
 	__le32 *dst = (__le32 *)out;
 	u32 b0[4], b1[4];
diff --git a/crypto/anubis.c b/crypto/anubis.c
index 2c796bd..7e2e1a2 100644
--- a/crypto/anubis.c
+++ b/crypto/anubis.c
@@ -460,16 +460,15 @@
 	0xf726ffedU, 0xe89d6f8eU, 0x19a0f089U,
 };
 
-static int anubis_setkey(void *ctx_arg, const u8 *in_key,
+static int anubis_setkey(struct crypto_tfm *tfm, const u8 *in_key,
 			 unsigned int key_len, u32 *flags)
 {
+	struct anubis_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __be32 *key = (const __be32 *)in_key;
 	int N, R, i, r;
 	u32 kappa[ANUBIS_MAX_N];
 	u32 inter[ANUBIS_MAX_N];
 
-	struct anubis_ctx *ctx = ctx_arg;
-
 	switch (key_len)
 	{
 		case 16: case 20: case 24: case 28:
@@ -660,15 +659,15 @@
 		dst[i] = cpu_to_be32(inter[i]);
 }
 
-static void anubis_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+static void anubis_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct anubis_ctx *ctx = ctx_arg;
+	struct anubis_ctx *ctx = crypto_tfm_ctx(tfm);
 	anubis_crypt(ctx->E, dst, src, ctx->R);
 }
 
-static void anubis_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+static void anubis_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct anubis_ctx *ctx = ctx_arg;
+	struct anubis_ctx *ctx = crypto_tfm_ctx(tfm);
 	anubis_crypt(ctx->D, dst, src, ctx->R);
 }
 
diff --git a/crypto/api.c b/crypto/api.c
index 80bba63..c11ec1f 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -188,13 +188,16 @@
 	if (crypto_init_flags(tfm, flags))
 		goto out_free_tfm;
 		
-	if (crypto_init_ops(tfm)) {
-		crypto_exit_ops(tfm);
+	if (crypto_init_ops(tfm))
 		goto out_free_tfm;
-	}
+
+	if (alg->cra_init && alg->cra_init(tfm))
+		goto cra_init_failed;
 
 	goto out;
 
+cra_init_failed:
+	crypto_exit_ops(tfm);
 out_free_tfm:
 	kfree(tfm);
 	tfm = NULL;
@@ -215,6 +218,8 @@
 	alg = tfm->__crt_alg;
 	size = sizeof(*tfm) + alg->cra_ctxsize;
 
+	if (alg->cra_exit)
+		alg->cra_exit(tfm);
 	crypto_exit_ops(tfm);
 	crypto_alg_put(alg);
 	memset(tfm, 0, size);
@@ -224,7 +229,7 @@
 static inline int crypto_set_driver_name(struct crypto_alg *alg)
 {
 	static const char suffix[] = "-generic";
-	char *driver_name = (char *)alg->cra_driver_name;
+	char *driver_name = alg->cra_driver_name;
 	int len;
 
 	if (*driver_name)
@@ -262,13 +267,13 @@
 	down_write(&crypto_alg_sem);
 	
 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
-		if (!strcmp(q->cra_driver_name, alg->cra_driver_name)) {
+		if (q == alg) {
 			ret = -EEXIST;
 			goto out;
 		}
 	}
 	
-	list_add_tail(&alg->cra_list, &crypto_alg_list);
+	list_add(&alg->cra_list, &crypto_alg_list);
 out:	
 	up_write(&crypto_alg_sem);
 	return ret;
diff --git a/crypto/arc4.c b/crypto/arc4.c
index 9efbcaa..5edc6a6 100644
--- a/crypto/arc4.c
+++ b/crypto/arc4.c
@@ -24,9 +24,10 @@
 	u8 x, y;
 };
 
-static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags)
+static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+			unsigned int key_len, u32 *flags)
 {
-	struct arc4_ctx *ctx = ctx_arg;
+	struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
 	int i, j = 0, k = 0;
 
 	ctx->x = 1;
@@ -48,9 +49,9 @@
 	return 0;
 }
 
-static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in)
+static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct arc4_ctx *ctx = ctx_arg;
+	struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	u8 *const S = ctx->S;
 	u8 x = ctx->x;
diff --git a/crypto/blowfish.c b/crypto/blowfish.c
index 7f710b2..490265f 100644
--- a/crypto/blowfish.c
+++ b/crypto/blowfish.c
@@ -349,7 +349,7 @@
 	dst[1] = yl;
 }
 
-static void bf_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void bf_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
 	const __be32 *in_blk = (const __be32 *)src;
 	__be32 *const out_blk = (__be32 *)dst;
@@ -357,17 +357,18 @@
 
 	in32[0] = be32_to_cpu(in_blk[0]);
 	in32[1] = be32_to_cpu(in_blk[1]);
-	encrypt_block(ctx, out32, in32);
+	encrypt_block(crypto_tfm_ctx(tfm), out32, in32);
 	out_blk[0] = cpu_to_be32(out32[0]);
 	out_blk[1] = cpu_to_be32(out32[1]);
 }
 
-static void bf_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void bf_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
+	struct bf_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __be32 *in_blk = (const __be32 *)src;
 	__be32 *const out_blk = (__be32 *)dst;
-	const u32 *P = ((struct bf_ctx *)ctx)->p;
-	const u32 *S = ((struct bf_ctx *)ctx)->s;
+	const u32 *P = ctx->p;
+	const u32 *S = ctx->s;
 	u32 yl = be32_to_cpu(in_blk[0]);
 	u32 yr = be32_to_cpu(in_blk[1]);
 
@@ -398,12 +399,14 @@
 /* 
  * Calculates the blowfish S and P boxes for encryption and decryption.
  */
-static int bf_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int bf_setkey(struct crypto_tfm *tfm, const u8 *key,
+		     unsigned int keylen, u32 *flags)
 {
+	struct bf_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *P = ctx->p;
+	u32 *S = ctx->s;
 	short i, j, count;
 	u32 data[2], temp;
-	u32 *P = ((struct bf_ctx *)ctx)->p;
-	u32 *S = ((struct bf_ctx *)ctx)->s;
 
 	/* Copy the initialization s-boxes */
 	for (i = 0, count = 0; i < 256; i++)
diff --git a/crypto/cast5.c b/crypto/cast5.c
index 8834c85..08eef58 100644
--- a/crypto/cast5.c
+++ b/crypto/cast5.c
@@ -577,9 +577,9 @@
     (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
 
 
-static void cast5_encrypt(void *ctx, u8 * outbuf, const u8 * inbuf)
+static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
 {
-	struct cast5_ctx *c = (struct cast5_ctx *) ctx;
+	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
 	const __be32 *src = (const __be32 *)inbuf;
 	__be32 *dst = (__be32 *)outbuf;
 	u32 l, r, t;
@@ -642,9 +642,9 @@
 	dst[1] = cpu_to_be32(l);
 }
 
-static void cast5_decrypt(void *ctx, u8 * outbuf, const u8 * inbuf)
+static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
 {
-	struct cast5_ctx *c = (struct cast5_ctx *) ctx;
+	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
 	const __be32 *src = (const __be32 *)inbuf;
 	__be32 *dst = (__be32 *)outbuf;
 	u32 l, r, t;
@@ -769,15 +769,15 @@
 }
 
 
-static int
-cast5_setkey(void *ctx, const u8 * key, unsigned key_len, u32 * flags)
+static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key,
+			unsigned key_len, u32 *flags)
 {
+	struct cast5_ctx *c = crypto_tfm_ctx(tfm);
 	int i;
 	u32 x[4];
 	u32 z[4];
 	u32 k[16];
 	__be32 p_key[4];
-	struct cast5_ctx *c = (struct cast5_ctx *) ctx;
 	
 	if (key_len < 5 || key_len > 16) {
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
diff --git a/crypto/cast6.c b/crypto/cast6.c
index 9e28740..08e33bf 100644
--- a/crypto/cast6.c
+++ b/crypto/cast6.c
@@ -381,13 +381,13 @@
 	key[7] ^= F2(key[0], Tr[i % 4][7], Tm[i][7]);
 }
 
-static int
-cast6_setkey(void *ctx, const u8 * in_key, unsigned key_len, u32 * flags)
+static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+			unsigned key_len, u32 *flags)
 {
 	int i;
 	u32 key[8];
 	__be32 p_key[8]; /* padded key */
-	struct cast6_ctx *c = (struct cast6_ctx *) ctx;
+	struct cast6_ctx *c = crypto_tfm_ctx(tfm);
 
 	if (key_len < 16 || key_len > 32 || key_len % 4 != 0) {
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -444,8 +444,9 @@
         block[2] ^= F1(block[3], Kr[0], Km[0]);
 }
 
-static void cast6_encrypt (void * ctx, u8 * outbuf, const u8 * inbuf) {
-	struct cast6_ctx * c = (struct cast6_ctx *)ctx;
+static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+	struct cast6_ctx *c = crypto_tfm_ctx(tfm);
 	const __be32 *src = (const __be32 *)inbuf;
 	__be32 *dst = (__be32 *)outbuf;
 	u32 block[4];
@@ -476,8 +477,8 @@
 	dst[3] = cpu_to_be32(block[3]);
 }	
 
-static void cast6_decrypt (void * ctx, u8 * outbuf, const u8 * inbuf) {
-	struct cast6_ctx * c = (struct cast6_ctx *)ctx;
+static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) {
+	struct cast6_ctx * c = crypto_tfm_ctx(tfm);
 	const __be32 *src = (const __be32 *)inbuf;
 	__be32 *dst = (__be32 *)outbuf;
 	u32 block[4];
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 65bcea0..b899eb9 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -187,7 +187,7 @@
 	void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
 	int bsize = crypto_tfm_alg_blocksize(tfm);
 
-	void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
 	u8 *iv = desc->info;
 	unsigned int done = 0;
 
@@ -195,7 +195,7 @@
 
 	do {
 		xor(iv, src);
-		fn(crypto_tfm_ctx(tfm), dst, iv);
+		fn(tfm, dst, iv);
 		memcpy(iv, dst, bsize);
 
 		src += bsize;
@@ -218,7 +218,7 @@
 	u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1);
 	u8 **dst_p = src == dst ? &buf : &dst;
 
-	void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
 	u8 *iv = desc->info;
 	unsigned int done = 0;
 
@@ -227,7 +227,7 @@
 	do {
 		u8 *tmp_dst = *dst_p;
 
-		fn(crypto_tfm_ctx(tfm), tmp_dst, src);
+		fn(tfm, tmp_dst, src);
 		xor(tmp_dst, iv);
 		memcpy(iv, src, bsize);
 		if (tmp_dst != dst)
@@ -245,13 +245,13 @@
 {
 	struct crypto_tfm *tfm = desc->tfm;
 	int bsize = crypto_tfm_alg_blocksize(tfm);
-	void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn;
 	unsigned int done = 0;
 
 	nbytes -= bsize;
 
 	do {
-		fn(crypto_tfm_ctx(tfm), dst, src);
+		fn(tfm, dst, src);
 
 		src += bsize;
 		dst += bsize;
@@ -268,7 +268,7 @@
 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
 		return -EINVAL;
 	} else
-		return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen,
+		return cia->cia_setkey(tfm, key, keylen,
 		                       &tfm->crt_flags);
 }
 
diff --git a/crypto/compress.c b/crypto/compress.c
index eb36d93..eca182a 100644
--- a/crypto/compress.c
+++ b/crypto/compress.c
@@ -22,8 +22,7 @@
                             const u8 *src, unsigned int slen,
                             u8 *dst, unsigned int *dlen)
 {
-	return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm),
-	                                                 src, slen, dst,
+	return tfm->__crt_alg->cra_compress.coa_compress(tfm, src, slen, dst,
 	                                                 dlen);
 }
 
@@ -31,8 +30,7 @@
                              const u8 *src, unsigned int slen,
                              u8 *dst, unsigned int *dlen)
 {
-	return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm),
-	                                                   src, slen, dst,
+	return tfm->__crt_alg->cra_compress.coa_decompress(tfm, src, slen, dst,
 	                                                   dlen);
 }
 
@@ -43,21 +41,14 @@
 
 int crypto_init_compress_ops(struct crypto_tfm *tfm)
 {
-	int ret = 0;
 	struct compress_tfm *ops = &tfm->crt_compress;
-	
-	ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm));
-	if (ret)
-		goto out;
 
 	ops->cot_compress = crypto_compress;
 	ops->cot_decompress = crypto_decompress;
 	
-out:
-	return ret;
+	return 0;
 }
 
 void crypto_exit_compress_ops(struct crypto_tfm *tfm)
 {
-	tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm));
 }
diff --git a/crypto/crc32c.c b/crypto/crc32c.c
index 9533624..f266012 100644
--- a/crypto/crc32c.c
+++ b/crypto/crc32c.c
@@ -31,9 +31,9 @@
  * crc using table.
  */
 
-static void chksum_init(void *ctx)
+static void chksum_init(struct crypto_tfm *tfm)
 {
-	struct chksum_ctx *mctx = ctx;
+	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 
 	mctx->crc = ~(u32)0;			/* common usage */
 }
@@ -43,10 +43,10 @@
  * If your algorithm starts with ~0, then XOR with ~0 before you set
  * the seed.
  */
-static int chksum_setkey(void *ctx, const u8 *key, unsigned int keylen,
-	                  u32 *flags)
+static int chksum_setkey(struct crypto_tfm *tfm, const u8 *key,
+			 unsigned int keylen, u32 *flags)
 {
-	struct chksum_ctx *mctx = ctx;
+	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 
 	if (keylen != sizeof(mctx->crc)) {
 		if (flags)
@@ -57,9 +57,10 @@
 	return 0;
 }
 
-static void chksum_update(void *ctx, const u8 *data, unsigned int length)
+static void chksum_update(struct crypto_tfm *tfm, const u8 *data,
+			  unsigned int length)
 {
-	struct chksum_ctx *mctx = ctx;
+	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 	u32 mcrc;
 
 	mcrc = crc32c(mctx->crc, data, (size_t)length);
@@ -67,9 +68,9 @@
 	mctx->crc = mcrc;
 }
 
-static void chksum_final(void *ctx, u8 *out)
+static void chksum_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct chksum_ctx *mctx = ctx;
+	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 	u32 mcrc = (mctx->crc ^ ~(u32)0);
 	
 	*(u32 *)out = __le32_to_cpu(mcrc);
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index 3fcf6e8..a0d956b 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -27,8 +27,8 @@
 #define NULL_BLOCK_SIZE		1
 #define NULL_DIGEST_SIZE	0
 
-static int null_compress(void *ctx, const u8 *src, unsigned int slen,
-                         u8 *dst, unsigned int *dlen)
+static int null_compress(struct crypto_tfm *tfm, const u8 *src,
+			 unsigned int slen, u8 *dst, unsigned int *dlen)
 {
 	if (slen > *dlen)
 		return -EINVAL;
@@ -37,20 +37,21 @@
 	return 0;
 }
 
-static void null_init(void *ctx)
+static void null_init(struct crypto_tfm *tfm)
 { }
 
-static void null_update(void *ctx, const u8 *data, unsigned int len)
+static void null_update(struct crypto_tfm *tfm, const u8 *data,
+			unsigned int len)
 { }
 
-static void null_final(void *ctx, u8 *out)
+static void null_final(struct crypto_tfm *tfm, u8 *out)
 { }
 
-static int null_setkey(void *ctx, const u8 *key,
-                       unsigned int keylen, u32 *flags)
+static int null_setkey(struct crypto_tfm *tfm, const u8 *key,
+		       unsigned int keylen, u32 *flags)
 { return 0; }
 
-static void null_crypt(void *ctx, u8 *dst, const u8 *src)
+static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
 	memcpy(dst, src, NULL_BLOCK_SIZE);
 }
diff --git a/crypto/deflate.c b/crypto/deflate.c
index f209368..6588bbf 100644
--- a/crypto/deflate.c
+++ b/crypto/deflate.c
@@ -102,8 +102,9 @@
 	kfree(ctx->decomp_stream.workspace);
 }
 
-static int deflate_init(void *ctx)
+static int deflate_init(struct crypto_tfm *tfm)
 {
+	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
 	int ret;
 	
 	ret = deflate_comp_init(ctx);
@@ -116,17 +117,19 @@
 	return ret;
 }
 
-static void deflate_exit(void *ctx)
+static void deflate_exit(struct crypto_tfm *tfm)
 {
+	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
+
 	deflate_comp_exit(ctx);
 	deflate_decomp_exit(ctx);
 }
 
-static int deflate_compress(void *ctx, const u8 *src, unsigned int slen,
-	                    u8 *dst, unsigned int *dlen)
+static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
+			    unsigned int slen, u8 *dst, unsigned int *dlen)
 {
 	int ret = 0;
-	struct deflate_ctx *dctx = ctx;
+	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
 	struct z_stream_s *stream = &dctx->comp_stream;
 
 	ret = zlib_deflateReset(stream);
@@ -151,12 +154,12 @@
 	return ret;
 }
  
-static int deflate_decompress(void *ctx, const u8 *src, unsigned int slen,
-                              u8 *dst, unsigned int *dlen)
+static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
+			      unsigned int slen, u8 *dst, unsigned int *dlen)
 {
 	
 	int ret = 0;
-	struct deflate_ctx *dctx = ctx;
+	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
 	struct z_stream_s *stream = &dctx->decomp_stream;
 
 	ret = zlib_inflateReset(stream);
@@ -198,9 +201,9 @@
 	.cra_ctxsize		= sizeof(struct deflate_ctx),
 	.cra_module		= THIS_MODULE,
 	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
+	.cra_init		= deflate_init,
+	.cra_exit		= deflate_exit,
 	.cra_u			= { .compress = {
-	.coa_init		= deflate_init,
-	.coa_exit		= deflate_exit,
 	.coa_compress 		= deflate_compress,
 	.coa_decompress  	= deflate_decompress } }
 };
diff --git a/crypto/des.c b/crypto/des.c
index 2d74cab..a9d3c23 100644
--- a/crypto/des.c
+++ b/crypto/des.c
@@ -783,9 +783,10 @@
 	}
 }
 
-static int des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
+		      unsigned int keylen, u32 *flags)
 {
-	struct des_ctx *dctx = ctx;
+	struct des_ctx *dctx = crypto_tfm_ctx(tfm);
 	u32 tmp[DES_EXPKEY_WORDS];
 	int ret;
 
@@ -803,9 +804,10 @@
 	return 0;
 }
 
-static void des_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	const u32 *K = ((struct des_ctx *)ctx)->expkey;
+	struct des_ctx *ctx = crypto_tfm_ctx(tfm);
+	const u32 *K = ctx->expkey;
 	const __le32 *s = (const __le32 *)src;
 	__le32 *d = (__le32 *)dst;
 	u32 L, R, A, B;
@@ -825,9 +827,10 @@
 	d[1] = cpu_to_le32(L);
 }
 
-static void des_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	const u32 *K = ((struct des_ctx *)ctx)->expkey + DES_EXPKEY_WORDS - 2;
+	struct des_ctx *ctx = crypto_tfm_ctx(tfm);
+	const u32 *K = ctx->expkey + DES_EXPKEY_WORDS - 2;
 	const __le32 *s = (const __le32 *)src;
 	__le32 *d = (__le32 *)dst;
 	u32 L, R, A, B;
@@ -860,11 +863,11 @@
  *   property.
  *
  */
-static int des3_ede_setkey(void *ctx, const u8 *key,
+static int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key,
 			   unsigned int keylen, u32 *flags)
 {
 	const u32 *K = (const u32 *)key;
-	struct des3_ede_ctx *dctx = ctx;
+	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
 	u32 *expkey = dctx->expkey;
 
 	if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
@@ -881,9 +884,9 @@
 	return 0;
 }
 
-static void des3_ede_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_ede_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct des3_ede_ctx *dctx = ctx;
+	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
 	const u32 *K = dctx->expkey;
 	const __le32 *s = (const __le32 *)src;
 	__le32 *d = (__le32 *)dst;
@@ -912,9 +915,9 @@
 	d[1] = cpu_to_le32(L);
 }
 
-static void des3_ede_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct des3_ede_ctx *dctx = ctx;
+	struct des3_ede_ctx *dctx = crypto_tfm_ctx(tfm);
 	const u32 *K = dctx->expkey + DES3_EDE_EXPKEY_WORDS - 2;
 	const __le32 *s = (const __le32 *)src;
 	__le32 *d = (__le32 *)dst;
diff --git a/crypto/digest.c b/crypto/digest.c
index d9b6ac9..603006a 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -20,13 +20,14 @@
 
 static void init(struct crypto_tfm *tfm)
 {
-	tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm));
+	tfm->__crt_alg->cra_digest.dia_init(tfm);
 }
 
 static void update(struct crypto_tfm *tfm,
                    struct scatterlist *sg, unsigned int nsg)
 {
 	unsigned int i;
+	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
 
 	for (i = 0; i < nsg; i++) {
 
@@ -38,12 +39,22 @@
 			unsigned int bytes_from_page = min(l, ((unsigned int)
 							   (PAGE_SIZE)) - 
 							   offset);
-			char *p = crypto_kmap(pg, 0) + offset;
+			char *src = crypto_kmap(pg, 0);
+			char *p = src + offset;
 
-			tfm->__crt_alg->cra_digest.dia_update
-					(crypto_tfm_ctx(tfm), p,
-					 bytes_from_page);
-			crypto_kunmap(p, 0);
+			if (unlikely(offset & alignmask)) {
+				unsigned int bytes =
+					alignmask + 1 - (offset & alignmask);
+				bytes = min(bytes, bytes_from_page);
+				tfm->__crt_alg->cra_digest.dia_update(tfm, p,
+								      bytes);
+				p += bytes;
+				bytes_from_page -= bytes;
+				l -= bytes;
+			}
+			tfm->__crt_alg->cra_digest.dia_update(tfm, p,
+							      bytes_from_page);
+			crypto_kunmap(src, 0);
 			crypto_yield(tfm);
 			offset = 0;
 			pg++;
@@ -54,7 +65,15 @@
 
 static void final(struct crypto_tfm *tfm, u8 *out)
 {
-	tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out);
+	unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+	if (unlikely((unsigned long)out & alignmask)) {
+		unsigned int size = crypto_tfm_alg_digestsize(tfm);
+		u8 buffer[size + alignmask];
+		u8 *dst = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+		tfm->__crt_alg->cra_digest.dia_final(tfm, dst);
+		memcpy(out, dst, size);
+	} else
+		tfm->__crt_alg->cra_digest.dia_final(tfm, out);
 }
 
 static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
@@ -62,25 +81,15 @@
 	u32 flags;
 	if (tfm->__crt_alg->cra_digest.dia_setkey == NULL)
 		return -ENOSYS;
-	return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm),
-						     key, keylen, &flags);
+	return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen, &flags);
 }
 
 static void digest(struct crypto_tfm *tfm,
                    struct scatterlist *sg, unsigned int nsg, u8 *out)
 {
-	unsigned int i;
-
-	tfm->crt_digest.dit_init(tfm);
-		
-	for (i = 0; i < nsg; i++) {
-		char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset;
-		tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm),
-		                                      p, sg[i].length);
-		crypto_kunmap(p, 0);
-		crypto_yield(tfm);
-	}
-	crypto_digest_final(tfm, out);
+	init(tfm);
+	update(tfm, sg, nsg);
+	final(tfm, out);
 }
 
 int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
diff --git a/crypto/khazad.c b/crypto/khazad.c
index 807f2bf..d4c9d36 100644
--- a/crypto/khazad.c
+++ b/crypto/khazad.c
@@ -754,11 +754,11 @@
 	0xccc41d14c363da5dULL, 0x5fdc7dcd7f5a6c5cULL, 0xf726ffede89d6f8eULL
 };
 
-static int khazad_setkey(void *ctx_arg, const u8 *in_key,
-                       unsigned int key_len, u32 *flags)
+static int khazad_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+			 unsigned int key_len, u32 *flags)
 {
-	struct khazad_ctx *ctx = ctx_arg;
-	const __be64 *key = (const __be64 *)in_key;
+	struct khazad_ctx *ctx = crypto_tfm_ctx(tfm);
+	const __be32 *key = (const __be32 *)in_key;
 	int r;
 	const u64 *S = T7;
 	u64 K2, K1;
@@ -769,8 +769,9 @@
 		return -EINVAL;
 	}
 
-	K2 = be64_to_cpu(key[0]);
-	K1 = be64_to_cpu(key[1]);
+	/* key is supposed to be 32-bit aligned */
+	K2 = ((u64)be32_to_cpu(key[0]) << 32) | be32_to_cpu(key[1]);
+	K1 = ((u64)be32_to_cpu(key[2]) << 32) | be32_to_cpu(key[3]);
 
 	/* setup the encrypt key */
 	for (r = 0; r <= KHAZAD_ROUNDS; r++) {
@@ -840,15 +841,15 @@
 	*dst = cpu_to_be64(state);
 }
 
-static void khazad_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+static void khazad_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct khazad_ctx *ctx = ctx_arg;
+	struct khazad_ctx *ctx = crypto_tfm_ctx(tfm);
 	khazad_crypt(ctx->E, dst, src);
 }
 
-static void khazad_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+static void khazad_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
-	struct khazad_ctx *ctx = ctx_arg;
+	struct khazad_ctx *ctx = crypto_tfm_ctx(tfm);
 	khazad_crypt(ctx->D, dst, src);
 }
 
diff --git a/crypto/md4.c b/crypto/md4.c
index a2d6df5..c1bc71b 100644
--- a/crypto/md4.c
+++ b/crypto/md4.c
@@ -152,9 +152,9 @@
 	md4_transform(ctx->hash, ctx->block);
 }
 
-static void md4_init(void *ctx)
+static void md4_init(struct crypto_tfm *tfm)
 {
-	struct md4_ctx *mctx = ctx;
+	struct md4_ctx *mctx = crypto_tfm_ctx(tfm);
 
 	mctx->hash[0] = 0x67452301;
 	mctx->hash[1] = 0xefcdab89;
@@ -163,9 +163,9 @@
 	mctx->byte_count = 0;
 }
 
-static void md4_update(void *ctx, const u8 *data, unsigned int len)
+static void md4_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
 {
-	struct md4_ctx *mctx = ctx;
+	struct md4_ctx *mctx = crypto_tfm_ctx(tfm);
 	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
 
 	mctx->byte_count += len;
@@ -193,9 +193,9 @@
 	memcpy(mctx->block, data, len);
 }
 
-static void md4_final(void *ctx, u8 *out)
+static void md4_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct md4_ctx *mctx = ctx;
+	struct md4_ctx *mctx = crypto_tfm_ctx(tfm);
 	const unsigned int offset = mctx->byte_count & 0x3f;
 	char *p = (char *)mctx->block + offset;
 	int padding = 56 - (offset + 1);
diff --git a/crypto/md5.c b/crypto/md5.c
index 7f041ae..93d18e8 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -147,9 +147,9 @@
 	md5_transform(ctx->hash, ctx->block);
 }
 
-static void md5_init(void *ctx)
+static void md5_init(struct crypto_tfm *tfm)
 {
-	struct md5_ctx *mctx = ctx;
+	struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
 
 	mctx->hash[0] = 0x67452301;
 	mctx->hash[1] = 0xefcdab89;
@@ -158,9 +158,9 @@
 	mctx->byte_count = 0;
 }
 
-static void md5_update(void *ctx, const u8 *data, unsigned int len)
+static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
 {
-	struct md5_ctx *mctx = ctx;
+	struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
 	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
 
 	mctx->byte_count += len;
@@ -188,9 +188,9 @@
 	memcpy(mctx->block, data, len);
 }
 
-static void md5_final(void *ctx, u8 *out)
+static void md5_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct md5_ctx *mctx = ctx;
+	struct md5_ctx *mctx = crypto_tfm_ctx(tfm);
 	const unsigned int offset = mctx->byte_count & 0x3f;
 	char *p = (char *)mctx->block + offset;
 	int padding = 56 - (offset + 1);
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
index 4f6ab23..d061da2 100644
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -45,16 +45,17 @@
 } while (0)
 
 
-static void michael_init(void *ctx)
+static void michael_init(struct crypto_tfm *tfm)
 {
-	struct michael_mic_ctx *mctx = ctx;
+	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
 	mctx->pending_len = 0;
 }
 
 
-static void michael_update(void *ctx, const u8 *data, unsigned int len)
+static void michael_update(struct crypto_tfm *tfm, const u8 *data,
+			   unsigned int len)
 {
-	struct michael_mic_ctx *mctx = ctx;
+	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
 	const __le32 *src;
 
 	if (mctx->pending_len) {
@@ -90,9 +91,9 @@
 }
 
 
-static void michael_final(void *ctx, u8 *out)
+static void michael_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct michael_mic_ctx *mctx = ctx;
+	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
 	u8 *data = mctx->pending;
 	__le32 *dst = (__le32 *)out;
 
@@ -121,10 +122,10 @@
 }
 
 
-static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen,
-			  u32 *flags)
+static int michael_setkey(struct crypto_tfm *tfm, const u8 *key,
+			  unsigned int keylen, u32 *flags)
 {
-	struct michael_mic_ctx *mctx = ctx;
+	struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
 	const __le32 *data = (const __le32 *)key;
 
 	if (keylen != 8) {
@@ -145,6 +146,7 @@
 	.cra_blocksize	= 8,
 	.cra_ctxsize	= sizeof(struct michael_mic_ctx),
 	.cra_module	= THIS_MODULE,
+	.cra_alignmask	= 3,
 	.cra_list	= LIST_HEAD_INIT(michael_mic_alg.cra_list),
 	.cra_u		= { .digest = {
 	.dia_digestsize	= 8,
diff --git a/crypto/serpent.c b/crypto/serpent.c
index e366406..de60cdd 100644
--- a/crypto/serpent.c
+++ b/crypto/serpent.c
@@ -215,9 +215,11 @@
 };
 
 
-static int serpent_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+			  unsigned int keylen, u32 *flags)
 {
-	u32 *k = ((struct serpent_ctx *)ctx)->expkey;
+	struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+	u32 *k = ctx->expkey;
 	u8  *k8 = (u8 *)k;
 	u32 r0,r1,r2,r3,r4;
 	int i;
@@ -365,10 +367,11 @@
 	return 0;
 }
 
-static void serpent_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void serpent_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
+	struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
 	const u32
-		*k = ((struct serpent_ctx *)ctx)->expkey,
+		*k = ctx->expkey,
 		*s = (const u32 *)src;
 	u32	*d = (u32 *)dst,
 		r0, r1, r2, r3, r4;
@@ -423,8 +426,9 @@
 	d[3] = cpu_to_le32(r3);
 }
 
-static void serpent_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
+	struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
 	const u32
 		*k = ((struct serpent_ctx *)ctx)->expkey,
 		*s = (const u32 *)src;
@@ -492,7 +496,8 @@
 	.cia_decrypt  		=	serpent_decrypt } }
 };
 
-static int tnepres_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key,
+			  unsigned int keylen, u32 *flags)
 {
 	u8 rev_key[SERPENT_MAX_KEY_SIZE];
 	int i;
@@ -506,10 +511,10 @@
 	for (i = 0; i < keylen; ++i)
 		rev_key[keylen - i - 1] = key[i];
  
-	return serpent_setkey(ctx, rev_key, keylen, flags);
+	return serpent_setkey(tfm, rev_key, keylen, flags);
 }
 
-static void tnepres_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void tnepres_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
 	const u32 * const s = (const u32 * const)src;
 	u32 * const d = (u32 * const)dst;
@@ -521,7 +526,7 @@
 	rs[2] = swab32(s[1]);
 	rs[3] = swab32(s[0]);
 
-	serpent_encrypt(ctx, (u8 *)rd, (u8 *)rs);
+	serpent_encrypt(tfm, (u8 *)rd, (u8 *)rs);
 
 	d[0] = swab32(rd[3]);
 	d[1] = swab32(rd[2]);
@@ -529,7 +534,7 @@
 	d[3] = swab32(rd[0]);
 }
 
-static void tnepres_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
 	const u32 * const s = (const u32 * const)src;
 	u32 * const d = (u32 * const)dst;
@@ -541,7 +546,7 @@
 	rs[2] = swab32(s[1]);
 	rs[3] = swab32(s[0]);
 
-	serpent_decrypt(ctx, (u8 *)rd, (u8 *)rs);
+	serpent_decrypt(tfm, (u8 *)rd, (u8 *)rs);
 
 	d[0] = swab32(rd[3]);
 	d[1] = swab32(rd[2]);
diff --git a/crypto/sha1.c b/crypto/sha1.c
index 21571ed3..6c77b68 100644
--- a/crypto/sha1.c
+++ b/crypto/sha1.c
@@ -34,9 +34,9 @@
         u8 buffer[64];
 };
 
-static void sha1_init(void *ctx)
+static void sha1_init(struct crypto_tfm *tfm)
 {
-	struct sha1_ctx *sctx = ctx;
+	struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 	static const struct sha1_ctx initstate = {
 	  0,
 	  { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 },
@@ -46,9 +46,10 @@
 	*sctx = initstate;
 }
 
-static void sha1_update(void *ctx, const u8 *data, unsigned int len)
+static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
+			unsigned int len)
 {
-	struct sha1_ctx *sctx = ctx;
+	struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 	unsigned int partial, done;
 	const u8 *src;
 
@@ -80,9 +81,9 @@
 
 
 /* Add padding and return the message digest. */
-static void sha1_final(void* ctx, u8 *out)
+static void sha1_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct sha1_ctx *sctx = ctx;
+	struct sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 	__be32 *dst = (__be32 *)out;
 	u32 i, index, padlen;
 	__be64 bits;
@@ -93,10 +94,10 @@
 	/* Pad out to 56 mod 64 */
 	index = sctx->count & 0x3f;
 	padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-	sha1_update(sctx, padding, padlen);
+	sha1_update(tfm, padding, padlen);
 
 	/* Append length */
-	sha1_update(sctx, (const u8 *)&bits, sizeof(bits));
+	sha1_update(tfm, (const u8 *)&bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 5; i++)
@@ -112,6 +113,7 @@
 	.cra_blocksize	=	SHA1_HMAC_BLOCK_SIZE,
 	.cra_ctxsize	=	sizeof(struct sha1_ctx),
 	.cra_module	=	THIS_MODULE,
+	.cra_alignmask	=	3,
 	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
 	.cra_u		=	{ .digest = {
 	.dia_digestsize	=	SHA1_DIGEST_SIZE,
diff --git a/crypto/sha256.c b/crypto/sha256.c
index 9d5ef67..bc71d85 100644
--- a/crypto/sha256.c
+++ b/crypto/sha256.c
@@ -230,9 +230,9 @@
 	memset(W, 0, 64 * sizeof(u32));
 }
 
-static void sha256_init(void *ctx)
+static void sha256_init(struct crypto_tfm *tfm)
 {
-	struct sha256_ctx *sctx = ctx;
+	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 	sctx->state[0] = H0;
 	sctx->state[1] = H1;
 	sctx->state[2] = H2;
@@ -242,12 +242,12 @@
 	sctx->state[6] = H6;
 	sctx->state[7] = H7;
 	sctx->count[0] = sctx->count[1] = 0;
-	memset(sctx->buf, 0, sizeof(sctx->buf));
 }
 
-static void sha256_update(void *ctx, const u8 *data, unsigned int len)
+static void sha256_update(struct crypto_tfm *tfm, const u8 *data,
+			  unsigned int len)
 {
-	struct sha256_ctx *sctx = ctx;
+	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 	unsigned int i, index, part_len;
 
 	/* Compute number of bytes mod 128 */
@@ -277,9 +277,9 @@
 	memcpy(&sctx->buf[index], &data[i], len-i);
 }
 
-static void sha256_final(void* ctx, u8 *out)
+static void sha256_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct sha256_ctx *sctx = ctx;
+	struct sha256_ctx *sctx = crypto_tfm_ctx(tfm);
 	__be32 *dst = (__be32 *)out;
 	__be32 bits[2];
 	unsigned int index, pad_len;
@@ -293,10 +293,10 @@
 	/* Pad out to 56 mod 64. */
 	index = (sctx->count[0] >> 3) & 0x3f;
 	pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
-	sha256_update(sctx, padding, pad_len);
+	sha256_update(tfm, padding, pad_len);
 
 	/* Append length (before padding) */
-	sha256_update(sctx, (const u8 *)bits, sizeof(bits));
+	sha256_update(tfm, (const u8 *)bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 8; i++)
@@ -313,6 +313,7 @@
 	.cra_blocksize	=	SHA256_HMAC_BLOCK_SIZE,
 	.cra_ctxsize	=	sizeof(struct sha256_ctx),
 	.cra_module	=	THIS_MODULE,
+	.cra_alignmask	=	3,
 	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
 	.cra_u		=	{ .digest = {
 	.dia_digestsize	=	SHA256_DIGEST_SIZE,
diff --git a/crypto/sha512.c b/crypto/sha512.c
index 3e6e939..2dfe7f1 100644
--- a/crypto/sha512.c
+++ b/crypto/sha512.c
@@ -161,9 +161,9 @@
 }
 
 static void
-sha512_init(void *ctx)
+sha512_init(struct crypto_tfm *tfm)
 {
-        struct sha512_ctx *sctx = ctx;
+	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
 	sctx->state[0] = H0;
 	sctx->state[1] = H1;
 	sctx->state[2] = H2;
@@ -173,13 +173,12 @@
 	sctx->state[6] = H6;
 	sctx->state[7] = H7;
 	sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
-	memset(sctx->buf, 0, sizeof(sctx->buf));
 }
 
 static void
-sha384_init(void *ctx)
+sha384_init(struct crypto_tfm *tfm)
 {
-        struct sha512_ctx *sctx = ctx;
+	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
         sctx->state[0] = HP0;
         sctx->state[1] = HP1;
         sctx->state[2] = HP2;
@@ -189,13 +188,12 @@
         sctx->state[6] = HP6;
         sctx->state[7] = HP7;
         sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
-        memset(sctx->buf, 0, sizeof(sctx->buf));
 }
 
 static void
-sha512_update(void *ctx, const u8 *data, unsigned int len)
+sha512_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len)
 {
-        struct sha512_ctx *sctx = ctx;
+	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
 
 	unsigned int i, index, part_len;
 
@@ -233,9 +231,9 @@
 }
 
 static void
-sha512_final(void *ctx, u8 *hash)
+sha512_final(struct crypto_tfm *tfm, u8 *hash)
 {
-        struct sha512_ctx *sctx = ctx;
+	struct sha512_ctx *sctx = crypto_tfm_ctx(tfm);
         static u8 padding[128] = { 0x80, };
 	__be64 *dst = (__be64 *)hash;
 	__be32 bits[4];
@@ -251,10 +249,10 @@
 	/* Pad out to 112 mod 128. */
 	index = (sctx->count[0] >> 3) & 0x7f;
 	pad_len = (index < 112) ? (112 - index) : ((128+112) - index);
-	sha512_update(sctx, padding, pad_len);
+	sha512_update(tfm, padding, pad_len);
 
 	/* Append length (before padding) */
-	sha512_update(sctx, (const u8 *)bits, sizeof(bits));
+	sha512_update(tfm, (const u8 *)bits, sizeof(bits));
 
 	/* Store state in digest */
 	for (i = 0; i < 8; i++)
@@ -264,12 +262,11 @@
 	memset(sctx, 0, sizeof(struct sha512_ctx));
 }
 
-static void sha384_final(void *ctx, u8 *hash)
+static void sha384_final(struct crypto_tfm *tfm, u8 *hash)
 {
-        struct sha512_ctx *sctx = ctx;
         u8 D[64];
 
-        sha512_final(sctx, D);
+	sha512_final(tfm, D);
 
         memcpy(hash, D, 48);
         memset(D, 0, 64);
@@ -281,6 +278,7 @@
         .cra_blocksize  = SHA512_HMAC_BLOCK_SIZE,
         .cra_ctxsize    = sizeof(struct sha512_ctx),
         .cra_module     = THIS_MODULE,
+	.cra_alignmask	= 3,
         .cra_list       = LIST_HEAD_INIT(sha512.cra_list),
         .cra_u          = { .digest = {
                                 .dia_digestsize = SHA512_DIGEST_SIZE,
@@ -295,6 +293,7 @@
         .cra_flags      = CRYPTO_ALG_TYPE_DIGEST,
         .cra_blocksize  = SHA384_HMAC_BLOCK_SIZE,
         .cra_ctxsize    = sizeof(struct sha512_ctx),
+	.cra_alignmask	= 3,
         .cra_module     = THIS_MODULE,
         .cra_list       = LIST_HEAD_INIT(sha384.cra_list),
         .cra_u          = { .digest = {
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 49e344f..e52f56c 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -570,6 +570,122 @@
 	crypto_free_tfm(tfm);
 }
 
+static void test_digest_jiffies(struct crypto_tfm *tfm, char *p, int blen,
+				int plen, char *out, int sec)
+{
+	struct scatterlist sg[1];
+	unsigned long start, end;
+	int bcount, pcount;
+
+	for (start = jiffies, end = start + sec * HZ, bcount = 0;
+	     time_before(jiffies, end); bcount++) {
+		crypto_digest_init(tfm);
+		for (pcount = 0; pcount < blen; pcount += plen) {
+			sg_set_buf(sg, p + pcount, plen);
+			crypto_digest_update(tfm, sg, 1);
+		}
+		/* we assume there is enough space in 'out' for the result */
+		crypto_digest_final(tfm, out);
+	}
+
+	printk("%6u opers/sec, %9lu bytes/sec\n",
+	       bcount / sec, ((long)bcount * blen) / sec);
+
+	return;
+}
+
+static void test_digest_cycles(struct crypto_tfm *tfm, char *p, int blen,
+			       int plen, char *out)
+{
+	struct scatterlist sg[1];
+	unsigned long cycles = 0;
+	int i, pcount;
+
+	local_bh_disable();
+	local_irq_disable();
+
+	/* Warm-up run. */
+	for (i = 0; i < 4; i++) {
+		crypto_digest_init(tfm);
+		for (pcount = 0; pcount < blen; pcount += plen) {
+			sg_set_buf(sg, p + pcount, plen);
+			crypto_digest_update(tfm, sg, 1);
+		}
+		crypto_digest_final(tfm, out);
+	}
+
+	/* The real thing. */
+	for (i = 0; i < 8; i++) {
+		cycles_t start, end;
+
+		crypto_digest_init(tfm);
+
+		start = get_cycles();
+
+		for (pcount = 0; pcount < blen; pcount += plen) {
+			sg_set_buf(sg, p + pcount, plen);
+			crypto_digest_update(tfm, sg, 1);
+		}
+		crypto_digest_final(tfm, out);
+
+		end = get_cycles();
+
+		cycles += end - start;
+	}
+
+	local_irq_enable();
+	local_bh_enable();
+
+	printk("%6lu cycles/operation, %4lu cycles/byte\n",
+	       cycles / 8, cycles / (8 * blen));
+
+	return;
+}
+
+static void test_digest_speed(char *algo, unsigned int sec,
+			      struct digest_speed *speed)
+{
+	struct crypto_tfm *tfm;
+	char output[1024];
+	int i;
+
+	printk("\ntesting speed of %s\n", algo);
+
+	tfm = crypto_alloc_tfm(algo, 0);
+
+	if (tfm == NULL) {
+		printk("failed to load transform for %s\n", algo);
+		return;
+	}
+
+	if (crypto_tfm_alg_digestsize(tfm) > sizeof(output)) {
+		printk("digestsize(%u) > outputbuffer(%zu)\n",
+		       crypto_tfm_alg_digestsize(tfm), sizeof(output));
+		goto out;
+	}
+
+	for (i = 0; speed[i].blen != 0; i++) {
+		if (speed[i].blen > TVMEMSIZE) {
+			printk("template (%u) too big for tvmem (%u)\n",
+			       speed[i].blen, TVMEMSIZE);
+			goto out;
+		}
+
+		printk("test%3u (%5u byte blocks,%5u bytes per update,%4u updates): ",
+		       i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen);
+
+		memset(tvmem, 0xff, speed[i].blen);
+
+		if (sec)
+			test_digest_jiffies(tfm, tvmem, speed[i].blen, speed[i].plen, output, sec);
+		else
+			test_digest_cycles(tfm, tvmem, speed[i].blen, speed[i].plen, output);
+	}
+
+out:
+	crypto_free_tfm(tfm);
+}
+
 static void test_deflate(void)
 {
 	unsigned int i;
@@ -1086,6 +1202,60 @@
 				  des_speed_template);
 		break;
 
+	case 300:
+		/* fall through */
+
+	case 301:
+		test_digest_speed("md4", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 302:
+		test_digest_speed("md5", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 303:
+		test_digest_speed("sha1", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 304:
+		test_digest_speed("sha256", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 305:
+		test_digest_speed("sha384", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 306:
+		test_digest_speed("sha512", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 307:
+		test_digest_speed("wp256", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 308:
+		test_digest_speed("wp384", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 309:
+		test_digest_speed("wp512", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 310:
+		test_digest_speed("tgr128", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 311:
+		test_digest_speed("tgr160", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 312:
+		test_digest_speed("tgr192", sec, generic_digest_speed_template);
+		if (mode > 300 && mode < 400) break;
+
+	case 399:
+		break;
+
 	case 1000:
 		test_available();
 		break;
@@ -1113,7 +1283,14 @@
 
 	kfree(xbuf);
 	kfree(tvmem);
-	return 0;
+
+	/* We intentionaly return -EAGAIN to prevent keeping
+	 * the module. It does all its work from init()
+	 * and doesn't offer any runtime functionality 
+	 * => we don't need it in the memory, do we?
+	 *                                        -- mludvig
+	 */
+	return -EAGAIN;
 }
 
 /*
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 1f683ba..1fac560 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -65,6 +65,11 @@
 	unsigned int blen;
 };
 
+struct digest_speed {
+	unsigned int blen;	/* buffer length */
+	unsigned int plen;	/* per-update length */
+};
+
 /*
  * MD4 test vectors from RFC1320
  */
@@ -2975,4 +2980,35 @@
 	{  .klen = 0, .blen = 0, }
 };
 
+/*
+ * Digest speed tests
+ */
+static struct digest_speed generic_digest_speed_template[] = {
+	{ .blen = 16, 	.plen = 16, },
+	{ .blen = 64,	.plen = 16, },
+	{ .blen = 64,	.plen = 64, },
+	{ .blen = 256,	.plen = 16, },
+	{ .blen = 256,	.plen = 64, },
+	{ .blen = 256,	.plen = 256, },
+	{ .blen = 1024,	.plen = 16, },
+	{ .blen = 1024,	.plen = 256, },
+	{ .blen = 1024,	.plen = 1024, },
+	{ .blen = 2048,	.plen = 16, },
+	{ .blen = 2048,	.plen = 256, },
+	{ .blen = 2048,	.plen = 1024, },
+	{ .blen = 2048,	.plen = 2048, },
+	{ .blen = 4096,	.plen = 16, },
+	{ .blen = 4096,	.plen = 256, },
+	{ .blen = 4096,	.plen = 1024, },
+	{ .blen = 4096,	.plen = 4096, },
+	{ .blen = 8192,	.plen = 16, },
+	{ .blen = 8192,	.plen = 256, },
+	{ .blen = 8192,	.plen = 1024, },
+	{ .blen = 8192,	.plen = 4096, },
+	{ .blen = 8192,	.plen = 8192, },
+
+	/* End marker */
+	{  .blen = 0,	.plen = 0, }
+};
+
 #endif	/* _CRYPTO_TCRYPT_H */
diff --git a/crypto/tea.c b/crypto/tea.c
index a6a02b3..5367adc 100644
--- a/crypto/tea.c
+++ b/crypto/tea.c
@@ -45,10 +45,10 @@
 	u32 KEY[4];
 };
 
-static int tea_setkey(void *ctx_arg, const u8 *in_key,
-                       unsigned int key_len, u32 *flags)
-{ 
-	struct tea_ctx *ctx = ctx_arg;
+static int tea_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+		      unsigned int key_len, u32 *flags)
+{
+	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 	
 	if (key_len != 16)
@@ -66,12 +66,11 @@
 
 }
 
-static void tea_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
-{ 
+static void tea_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
 	u32 y, z, n, sum = 0;
 	u32 k0, k1, k2, k3;
-
-	struct tea_ctx *ctx = ctx_arg;
+	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *in = (const __le32 *)src;
 	__le32 *out = (__le32 *)dst;
 
@@ -95,11 +94,11 @@
 	out[1] = cpu_to_le32(z);
 }
 
-static void tea_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
-{ 
+static void tea_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
 	u32 y, z, n, sum;
 	u32 k0, k1, k2, k3;
-	struct tea_ctx *ctx = ctx_arg;
+	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *in = (const __le32 *)src;
 	__le32 *out = (__le32 *)dst;
 
@@ -125,10 +124,10 @@
 	out[1] = cpu_to_le32(z);
 }
 
-static int xtea_setkey(void *ctx_arg, const u8 *in_key,
-                       unsigned int key_len, u32 *flags)
-{ 
-	struct xtea_ctx *ctx = ctx_arg;
+static int xtea_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len, u32 *flags)
+{
+	struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 	
 	if (key_len != 16)
@@ -146,12 +145,11 @@
 
 }
 
-static void xtea_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
-{ 
+static void xtea_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
 	u32 y, z, sum = 0;
 	u32 limit = XTEA_DELTA * XTEA_ROUNDS;
-
-	struct xtea_ctx *ctx = ctx_arg;
+	struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *in = (const __le32 *)src;
 	__le32 *out = (__le32 *)dst;
 
@@ -168,10 +166,10 @@
 	out[1] = cpu_to_le32(z);
 }
 
-static void xtea_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
-{ 
+static void xtea_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
 	u32 y, z, sum;
-	struct tea_ctx *ctx = ctx_arg;
+	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *in = (const __le32 *)src;
 	__le32 *out = (__le32 *)dst;
 
@@ -191,12 +189,11 @@
 }
 
 
-static void xeta_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
-{ 
+static void xeta_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
 	u32 y, z, sum = 0;
 	u32 limit = XTEA_DELTA * XTEA_ROUNDS;
-
-	struct xtea_ctx *ctx = ctx_arg;
+	struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *in = (const __le32 *)src;
 	__le32 *out = (__le32 *)dst;
 
@@ -213,10 +210,10 @@
 	out[1] = cpu_to_le32(z);
 }
 
-static void xeta_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
-{ 
+static void xeta_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
 	u32 y, z, sum;
-	struct tea_ctx *ctx = ctx_arg;
+	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *in = (const __le32 *)src;
 	__le32 *out = (__le32 *)dst;
 
diff --git a/crypto/tgr192.c b/crypto/tgr192.c
index 2d8e44f..a0fadf3 100644
--- a/crypto/tgr192.c
+++ b/crypto/tgr192.c
@@ -496,11 +496,10 @@
 	tctx->c = c;
 }
 
-static void tgr192_init(void *ctx)
+static void tgr192_init(struct crypto_tfm *tfm)
 {
-	struct tgr192_ctx *tctx = ctx;
+	struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm);
 
-	memset (tctx->hash, 0, 64);
 	tctx->a = 0x0123456789abcdefULL;
 	tctx->b = 0xfedcba9876543210ULL;
 	tctx->c = 0xf096a5b4c3b2e187ULL;
@@ -511,9 +510,10 @@
 
 /* Update the message digest with the contents
  * of INBUF with length INLEN. */
-static void tgr192_update(void *ctx, const u8 * inbuf, unsigned int len)
+static void tgr192_update(struct crypto_tfm *tfm, const u8 *inbuf,
+			  unsigned int len)
 {
-	struct tgr192_ctx *tctx = ctx;
+	struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm);
 
 	if (tctx->count == 64) {	/* flush the buffer */
 		tgr192_transform(tctx, tctx->hash);
@@ -527,7 +527,7 @@
 		for (; len && tctx->count < 64; len--) {
 			tctx->hash[tctx->count++] = *inbuf++;
 		}
-		tgr192_update(tctx, NULL, 0);
+		tgr192_update(tfm, NULL, 0);
 		if (!len) {
 			return;
 		}
@@ -549,15 +549,15 @@
 
 
 /* The routine terminates the computation */
-static void tgr192_final(void *ctx, u8 * out)
+static void tgr192_final(struct crypto_tfm *tfm, u8 * out)
 {
-	struct tgr192_ctx *tctx = ctx;
+	struct tgr192_ctx *tctx = crypto_tfm_ctx(tfm);
 	__be64 *dst = (__be64 *)out;
 	__be64 *be64p;
 	__le32 *le32p;
 	u32 t, msb, lsb;
 
-	tgr192_update(tctx, NULL, 0); /* flush */ ;
+	tgr192_update(tfm, NULL, 0); /* flush */ ;
 
 	msb = 0;
 	t = tctx->nblocks;
@@ -585,7 +585,7 @@
 		while (tctx->count < 64) {
 			tctx->hash[tctx->count++] = 0;
 		}
-		tgr192_update(tctx, NULL, 0); /* flush */ ;
+		tgr192_update(tfm, NULL, 0); /* flush */ ;
 		memset(tctx->hash, 0, 56);    /* fill next block with zeroes */
 	}
 	/* append the 64 bit count */
@@ -601,22 +601,20 @@
 	dst[2] = be64p[2] = cpu_to_be64(tctx->c);
 }
 
-static void tgr160_final(void *ctx, u8 * out)
+static void tgr160_final(struct crypto_tfm *tfm, u8 * out)
 {
-	struct tgr192_ctx *wctx = ctx;
 	u8 D[64];
 
-	tgr192_final(wctx, D);
+	tgr192_final(tfm, D);
 	memcpy(out, D, TGR160_DIGEST_SIZE);
 	memset(D, 0, TGR192_DIGEST_SIZE);
 }
 
-static void tgr128_final(void *ctx, u8 * out)
+static void tgr128_final(struct crypto_tfm *tfm, u8 * out)
 {
-	struct tgr192_ctx *wctx = ctx;
 	u8 D[64];
 
-	tgr192_final(wctx, D);
+	tgr192_final(tfm, D);
 	memcpy(out, D, TGR128_DIGEST_SIZE);
 	memset(D, 0, TGR192_DIGEST_SIZE);
 }
@@ -627,6 +625,7 @@
 	.cra_blocksize = TGR192_BLOCK_SIZE,
 	.cra_ctxsize = sizeof(struct tgr192_ctx),
 	.cra_module = THIS_MODULE,
+	.cra_alignmask = 7,
 	.cra_list = LIST_HEAD_INIT(tgr192.cra_list),
 	.cra_u = {.digest = {
 			     .dia_digestsize = TGR192_DIGEST_SIZE,
@@ -641,6 +640,7 @@
 	.cra_blocksize = TGR192_BLOCK_SIZE,
 	.cra_ctxsize = sizeof(struct tgr192_ctx),
 	.cra_module = THIS_MODULE,
+	.cra_alignmask = 7,
 	.cra_list = LIST_HEAD_INIT(tgr160.cra_list),
 	.cra_u = {.digest = {
 			     .dia_digestsize = TGR160_DIGEST_SIZE,
@@ -655,6 +655,7 @@
 	.cra_blocksize = TGR192_BLOCK_SIZE,
 	.cra_ctxsize = sizeof(struct tgr192_ctx),
 	.cra_module = THIS_MODULE,
+	.cra_alignmask = 7,
 	.cra_list = LIST_HEAD_INIT(tgr128.cra_list),
 	.cra_u = {.digest = {
 			     .dia_digestsize = TGR128_DIGEST_SIZE,
diff --git a/crypto/twofish.c b/crypto/twofish.c
index ddfd5a3..ec24882 100644
--- a/crypto/twofish.c
+++ b/crypto/twofish.c
@@ -643,11 +643,11 @@
 };
 
 /* Perform the key setup. */
-static int twofish_setkey(void *cx, const u8 *key,
-                          unsigned int key_len, u32 *flags)
+static int twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
+			  unsigned int key_len, u32 *flags)
 {
 	
-	struct twofish_ctx *ctx = cx;
+	struct twofish_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	int i, j, k;
 
@@ -802,9 +802,9 @@
 }
 
 /* Encrypt one block.  in and out may be the same. */
-static void twofish_encrypt(void *cx, u8 *out, const u8 *in)
+static void twofish_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct twofish_ctx *ctx = cx;
+	struct twofish_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *src = (const __le32 *)in;
 	__le32 *dst = (__le32 *)out;
 
@@ -839,9 +839,9 @@
 }
 
 /* Decrypt one block.  in and out may be the same. */
-static void twofish_decrypt(void *cx, u8 *out, const u8 *in)
+static void twofish_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct twofish_ctx *ctx = cx;
+	struct twofish_ctx *ctx = crypto_tfm_ctx(tfm);
 	const __le32 *src = (const __le32 *)in;
 	__le32 *dst = (__le32 *)out;
   
diff --git a/crypto/wp512.c b/crypto/wp512.c
index b226a12..727d05a 100644
--- a/crypto/wp512.c
+++ b/crypto/wp512.c
@@ -981,9 +981,9 @@
 
 }
 
-static void wp512_init (void *ctx) {
+static void wp512_init(struct crypto_tfm *tfm) {
+	struct wp512_ctx *wctx = crypto_tfm_ctx(tfm);
 	int i;
-	struct wp512_ctx *wctx = ctx;
 
 	memset(wctx->bitLength, 0, 32);
 	wctx->bufferBits = wctx->bufferPos = 0;
@@ -993,10 +993,10 @@
 	}
 }
 
-static void wp512_update(void *ctx, const u8 *source, unsigned int len)
+static void wp512_update(struct crypto_tfm *tfm, const u8 *source,
+			 unsigned int len)
 {
-
-	struct wp512_ctx *wctx = ctx;
+	struct wp512_ctx *wctx = crypto_tfm_ctx(tfm);
 	int sourcePos    = 0;
 	unsigned int bits_len = len * 8; // convert to number of bits
 	int sourceGap    = (8 - ((int)bits_len & 7)) & 7;
@@ -1054,9 +1054,9 @@
 
 }
 
-static void wp512_final(void *ctx, u8 *out)
+static void wp512_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct wp512_ctx *wctx = ctx;
+	struct wp512_ctx *wctx = crypto_tfm_ctx(tfm);
 	int i;
    	u8 *buffer      = wctx->buffer;
    	u8 *bitLength   = wctx->bitLength;
@@ -1087,22 +1087,20 @@
    	wctx->bufferPos    = bufferPos;
 }
 
-static void wp384_final(void *ctx, u8 *out)
+static void wp384_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct wp512_ctx *wctx = ctx;
 	u8 D[64];
 
-	wp512_final (wctx, D);
+	wp512_final(tfm, D);
 	memcpy (out, D, WP384_DIGEST_SIZE);
 	memset (D, 0, WP512_DIGEST_SIZE);
 }
 
-static void wp256_final(void *ctx, u8 *out)
+static void wp256_final(struct crypto_tfm *tfm, u8 *out)
 {
-	struct wp512_ctx *wctx = ctx;
 	u8 D[64];
 
-	wp512_final (wctx, D);
+	wp512_final(tfm, D);
 	memcpy (out, D, WP256_DIGEST_SIZE);
 	memset (D, 0, WP512_DIGEST_SIZE);
 }
diff --git a/drivers/Makefile b/drivers/Makefile
index 3c51703..fc2d744 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -74,4 +74,5 @@
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
 obj-$(CONFIG_SUPERH)		+= sh/
+obj-$(CONFIG_GENERIC_TIME)	+= clocksource/
 obj-$(CONFIG_DMA_ENGINE)	+= dma/
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 3b97a5e..8a74bf3 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -206,11 +206,11 @@
 
 static void acpi_safe_halt(void)
 {
-	clear_thread_flag(TIF_POLLING_NRFLAG);
+	current_thread_info()->status &= ~TS_POLLING;
 	smp_mb__after_clear_bit();
 	if (!need_resched())
 		safe_halt();
-	set_thread_flag(TIF_POLLING_NRFLAG);
+	current_thread_info()->status |= TS_POLLING;
 }
 
 static atomic_t c3_cpu_count;
@@ -330,10 +330,10 @@
 	 * Invoke the current Cx state to put the processor to sleep.
 	 */
 	if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {
-		clear_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status &= ~TS_POLLING;
 		smp_mb__after_clear_bit();
 		if (need_resched()) {
-			set_thread_flag(TIF_POLLING_NRFLAG);
+			current_thread_info()->status |= TS_POLLING;
 			local_irq_enable();
 			return;
 		}
@@ -369,9 +369,14 @@
 		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
 		/* Get end time (ticks) */
 		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+
+#ifdef CONFIG_GENERIC_TIME
+		/* TSC halts in C2, so notify users */
+		mark_tsc_unstable();
+#endif
 		/* Re-enable interrupts */
 		local_irq_enable();
-		set_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status |= TS_POLLING;
 		/* Compute time (ticks) that we were actually asleep */
 		sleep_ticks =
 		    ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
@@ -409,9 +414,13 @@
 					  ACPI_MTX_DO_NOT_LOCK);
 		}
 
+#ifdef CONFIG_GENERIC_TIME
+		/* TSC halts in C3, so notify users */
+		mark_tsc_unstable();
+#endif
 		/* Re-enable interrupts */
 		local_irq_enable();
-		set_thread_flag(TIF_POLLING_NRFLAG);
+		current_thread_info()->status |= TS_POLLING;
 		/* Compute time (ticks) that we were actually asleep */
 		sleep_ticks =
 		    ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 7f7ec28..f2eeaf9 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -951,7 +951,7 @@
 		   it most likely that the chip will notice it. It also prevents us
 		   from having to wait for completion. On the other hand, we may
 		   need to wait for completion anyway, to see if it completed
-		   succesfully. */
+		   successfully. */
 
 		switch (atm_vcc->qos.aal) {
 		case ATM_AAL2:
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index 520679c..826093e 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -53,8 +53,7 @@
 		struct device * dev = to_device(entry);
 
 		get_device(dev);
-		list_del_init(entry);
-		list_add_tail(entry, &dpm_active);
+		list_move_tail(entry, &dpm_active);
 
 		up(&dpm_list_sem);
 		if (!dev->power.prev_state.event)
@@ -101,8 +100,7 @@
 		struct device * dev = to_device(entry);
 
 		get_device(dev);
-		list_del_init(entry);
-		list_add_tail(entry, &dpm_active);
+		list_move_tail(entry, &dpm_active);
 		resume_device(dev);
 		put_device(dev);
 	}
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 1a1fe43..69509e0 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -116,12 +116,10 @@
 		/* Check if the device got removed */
 		if (!list_empty(&dev->power.entry)) {
 			/* Move it to the dpm_off or dpm_off_irq list */
-			if (!error) {
-				list_del(&dev->power.entry);
-				list_add(&dev->power.entry, &dpm_off);
-			} else if (error == -EAGAIN) {
-				list_del(&dev->power.entry);
-				list_add(&dev->power.entry, &dpm_off_irq);
+			if (!error)
+				list_move(&dev->power.entry, &dpm_off);
+			else if (error == -EAGAIN) {
+				list_move(&dev->power.entry, &dpm_off_irq);
 				error = 0;
 			}
 		}
@@ -139,8 +137,7 @@
 		 */
 		while (!list_empty(&dpm_off_irq)) {
 			struct list_head * entry = dpm_off_irq.next;
-			list_del(entry);
-			list_add(entry, &dpm_off);
+			list_move(entry, &dpm_off);
 		}
 		dpm_resume();
 	}
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2a8af68..2641597 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -64,6 +64,7 @@
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
+#include <linux/interrupt.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 25c3c4a..39b0f53 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -34,7 +34,7 @@
 #include <linux/blkpg.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
-#include <linux/init.h> 
+#include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
@@ -64,143 +64,129 @@
 
 /* define the PCI info for the cards we can control */
 static const struct pci_device_id cciss_pci_device_id[] = {
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
-			0x0E11, 0x4070, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
-                        0x0E11, 0x4080, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
-                        0x0E11, 0x4082, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
-                        0x0E11, 0x4083, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-		0x0E11, 0x409A, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-		0x0E11, 0x409B, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-		0x0E11, 0x409C, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-		0x0E11, 0x409D, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
-		0x0E11, 0x4091, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
-		0x103C, 0x3225, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-		0x103c, 0x3223, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-		0x103c, 0x3234, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-		0x103c, 0x3235, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-		0x103c, 0x3211, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-		0x103c, 0x3212, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-		0x103c, 0x3213, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-		0x103c, 0x3214, 0, 0, 0},
-	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
-		0x103c, 0x3215, 0, 0, 0},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,  0x0E11, 0x4070},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4080},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4083},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409A},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409B},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409C},
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409D},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSA,     0x103C, 0x3225},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3223},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3234},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3235},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3211},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3212},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3213},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3214},
+	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
 	{0,}
 };
-MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 
-#define NR_PRODUCTS ARRAY_SIZE(products)
+MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
- *  access = Address of the struct of function pointers 
+ *  access = Address of the struct of function pointers
  */
 static struct board_type products[] = {
-	{ 0x40700E11, "Smart Array 5300", &SA5_access },
-	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
-	{ 0x40820E11, "Smart Array 532", &SA5B_access},
-	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
-	{ 0x409A0E11, "Smart Array 641", &SA5_access},
-	{ 0x409B0E11, "Smart Array 642", &SA5_access},
-	{ 0x409C0E11, "Smart Array 6400", &SA5_access},
-	{ 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
-	{ 0x40910E11, "Smart Array 6i", &SA5_access},
-	{ 0x3225103C, "Smart Array P600", &SA5_access},
-	{ 0x3223103C, "Smart Array P800", &SA5_access},
-	{ 0x3234103C, "Smart Array P400", &SA5_access},
-	{ 0x3235103C, "Smart Array P400i", &SA5_access},
-	{ 0x3211103C, "Smart Array E200i", &SA5_access},
-	{ 0x3212103C, "Smart Array E200", &SA5_access},
-	{ 0x3213103C, "Smart Array E200i", &SA5_access},
-	{ 0x3214103C, "Smart Array E200i", &SA5_access},
-	{ 0x3215103C, "Smart Array E200i", &SA5_access},
+	{0x40700E11, "Smart Array 5300", &SA5_access},
+	{0x40800E11, "Smart Array 5i", &SA5B_access},
+	{0x40820E11, "Smart Array 532", &SA5B_access},
+	{0x40830E11, "Smart Array 5312", &SA5B_access},
+	{0x409A0E11, "Smart Array 641", &SA5_access},
+	{0x409B0E11, "Smart Array 642", &SA5_access},
+	{0x409C0E11, "Smart Array 6400", &SA5_access},
+	{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
+	{0x40910E11, "Smart Array 6i", &SA5_access},
+	{0x3225103C, "Smart Array P600", &SA5_access},
+	{0x3223103C, "Smart Array P800", &SA5_access},
+	{0x3234103C, "Smart Array P400", &SA5_access},
+	{0x3235103C, "Smart Array P400i", &SA5_access},
+	{0x3211103C, "Smart Array E200i", &SA5_access},
+	{0x3212103C, "Smart Array E200", &SA5_access},
+	{0x3213103C, "Smart Array E200i", &SA5_access},
+	{0x3214103C, "Smart Array E200i", &SA5_access},
+	{0x3215103C, "Smart Array E200i", &SA5_access},
 };
 
-/* How long to wait (in millesconds) for board to go into simple mode */
-#define MAX_CONFIG_WAIT 30000 
+/* How long to wait (in milliseconds) for board to go into simple mode */
+#define MAX_CONFIG_WAIT 30000
 #define MAX_IOCTL_CONFIG_WAIT 1000
 
 /*define how many times we will try a command because of bus resets */
 #define MAX_CMD_RETRIES 3
 
 #define READ_AHEAD 	 1024
-#define NR_CMDS		 384 /* #commands that can be outstanding */
+#define NR_CMDS		 384	/* #commands that can be outstanding */
 #define MAX_CTLR	32
 
 /* Originally cciss driver only supports 8 major numbers */
 #define MAX_CTLR_ORIG 	8
 
-
 static ctlr_info_t *hba[MAX_CTLR];
 
 static void do_cciss_request(request_queue_t *q);
 static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
 static int cciss_open(struct inode *inode, struct file *filep);
 static int cciss_release(struct inode *inode, struct file *filep);
-static int cciss_ioctl(struct inode *inode, struct file *filep, 
-		unsigned int cmd, unsigned long arg);
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+		       unsigned int cmd, unsigned long arg);
 static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int revalidate_allvol(ctlr_info_t *host);
 static int cciss_revalidate(struct gendisk *disk);
 static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+			   int clear_all);
 
 static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
-	int withirq, unsigned int *total_size, unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol,
-			int withirq, unsigned int total_size,
-			unsigned int block_size, InquiryData_struct *inq_buff,
-			drive_info_struct *drv);
+				int withirq, unsigned int *total_size,
+				unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
+				   unsigned int total_size,
+				   unsigned int block_size,
+				   InquiryData_struct *inq_buff,
+				   drive_info_struct *drv);
 static void cciss_getgeometry(int cntl_num);
-static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
-static void start_io( ctlr_info_t *h);
-static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
-	unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
-	unsigned char *scsi3addr, int cmd_type);
-static int sendcmd_withirq(__u8	cmd, int ctlr, void *buff, size_t size,
-	unsigned int use_unit_num, unsigned int log_unit, __u8	page_code,
-	int cmd_type);
+static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
+					   __u32);
+static void start_io(ctlr_info_t *h);
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
+		   unsigned int use_unit_num, unsigned int log_unit,
+		   __u8 page_code, unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+			   unsigned int use_unit_num, unsigned int log_unit,
+			   __u8 page_code, int cmd_type);
 
 static void fail_all_cmds(unsigned long ctlr);
 
 #ifdef CONFIG_PROC_FS
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
-		int length, int *eof, void *data);
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+			       int length, int *eof, void *data);
 static void cciss_procinit(int i);
 #else
-static void cciss_procinit(int i) {}
-#endif /* CONFIG_PROC_FS */
+static void cciss_procinit(int i)
+{
+}
+#endif				/* CONFIG_PROC_FS */
 
 #ifdef CONFIG_COMPAT
 static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
 #endif
 
-static struct block_device_operations cciss_fops  = {
-	.owner		= THIS_MODULE,
-	.open		= cciss_open, 
-	.release       	= cciss_release,
-        .ioctl		= cciss_ioctl,
-        .getgeo		= cciss_getgeo,
+static struct block_device_operations cciss_fops = {
+	.owner = THIS_MODULE,
+	.open = cciss_open,
+	.release = cciss_release,
+	.ioctl = cciss_ioctl,
+	.getgeo = cciss_getgeo,
 #ifdef CONFIG_COMPAT
-	.compat_ioctl   = cciss_compat_ioctl,
+	.compat_ioctl = cciss_compat_ioctl,
 #endif
-	.revalidate_disk= cciss_revalidate,
+	.revalidate_disk = cciss_revalidate,
 };
 
 /*
@@ -208,28 +194,29 @@
  */
 static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
 {
-        if (*Qptr == NULL) {
-                *Qptr = c;
-                c->next = c->prev = c;
-        } else {
-                c->prev = (*Qptr)->prev;
-                c->next = (*Qptr);
-                (*Qptr)->prev->next = c;
-                (*Qptr)->prev = c;
-        }
+	if (*Qptr == NULL) {
+		*Qptr = c;
+		c->next = c->prev = c;
+	} else {
+		c->prev = (*Qptr)->prev;
+		c->next = (*Qptr);
+		(*Qptr)->prev->next = c;
+		(*Qptr)->prev = c;
+	}
 }
 
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr, 
-						CommandList_struct *c)
+static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
+					  CommandList_struct *c)
 {
-        if (c && c->next != c) {
-                if (*Qptr == c) *Qptr = c->next;
-                c->prev->next = c->next;
-                c->next->prev = c->prev;
-        } else {
-                *Qptr = NULL;
-        }
-        return c;
+	if (c && c->next != c) {
+		if (*Qptr == c)
+			*Qptr = c->next;
+		c->prev->next = c->next;
+		c->next->prev = c->prev;
+	} else {
+		*Qptr = NULL;
+	}
+	return c;
 }
 
 #include "cciss_scsi.c"		/* For SCSI tape support */
@@ -242,23 +229,24 @@
 #define ENG_GIG 1000000000
 #define ENG_GIG_FACTOR (ENG_GIG/512)
 #define RAID_UNKNOWN 6
-static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG",
-	                                   "UNKNOWN"};
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+	"UNKNOWN"
+};
 
 static struct proc_dir_entry *proc_cciss;
 
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
-		int length, int *eof, void *data)
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+			       int length, int *eof, void *data)
 {
-        off_t pos = 0;
-        off_t len = 0;
-        int size, i, ctlr;
-        ctlr_info_t *h = (ctlr_info_t*)data;
-        drive_info_struct *drv;
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h = (ctlr_info_t *) data;
+	drive_info_struct *drv;
 	unsigned long flags;
-        sector_t vol_sz, vol_sz_frac;
+	sector_t vol_sz, vol_sz_frac;
 
-        ctlr = h->ctlr;
+	ctlr = h->ctlr;
 
 	/* prevent displaying bogus info during configuration
 	 * or deconfiguration of a logical volume
@@ -266,35 +254,35 @@
 	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 	if (h->busy_configuring) {
 		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-	return -EBUSY;
+		return -EBUSY;
 	}
 	h->busy_configuring = 1;
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
-        size = sprintf(buffer, "%s: HP %s Controller\n"
-		"Board ID: 0x%08lx\n"
-		"Firmware Version: %c%c%c%c\n"
-		"IRQ: %d\n"
-		"Logical drives: %d\n"
-		"Current Q depth: %d\n"
-		"Current # commands on controller: %d\n"
-		"Max Q depth since init: %d\n"
-		"Max # commands on controller since init: %d\n"
-		"Max SG entries since init: %d\n\n",
-                h->devname,
-                h->product_name,
-                (unsigned long)h->board_id,
-		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned int)h->intr[SIMPLE_MODE_INT],
-                h->num_luns, 
-		h->Qdepth, h->commands_outstanding,
-		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+	size = sprintf(buffer, "%s: HP %s Controller\n"
+		       "Board ID: 0x%08lx\n"
+		       "Firmware Version: %c%c%c%c\n"
+		       "IRQ: %d\n"
+		       "Logical drives: %d\n"
+		       "Current Q depth: %d\n"
+		       "Current # commands on controller: %d\n"
+		       "Max Q depth since init: %d\n"
+		       "Max # commands on controller since init: %d\n"
+		       "Max SG entries since init: %d\n\n",
+		       h->devname,
+		       h->product_name,
+		       (unsigned long)h->board_id,
+		       h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
+		       h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT],
+		       h->num_luns, h->Qdepth, h->commands_outstanding,
+		       h->maxQsinceinit, h->max_outstanding, h->maxSG);
 
-        pos += size; len += size;
+	pos += size;
+	len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-	for(i=0; i<=h->highest_lun; i++) {
+	for (i = 0; i <= h->highest_lun; i++) {
 
-                drv = &h->drv[i];
+		drv = &h->drv[i];
 		if (drv->heads == 0)
 			continue;
 
@@ -305,25 +293,26 @@
 
 		if (drv->raid_level > 5)
 			drv->raid_level = RAID_UNKNOWN;
-		size = sprintf(buffer+len, "cciss/c%dd%d:"
-				"\t%4u.%02uGB\tRAID %s\n",
-				ctlr, i, (int)vol_sz, (int)vol_sz_frac,
-				raid_label[drv->raid_level]);
-                pos += size; len += size;
-        }
+		size = sprintf(buffer + len, "cciss/c%dd%d:"
+			       "\t%4u.%02uGB\tRAID %s\n",
+			       ctlr, i, (int)vol_sz, (int)vol_sz_frac,
+			       raid_label[drv->raid_level]);
+		pos += size;
+		len += size;
+	}
 
-        *eof = 1;
-        *start = buffer+offset;
-        len -= offset;
-        if (len>length)
-                len = length;
+	*eof = 1;
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
 	h->busy_configuring = 0;
-        return len;
+	return len;
 }
 
-static int 
-cciss_proc_write(struct file *file, const char __user *buffer, 
-			unsigned long count, void *data)
+static int
+cciss_proc_write(struct file *file, const char __user *buffer,
+		 unsigned long count, void *data)
 {
 	unsigned char cmd[80];
 	int len;
@@ -332,20 +321,23 @@
 	int rc;
 #endif
 
-	if (count > sizeof(cmd)-1) return -EINVAL;
-	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+	if (count > sizeof(cmd) - 1)
+		return -EINVAL;
+	if (copy_from_user(cmd, buffer, count))
+		return -EFAULT;
 	cmd[count] = '\0';
 	len = strlen(cmd);	// above 3 lines ensure safety
-	if (len && cmd[len-1] == '\n')
+	if (len && cmd[len - 1] == '\n')
 		cmd[--len] = '\0';
 #	ifdef CONFIG_CISS_SCSI_TAPE
-		if (strcmp("engage scsi", cmd)==0) {
-			rc = cciss_engage_scsi(h->ctlr);
-			if (rc != 0) return -rc;
-			return count;
-		}
-		/* might be nice to have "disengage" too, but it's not 
-		   safely possible. (only 1 module use count, lock issues.) */
+	if (strcmp("engage scsi", cmd) == 0) {
+		rc = cciss_engage_scsi(h->ctlr);
+		if (rc != 0)
+			return -rc;
+		return count;
+	}
+	/* might be nice to have "disengage" too, but it's not
+	   safely possible. (only 1 module use count, lock issues.) */
 #	endif
 	return -EINVAL;
 }
@@ -358,116 +350,113 @@
 {
 	struct proc_dir_entry *pde;
 
-        if (proc_cciss == NULL) {
-                proc_cciss = proc_mkdir("cciss", proc_root_driver);
-                if (!proc_cciss) 
+	if (proc_cciss == NULL) {
+		proc_cciss = proc_mkdir("cciss", proc_root_driver);
+		if (!proc_cciss)
 			return;
-        }
+	}
 
-	pde = create_proc_read_entry(hba[i]->devname, 
-		S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 
-		proc_cciss, cciss_proc_get_info, hba[i]);
+	pde = create_proc_read_entry(hba[i]->devname,
+				     S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
+				     proc_cciss, cciss_proc_get_info, hba[i]);
 	pde->write_proc = cciss_proc_write;
 }
-#endif /* CONFIG_PROC_FS */
+#endif				/* CONFIG_PROC_FS */
 
-/* 
- * For operations that cannot sleep, a command block is allocated at init, 
+/*
+ * For operations that cannot sleep, a command block is allocated at init,
  * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
- * which ones are free or in use.  For operations that can wait for kmalloc 
- * to possible sleep, this routine can be called with get_from_pool set to 0. 
- * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was. 
- */ 
-static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
+ * which ones are free or in use.  For operations that can wait for kmalloc
+ * to possible sleep, this routine can be called with get_from_pool set to 0.
+ * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
+ */
+static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
 {
 	CommandList_struct *c;
-	int i; 
+	int i;
 	u64bit temp64;
 	dma_addr_t cmd_dma_handle, err_dma_handle;
 
-	if (!get_from_pool)
-	{
-		c = (CommandList_struct *) pci_alloc_consistent(
-			h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); 
-        	if(c==NULL)
-                 	return NULL;
+	if (!get_from_pool) {
+		c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
+			sizeof(CommandList_struct), &cmd_dma_handle);
+		if (c == NULL)
+			return NULL;
 		memset(c, 0, sizeof(CommandList_struct));
 
 		c->cmdindex = -1;
 
-		c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
-					h->pdev, sizeof(ErrorInfo_struct), 
-					&err_dma_handle);
-	
-		if (c->err_info == NULL)
-		{
-			pci_free_consistent(h->pdev, 
+		c->err_info = (ErrorInfo_struct *)
+		    pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
+			    &err_dma_handle);
+
+		if (c->err_info == NULL) {
+			pci_free_consistent(h->pdev,
 				sizeof(CommandList_struct), c, cmd_dma_handle);
 			return NULL;
 		}
 		memset(c->err_info, 0, sizeof(ErrorInfo_struct));
-	} else /* get it out of the controllers pool */ 
-	{
-	     	do {
-                	i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
-                        if (i == NR_CMDS)
-                                return NULL;
-                } while(test_and_set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits+(i/BITS_PER_LONG)) != 0);
+	} else {		/* get it out of the controllers pool */
+
+		do {
+			i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+			if (i == NR_CMDS)
+				return NULL;
+		} while (test_and_set_bit
+			 (i & (BITS_PER_LONG - 1),
+			  h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
 #ifdef CCISS_DEBUG
 		printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
 #endif
-                c = h->cmd_pool + i;
+		c = h->cmd_pool + i;
 		memset(c, 0, sizeof(CommandList_struct));
-		cmd_dma_handle = h->cmd_pool_dhandle 
-					+ i*sizeof(CommandList_struct);
+		cmd_dma_handle = h->cmd_pool_dhandle
+		    + i * sizeof(CommandList_struct);
 		c->err_info = h->errinfo_pool + i;
 		memset(c->err_info, 0, sizeof(ErrorInfo_struct));
-		err_dma_handle = h->errinfo_pool_dhandle 
-					+ i*sizeof(ErrorInfo_struct);
-                h->nr_allocs++;
+		err_dma_handle = h->errinfo_pool_dhandle
+		    + i * sizeof(ErrorInfo_struct);
+		h->nr_allocs++;
 
 		c->cmdindex = i;
-        }
+	}
 
 	c->busaddr = (__u32) cmd_dma_handle;
-	temp64.val = (__u64) err_dma_handle;	
+	temp64.val = (__u64) err_dma_handle;
 	c->ErrDesc.Addr.lower = temp64.val32.lower;
 	c->ErrDesc.Addr.upper = temp64.val32.upper;
 	c->ErrDesc.Len = sizeof(ErrorInfo_struct);
-	
+
 	c->ctlr = h->ctlr;
-        return c;
-
-
+	return c;
 }
 
-/* 
- * Frees a command block that was previously allocated with cmd_alloc(). 
+/*
+ * Frees a command block that was previously allocated with cmd_alloc().
  */
 static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool)
 {
 	int i;
 	u64bit temp64;
 
-	if( !got_from_pool)
-	{ 
+	if (!got_from_pool) {
 		temp64.val32.lower = c->ErrDesc.Addr.lower;
 		temp64.val32.upper = c->ErrDesc.Addr.upper;
-		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 
-			c->err_info, (dma_addr_t) temp64.val);
-		pci_free_consistent(h->pdev, sizeof(CommandList_struct), 
-			c, (dma_addr_t) c->busaddr);
-	} else 
-	{
+		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
+				    c->err_info, (dma_addr_t) temp64.val);
+		pci_free_consistent(h->pdev, sizeof(CommandList_struct),
+				    c, (dma_addr_t) c->busaddr);
+	} else {
 		i = c - h->cmd_pool;
-		clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));
-                h->nr_frees++;
-        }
+		clear_bit(i & (BITS_PER_LONG - 1),
+			  h->cmd_pool_bits + (i / BITS_PER_LONG));
+		h->nr_frees++;
+	}
 }
 
 static inline ctlr_info_t *get_host(struct gendisk *disk)
 {
-	return disk->queue->queuedata; 
+	return disk->queue->queuedata;
 }
 
 static inline drive_info_struct *get_drv(struct gendisk *disk)
@@ -485,7 +474,7 @@
 
 #ifdef CCISS_DEBUG
 	printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */ 
+#endif				/* CCISS_DEBUG */
 
 	if (host->busy_initializing || drv->busy_configuring)
 		return -EBUSY;
@@ -498,10 +487,10 @@
 	 * for "raw controller".
 	 */
 	if (drv->nr_blocks == 0) {
-		if (iminor(inode) != 0)	{ 	/* not node 0? */
+		if (iminor(inode) != 0) {	/* not node 0? */
 			/* if not node 0 make sure it is a partition = 0 */
 			if (iminor(inode) & 0x0f) {
-			return -ENXIO;
+				return -ENXIO;
 				/* if it is, make sure we have a LUN ID */
 			} else if (drv->LunID == 0) {
 				return -ENXIO;
@@ -514,6 +503,7 @@
 	host->usage_count++;
 	return 0;
 }
+
 /*
  * Close.  Sync first.
  */
@@ -523,8 +513,9 @@
 	drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
 
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */
+	printk(KERN_DEBUG "cciss_release %s\n",
+	       inode->i_bdev->bd_disk->disk_name);
+#endif				/* CCISS_DEBUG */
 
 	drv->usage_count--;
 	host->usage_count--;
@@ -542,8 +533,10 @@
 	return ret;
 }
 
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg);
-static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd, unsigned long arg);
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+				  unsigned long arg);
+static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd,
+				      unsigned long arg);
 
 static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
 {
@@ -575,19 +568,26 @@
 	}
 }
 
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+				  unsigned long arg)
 {
 	IOCTL32_Command_struct __user *arg32 =
-		(IOCTL32_Command_struct __user *) arg;
+	    (IOCTL32_Command_struct __user *) arg;
 	IOCTL_Command_struct arg64;
 	IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
 	int err;
 	u32 cp;
 
 	err = 0;
-	err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
-	err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
-	err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+	err |=
+	    copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+			   sizeof(arg64.LUN_info));
+	err |=
+	    copy_from_user(&arg64.Request, &arg32->Request,
+			   sizeof(arg64.Request));
+	err |=
+	    copy_from_user(&arg64.error_info, &arg32->error_info,
+			   sizeof(arg64.error_info));
 	err |= get_user(arg64.buf_size, &arg32->buf_size);
 	err |= get_user(cp, &arg32->buf);
 	arg64.buf = compat_ptr(cp);
@@ -596,28 +596,38 @@
 	if (err)
 		return -EFAULT;
 
-	err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long) p);
+	err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long)p);
 	if (err)
 		return err;
-	err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+	err |=
+	    copy_in_user(&arg32->error_info, &p->error_info,
+			 sizeof(arg32->error_info));
 	if (err)
 		return -EFAULT;
 	return err;
 }
 
-static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd,
+				      unsigned long arg)
 {
 	BIG_IOCTL32_Command_struct __user *arg32 =
-		(BIG_IOCTL32_Command_struct __user *) arg;
+	    (BIG_IOCTL32_Command_struct __user *) arg;
 	BIG_IOCTL_Command_struct arg64;
-	BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+	BIG_IOCTL_Command_struct __user *p =
+	    compat_alloc_user_space(sizeof(arg64));
 	int err;
 	u32 cp;
 
 	err = 0;
-	err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
-	err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
-	err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+	err |=
+	    copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+			   sizeof(arg64.LUN_info));
+	err |=
+	    copy_from_user(&arg64.Request, &arg32->Request,
+			   sizeof(arg64.Request));
+	err |=
+	    copy_from_user(&arg64.error_info, &arg32->error_info,
+			   sizeof(arg64.error_info));
 	err |= get_user(arg64.buf_size, &arg32->buf_size);
 	err |= get_user(arg64.malloc_size, &arg32->malloc_size);
 	err |= get_user(cp, &arg32->buf);
@@ -625,12 +635,14 @@
 	err |= copy_to_user(p, &arg64, sizeof(arg64));
 
 	if (err)
-		 return -EFAULT;
+		return -EFAULT;
 
-	err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long) p);
+	err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long)p);
 	if (err)
 		return err;
-	err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+	err |=
+	    copy_in_user(&arg32->error_info, &p->error_info,
+			 sizeof(arg32->error_info));
 	if (err)
 		return -EFAULT;
 	return err;
@@ -651,10 +663,10 @@
 }
 
 /*
- * ioctl 
+ * ioctl
  */
-static int cciss_ioctl(struct inode *inode, struct file *filep, 
-		unsigned int cmd, unsigned long arg)
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+		       unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
 	struct gendisk *disk = bdev->bd_disk;
@@ -665,171 +677,193 @@
 
 #ifdef CCISS_DEBUG
 	printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
-#endif /* CCISS_DEBUG */ 
-	
-	switch(cmd) {
+#endif				/* CCISS_DEBUG */
+
+	switch (cmd) {
 	case CCISS_GETPCIINFO:
-	{
-		cciss_pci_info_struct pciinfo;
-
-		if (!arg) return -EINVAL;
-		pciinfo.domain = pci_domain_nr(host->pdev->bus);
-		pciinfo.bus = host->pdev->bus->number;
-		pciinfo.dev_fn = host->pdev->devfn;
-		pciinfo.board_id = host->board_id;
-		if (copy_to_user(argp, &pciinfo,  sizeof( cciss_pci_info_struct )))
-			return  -EFAULT;
-		return(0);
-	}	
-	case CCISS_GETINTINFO:
-	{
-		cciss_coalint_struct intinfo;
-		if (!arg) return -EINVAL;
-		intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay);
-		intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount);
-		if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct )))
-			return -EFAULT;
-                return(0);
-        }
-	case CCISS_SETINTINFO:
-        {
-                cciss_coalint_struct intinfo;
-		unsigned long flags;
-		int i;
-
-		if (!arg) return -EINVAL;	
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-		if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct)))
-			return -EFAULT;
-		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
 		{
-//			printk("cciss_ioctl: delay and count cannot be 0\n");
-			return( -EINVAL);
+			cciss_pci_info_struct pciinfo;
+
+			if (!arg)
+				return -EINVAL;
+			pciinfo.domain = pci_domain_nr(host->pdev->bus);
+			pciinfo.bus = host->pdev->bus->number;
+			pciinfo.dev_fn = host->pdev->devfn;
+			pciinfo.board_id = host->board_id;
+			if (copy_to_user
+			    (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
+				return -EFAULT;
+			return 0;
 		}
-		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-		/* Update the field, and then ring the doorbell */ 
-		writel( intinfo.delay, 
-			&(host->cfgtable->HostWrite.CoalIntDelay));
-		writel( intinfo.count, 
-                        &(host->cfgtable->HostWrite.CoalIntCount));
-		writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+	case CCISS_GETINTINFO:
+		{
+			cciss_coalint_struct intinfo;
+			if (!arg)
+				return -EINVAL;
+			intinfo.delay =
+			    readl(&host->cfgtable->HostWrite.CoalIntDelay);
+			intinfo.count =
+			    readl(&host->cfgtable->HostWrite.CoalIntCount);
+			if (copy_to_user
+			    (argp, &intinfo, sizeof(cciss_coalint_struct)))
+				return -EFAULT;
+			return 0;
+		}
+	case CCISS_SETINTINFO:
+		{
+			cciss_coalint_struct intinfo;
+			unsigned long flags;
+			int i;
 
-		for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
-			if (!(readl(host->vaddr + SA5_DOORBELL) 
-					& CFGTBL_ChangeReq))
-				break;
-			/* delay and try again */
-			udelay(1000);
-		}	
-		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-		if (i >= MAX_IOCTL_CONFIG_WAIT)
-			return -EAGAIN;
-                return(0);
-        }
+			if (!arg)
+				return -EINVAL;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			if (copy_from_user
+			    (&intinfo, argp, sizeof(cciss_coalint_struct)))
+				return -EFAULT;
+			if ((intinfo.delay == 0) && (intinfo.count == 0))
+			{
+//                      printk("cciss_ioctl: delay and count cannot be 0\n");
+				return -EINVAL;
+			}
+			spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+			/* Update the field, and then ring the doorbell */
+			writel(intinfo.delay,
+			       &(host->cfgtable->HostWrite.CoalIntDelay));
+			writel(intinfo.count,
+			       &(host->cfgtable->HostWrite.CoalIntCount));
+			writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+			for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+				if (!(readl(host->vaddr + SA5_DOORBELL)
+				      & CFGTBL_ChangeReq))
+					break;
+				/* delay and try again */
+				udelay(1000);
+			}
+			spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+			if (i >= MAX_IOCTL_CONFIG_WAIT)
+				return -EAGAIN;
+			return 0;
+		}
 	case CCISS_GETNODENAME:
-        {
-                NodeName_type NodeName;
-		int i; 
+		{
+			NodeName_type NodeName;
+			int i;
 
-		if (!arg) return -EINVAL;
-		for(i=0;i<16;i++)
-			NodeName[i] = readb(&host->cfgtable->ServerName[i]);
-                if (copy_to_user(argp, NodeName, sizeof( NodeName_type)))
-                	return  -EFAULT;
-                return(0);
-        }
+			if (!arg)
+				return -EINVAL;
+			for (i = 0; i < 16; i++)
+				NodeName[i] =
+				    readb(&host->cfgtable->ServerName[i]);
+			if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
+				return -EFAULT;
+			return 0;
+		}
 	case CCISS_SETNODENAME:
-	{
-		NodeName_type NodeName;
-		unsigned long flags;
-		int i;
+		{
+			NodeName_type NodeName;
+			unsigned long flags;
+			int i;
 
-		if (!arg) return -EINVAL;
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-		
-		if (copy_from_user(NodeName, argp, sizeof( NodeName_type)))
-			return -EFAULT;
+			if (!arg)
+				return -EINVAL;
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
 
-		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+			if (copy_from_user
+			    (NodeName, argp, sizeof(NodeName_type)))
+				return -EFAULT;
 
-			/* Update the field, and then ring the doorbell */ 
-		for(i=0;i<16;i++)
-			writeb( NodeName[i], &host->cfgtable->ServerName[i]);
-			
-		writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+			spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 
-		for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
-			if (!(readl(host->vaddr + SA5_DOORBELL) 
-					& CFGTBL_ChangeReq))
-				break;
-			/* delay and try again */
-			udelay(1000);
-		}	
-		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-		if (i >= MAX_IOCTL_CONFIG_WAIT)
-			return -EAGAIN;
-                return(0);
-        }
+			/* Update the field, and then ring the doorbell */
+			for (i = 0; i < 16; i++)
+				writeb(NodeName[i],
+				       &host->cfgtable->ServerName[i]);
+
+			writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+			for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+				if (!(readl(host->vaddr + SA5_DOORBELL)
+				      & CFGTBL_ChangeReq))
+					break;
+				/* delay and try again */
+				udelay(1000);
+			}
+			spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+			if (i >= MAX_IOCTL_CONFIG_WAIT)
+				return -EAGAIN;
+			return 0;
+		}
 
 	case CCISS_GETHEARTBEAT:
-        {
-                Heartbeat_type heartbeat;
+		{
+			Heartbeat_type heartbeat;
 
-		if (!arg) return -EINVAL;
-                heartbeat = readl(&host->cfgtable->HeartBeat);
-                if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type)))
-                	return -EFAULT;
-                return(0);
-        }
+			if (!arg)
+				return -EINVAL;
+			heartbeat = readl(&host->cfgtable->HeartBeat);
+			if (copy_to_user
+			    (argp, &heartbeat, sizeof(Heartbeat_type)))
+				return -EFAULT;
+			return 0;
+		}
 	case CCISS_GETBUSTYPES:
-        {
-                BusTypes_type BusTypes;
+		{
+			BusTypes_type BusTypes;
 
-		if (!arg) return -EINVAL;
-                BusTypes = readl(&host->cfgtable->BusTypes);
-                if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) ))
-                	return  -EFAULT;
-                return(0);
-        }
+			if (!arg)
+				return -EINVAL;
+			BusTypes = readl(&host->cfgtable->BusTypes);
+			if (copy_to_user
+			    (argp, &BusTypes, sizeof(BusTypes_type)))
+				return -EFAULT;
+			return 0;
+		}
 	case CCISS_GETFIRMVER:
-        {
-		FirmwareVer_type firmware;
+		{
+			FirmwareVer_type firmware;
 
-		if (!arg) return -EINVAL;
-		memcpy(firmware, host->firm_ver, 4);
+			if (!arg)
+				return -EINVAL;
+			memcpy(firmware, host->firm_ver, 4);
 
-                if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type)))
-                	return -EFAULT;
-                return(0);
-        }
-        case CCISS_GETDRIVVER:
-        {
-		DriverVer_type DriverVer = DRIVER_VERSION;
+			if (copy_to_user
+			    (argp, firmware, sizeof(FirmwareVer_type)))
+				return -EFAULT;
+			return 0;
+		}
+	case CCISS_GETDRIVVER:
+		{
+			DriverVer_type DriverVer = DRIVER_VERSION;
 
-                if (!arg) return -EINVAL;
+			if (!arg)
+				return -EINVAL;
 
-                if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) ))
-                	return -EFAULT;
-                return(0);
-        }
+			if (copy_to_user
+			    (argp, &DriverVer, sizeof(DriverVer_type)))
+				return -EFAULT;
+			return 0;
+		}
 
 	case CCISS_REVALIDVOLS:
 		if (bdev != bdev->bd_contains || drv != host->drv)
 			return -ENXIO;
-                return revalidate_allvol(host);
+		return revalidate_allvol(host);
 
- 	case CCISS_GETLUNINFO: {
- 		LogvolInfo_struct luninfo;
- 		
- 		luninfo.LunID = drv->LunID;
- 		luninfo.num_opens = drv->usage_count;
- 		luninfo.num_parts = 0;
- 		if (copy_to_user(argp, &luninfo,
- 				sizeof(LogvolInfo_struct)))
- 			return -EFAULT;
- 		return(0);
- 	}
+	case CCISS_GETLUNINFO:{
+			LogvolInfo_struct luninfo;
+
+			luninfo.LunID = drv->LunID;
+			luninfo.num_opens = drv->usage_count;
+			luninfo.num_parts = 0;
+			if (copy_to_user(argp, &luninfo,
+					 sizeof(LogvolInfo_struct)))
+				return -EFAULT;
+			return 0;
+		}
 	case CCISS_DEREGDISK:
 		return rebuild_lun_table(host, disk);
 
@@ -837,278 +871,284 @@
 		return rebuild_lun_table(host, NULL);
 
 	case CCISS_PASSTHRU:
-	{
-		IOCTL_Command_struct iocommand;
-		CommandList_struct *c;
-		char 	*buff = NULL;
-		u64bit	temp64;
-		unsigned long flags;
-		DECLARE_COMPLETION(wait);
-
-		if (!arg) return -EINVAL;
-	
-		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
-
-		if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) ))
-			return -EFAULT;
-		if((iocommand.buf_size < 1) && 
-				(iocommand.Request.Type.Direction != XFER_NONE))
-		{	
-			return -EINVAL;
-		} 
-#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
-		/* Check kmalloc limits */
-		if(iocommand.buf_size > 128000)
-			return -EINVAL;
-#endif
-		if(iocommand.buf_size > 0)
 		{
-			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
-			if( buff == NULL) 
+			IOCTL_Command_struct iocommand;
+			CommandList_struct *c;
+			char *buff = NULL;
+			u64bit temp64;
+			unsigned long flags;
+			DECLARE_COMPLETION(wait);
+
+			if (!arg)
+				return -EINVAL;
+
+			if (!capable(CAP_SYS_RAWIO))
+				return -EPERM;
+
+			if (copy_from_user
+			    (&iocommand, argp, sizeof(IOCTL_Command_struct)))
 				return -EFAULT;
-		}
-		if (iocommand.Request.Type.Direction == XFER_WRITE)
-		{
-			/* Copy the data into the buffer we created */ 
-			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
-			{
-				kfree(buff);
-				return -EFAULT;
+			if ((iocommand.buf_size < 1) &&
+			    (iocommand.Request.Type.Direction != XFER_NONE)) {
+				return -EINVAL;
 			}
-		} else {
-			memset(buff, 0, iocommand.buf_size);
-		}
-		if ((c = cmd_alloc(host , 0)) == NULL)
-		{
-			kfree(buff);
-			return -ENOMEM;
-		}
-			// Fill in the command type 
-		c->cmd_type = CMD_IOCTL_PEND;
-			// Fill in Command Header 
-		c->Header.ReplyQueue = 0;  // unused in simple mode
-		if( iocommand.buf_size > 0) 	// buffer to fill 
-		{
-			c->Header.SGList = 1;
-			c->Header.SGTotal= 1;
-		} else	// no buffers to fill  
-		{
-			c->Header.SGList = 0;
-                	c->Header.SGTotal= 0;
-		}
-		c->Header.LUN = iocommand.LUN_info;
-		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-		
-		// Fill in Request block 
-		c->Request = iocommand.Request; 
-	
-		// Fill in the scatter gather information
-		if (iocommand.buf_size > 0 ) 
-		{
-			temp64.val = pci_map_single( host->pdev, buff,
-                                        iocommand.buf_size, 
-                                PCI_DMA_BIDIRECTIONAL);	
-			c->SG[0].Addr.lower = temp64.val32.lower;
-			c->SG[0].Addr.upper = temp64.val32.upper;
-			c->SG[0].Len = iocommand.buf_size;
-			c->SG[0].Ext = 0;  // we are not chaining
-		}
-		c->waiting = &wait;
-
-		/* Put the request on the tail of the request queue */
-		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-		addQ(&host->reqQ, c);
-		host->Qdepth++;
-		start_io(host);
-		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-
-		wait_for_completion(&wait);
-
-		/* unlock the buffers from DMA */
-		temp64.val32.lower = c->SG[0].Addr.lower;
-                temp64.val32.upper = c->SG[0].Addr.upper;
-                pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
-                	iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
-
-		/* Copy the error information out */ 
-		iocommand.error_info = *(c->err_info);
-		if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) )
-		{
-			kfree(buff);
-			cmd_free(host, c, 0);
-			return( -EFAULT);	
-		} 	
-
-		if (iocommand.Request.Type.Direction == XFER_READ)
-                {
-                        /* Copy the data out of the buffer we created */
-                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
+#if 0				/* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
+			/* Check kmalloc limits */
+			if (iocommand.buf_size > 128000)
+				return -EINVAL;
+#endif
+			if (iocommand.buf_size > 0) {
+				buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+				if (buff == NULL)
+					return -EFAULT;
+			}
+			if (iocommand.Request.Type.Direction == XFER_WRITE) {
+				/* Copy the data into the buffer we created */
+				if (copy_from_user
+				    (buff, iocommand.buf, iocommand.buf_size)) {
+					kfree(buff);
+					return -EFAULT;
+				}
+			} else {
+				memset(buff, 0, iocommand.buf_size);
+			}
+			if ((c = cmd_alloc(host, 0)) == NULL) {
+				kfree(buff);
+				return -ENOMEM;
+			}
+			// Fill in the command type
+			c->cmd_type = CMD_IOCTL_PEND;
+			// Fill in Command Header
+			c->Header.ReplyQueue = 0;	// unused in simple mode
+			if (iocommand.buf_size > 0)	// buffer to fill
 			{
-                        	kfree(buff);
+				c->Header.SGList = 1;
+				c->Header.SGTotal = 1;
+			} else	// no buffers to fill
+			{
+				c->Header.SGList = 0;
+				c->Header.SGTotal = 0;
+			}
+			c->Header.LUN = iocommand.LUN_info;
+			c->Header.Tag.lower = c->busaddr;	// use the kernel address the cmd block for tag
+
+			// Fill in Request block
+			c->Request = iocommand.Request;
+
+			// Fill in the scatter gather information
+			if (iocommand.buf_size > 0) {
+				temp64.val = pci_map_single(host->pdev, buff,
+					iocommand.buf_size,
+					PCI_DMA_BIDIRECTIONAL);
+				c->SG[0].Addr.lower = temp64.val32.lower;
+				c->SG[0].Addr.upper = temp64.val32.upper;
+				c->SG[0].Len = iocommand.buf_size;
+				c->SG[0].Ext = 0;	// we are not chaining
+			}
+			c->waiting = &wait;
+
+			/* Put the request on the tail of the request queue */
+			spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+			addQ(&host->reqQ, c);
+			host->Qdepth++;
+			start_io(host);
+			spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+			wait_for_completion(&wait);
+
+			/* unlock the buffers from DMA */
+			temp64.val32.lower = c->SG[0].Addr.lower;
+			temp64.val32.upper = c->SG[0].Addr.upper;
+			pci_unmap_single(host->pdev, (dma_addr_t) temp64.val,
+					 iocommand.buf_size,
+					 PCI_DMA_BIDIRECTIONAL);
+
+			/* Copy the error information out */
+			iocommand.error_info = *(c->err_info);
+			if (copy_to_user
+			    (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
+				kfree(buff);
 				cmd_free(host, c, 0);
 				return -EFAULT;
 			}
-                }
-                kfree(buff);
-		cmd_free(host, c, 0);
-                return(0);
-	} 
-	case CCISS_BIG_PASSTHRU: {
-		BIG_IOCTL_Command_struct *ioc;
-		CommandList_struct *c;
-		unsigned char **buff = NULL;
-		int	*buff_size = NULL;
-		u64bit	temp64;
-		unsigned long flags;
-		BYTE sg_used = 0;
-		int status = 0;
-		int i;
-		DECLARE_COMPLETION(wait);
-		__u32   left;
-		__u32	sz;
-		BYTE    __user *data_ptr;
 
-		if (!arg)
-			return -EINVAL;
-		if (!capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		ioc = (BIG_IOCTL_Command_struct *) 
-			kmalloc(sizeof(*ioc), GFP_KERNEL);
-		if (!ioc) {
-			status = -ENOMEM;
-			goto cleanup1;
+			if (iocommand.Request.Type.Direction == XFER_READ) {
+				/* Copy the data out of the buffer we created */
+				if (copy_to_user
+				    (iocommand.buf, buff, iocommand.buf_size)) {
+					kfree(buff);
+					cmd_free(host, c, 0);
+					return -EFAULT;
+				}
+			}
+			kfree(buff);
+			cmd_free(host, c, 0);
+			return 0;
 		}
-		if (copy_from_user(ioc, argp, sizeof(*ioc))) {
-			status = -EFAULT;
-			goto cleanup1;
-		}
-		if ((ioc->buf_size < 1) &&
-			(ioc->Request.Type.Direction != XFER_NONE)) {
-				status = -EINVAL;
-				goto cleanup1;
-		}
-		/* Check kmalloc limits  using all SGs */
-		if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
-			status = -EINVAL;
-			goto cleanup1;
-		}
-		if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
-			status = -EINVAL;
-			goto cleanup1;
-		}
-		buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
-		if (!buff) {
-			status = -ENOMEM;
-			goto cleanup1;
-		}
-		buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int), 
-					GFP_KERNEL);
-		if (!buff_size) {
-			status = -ENOMEM;
-			goto cleanup1;
-		}
-		left = ioc->buf_size;
-		data_ptr = ioc->buf;
-		while (left) {
-			sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
-			buff_size[sg_used] = sz;
-			buff[sg_used] = kmalloc(sz, GFP_KERNEL);
-			if (buff[sg_used] == NULL) {
+	case CCISS_BIG_PASSTHRU:{
+			BIG_IOCTL_Command_struct *ioc;
+			CommandList_struct *c;
+			unsigned char **buff = NULL;
+			int *buff_size = NULL;
+			u64bit temp64;
+			unsigned long flags;
+			BYTE sg_used = 0;
+			int status = 0;
+			int i;
+			DECLARE_COMPLETION(wait);
+			__u32 left;
+			__u32 sz;
+			BYTE __user *data_ptr;
+
+			if (!arg)
+				return -EINVAL;
+			if (!capable(CAP_SYS_RAWIO))
+				return -EPERM;
+			ioc = (BIG_IOCTL_Command_struct *)
+			    kmalloc(sizeof(*ioc), GFP_KERNEL);
+			if (!ioc) {
 				status = -ENOMEM;
 				goto cleanup1;
 			}
-			if (ioc->Request.Type.Direction == XFER_WRITE) {
-				if (copy_from_user(buff[sg_used], data_ptr, sz)) {
+			if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+				status = -EFAULT;
+				goto cleanup1;
+			}
+			if ((ioc->buf_size < 1) &&
+			    (ioc->Request.Type.Direction != XFER_NONE)) {
+				status = -EINVAL;
+				goto cleanup1;
+			}
+			/* Check kmalloc limits  using all SGs */
+			if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+				status = -EINVAL;
+				goto cleanup1;
+			}
+			if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+				status = -EINVAL;
+				goto cleanup1;
+			}
+			buff =
+			    kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+			if (!buff) {
+				status = -ENOMEM;
+				goto cleanup1;
+			}
+			buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int),
+						   GFP_KERNEL);
+			if (!buff_size) {
+				status = -ENOMEM;
+				goto cleanup1;
+			}
+			left = ioc->buf_size;
+			data_ptr = ioc->buf;
+			while (left) {
+				sz = (left >
+				      ioc->malloc_size) ? ioc->
+				    malloc_size : left;
+				buff_size[sg_used] = sz;
+				buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+				if (buff[sg_used] == NULL) {
 					status = -ENOMEM;
 					goto cleanup1;
 				}
-			} else {
-				memset(buff[sg_used], 0, sz);
-			}
-			left -= sz;
-			data_ptr += sz;
-			sg_used++;
-		}
-		if ((c = cmd_alloc(host , 0)) == NULL) {
-			status = -ENOMEM;
-			goto cleanup1;	
-		}
-		c->cmd_type = CMD_IOCTL_PEND;
-		c->Header.ReplyQueue = 0;
-		
-		if( ioc->buf_size > 0) {
-			c->Header.SGList = sg_used;
-			c->Header.SGTotal= sg_used;
-		} else { 
-			c->Header.SGList = 0;
-			c->Header.SGTotal= 0;
-		}
-		c->Header.LUN = ioc->LUN_info;
-		c->Header.Tag.lower = c->busaddr;
-		
-		c->Request = ioc->Request;
-		if (ioc->buf_size > 0 ) {
-			int i;
-			for(i=0; i<sg_used; i++) {
-				temp64.val = pci_map_single( host->pdev, buff[i],
-					buff_size[i],
-					PCI_DMA_BIDIRECTIONAL);
-				c->SG[i].Addr.lower = temp64.val32.lower;
-				c->SG[i].Addr.upper = temp64.val32.upper;
-				c->SG[i].Len = buff_size[i];
-				c->SG[i].Ext = 0;  /* we are not chaining */
-			}
-		}
-		c->waiting = &wait;
-		/* Put the request on the tail of the request queue */
-		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-		addQ(&host->reqQ, c);
-		host->Qdepth++;
-		start_io(host);
-		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-		wait_for_completion(&wait);
-		/* unlock the buffers from DMA */
-		for(i=0; i<sg_used; i++) {
-			temp64.val32.lower = c->SG[i].Addr.lower;
-			temp64.val32.upper = c->SG[i].Addr.upper;
-			pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
-				buff_size[i], PCI_DMA_BIDIRECTIONAL);
-		}
-		/* Copy the error information out */
-		ioc->error_info = *(c->err_info);
-		if (copy_to_user(argp, ioc, sizeof(*ioc))) {
-			cmd_free(host, c, 0);
-			status = -EFAULT;
-			goto cleanup1;
-		}
-		if (ioc->Request.Type.Direction == XFER_READ) {
-			/* Copy the data out of the buffer we created */
-			BYTE __user *ptr = ioc->buf;
-	        	for(i=0; i< sg_used; i++) {
-				if (copy_to_user(ptr, buff[i], buff_size[i])) {
-					cmd_free(host, c, 0);
-					status = -EFAULT;
-					goto cleanup1;
+				if (ioc->Request.Type.Direction == XFER_WRITE) {
+					if (copy_from_user
+					    (buff[sg_used], data_ptr, sz)) {
+						status = -ENOMEM;
+						goto cleanup1;
+					}
+				} else {
+					memset(buff[sg_used], 0, sz);
 				}
-				ptr += buff_size[i];
+				left -= sz;
+				data_ptr += sz;
+				sg_used++;
 			}
+			if ((c = cmd_alloc(host, 0)) == NULL) {
+				status = -ENOMEM;
+				goto cleanup1;
+			}
+			c->cmd_type = CMD_IOCTL_PEND;
+			c->Header.ReplyQueue = 0;
+
+			if (ioc->buf_size > 0) {
+				c->Header.SGList = sg_used;
+				c->Header.SGTotal = sg_used;
+			} else {
+				c->Header.SGList = 0;
+				c->Header.SGTotal = 0;
+			}
+			c->Header.LUN = ioc->LUN_info;
+			c->Header.Tag.lower = c->busaddr;
+
+			c->Request = ioc->Request;
+			if (ioc->buf_size > 0) {
+				int i;
+				for (i = 0; i < sg_used; i++) {
+					temp64.val =
+					    pci_map_single(host->pdev, buff[i],
+						    buff_size[i],
+						    PCI_DMA_BIDIRECTIONAL);
+					c->SG[i].Addr.lower =
+					    temp64.val32.lower;
+					c->SG[i].Addr.upper =
+					    temp64.val32.upper;
+					c->SG[i].Len = buff_size[i];
+					c->SG[i].Ext = 0;	/* we are not chaining */
+				}
+			}
+			c->waiting = &wait;
+			/* Put the request on the tail of the request queue */
+			spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+			addQ(&host->reqQ, c);
+			host->Qdepth++;
+			start_io(host);
+			spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+			wait_for_completion(&wait);
+			/* unlock the buffers from DMA */
+			for (i = 0; i < sg_used; i++) {
+				temp64.val32.lower = c->SG[i].Addr.lower;
+				temp64.val32.upper = c->SG[i].Addr.upper;
+				pci_unmap_single(host->pdev,
+					(dma_addr_t) temp64.val, buff_size[i],
+					PCI_DMA_BIDIRECTIONAL);
+			}
+			/* Copy the error information out */
+			ioc->error_info = *(c->err_info);
+			if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+				cmd_free(host, c, 0);
+				status = -EFAULT;
+				goto cleanup1;
+			}
+			if (ioc->Request.Type.Direction == XFER_READ) {
+				/* Copy the data out of the buffer we created */
+				BYTE __user *ptr = ioc->buf;
+				for (i = 0; i < sg_used; i++) {
+					if (copy_to_user
+					    (ptr, buff[i], buff_size[i])) {
+						cmd_free(host, c, 0);
+						status = -EFAULT;
+						goto cleanup1;
+					}
+					ptr += buff_size[i];
+				}
+			}
+			cmd_free(host, c, 0);
+			status = 0;
+		      cleanup1:
+			if (buff) {
+				for (i = 0; i < sg_used; i++)
+					kfree(buff[i]);
+				kfree(buff);
+			}
+			kfree(buff_size);
+			kfree(ioc);
+			return status;
 		}
-		cmd_free(host, c, 0);
-		status = 0;
-cleanup1:
-		if (buff) {
-			for(i=0; i<sg_used; i++)
-				kfree(buff[i]);
-			kfree(buff);
-		}
-		kfree(buff_size);
-		kfree(ioc);
-		return(status);
-	}
 	default:
 		return -ENOTTY;
 	}
-	
 }
 
 /*
@@ -1119,7 +1159,7 @@
  *
  * Right now I'm using the getgeometry() function to do this, but this
  * function should probably be finer grained and allow you to revalidate one
- * particualar logical volume (instead of all of them on a particular
+ * particular logical volume (instead of all of them on a particular
  * controller).
  */
 static int revalidate_allvol(ctlr_info_t *host)
@@ -1127,17 +1167,17 @@
 	int ctlr = host->ctlr, i;
 	unsigned long flags;
 
-        spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-        if (host->usage_count > 1) {
-                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-                printk(KERN_WARNING "cciss: Device busy for volume"
-                        " revalidation (usage=%d)\n", host->usage_count);
-                return -EBUSY;
-        }
-        host->usage_count++;
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	if (host->usage_count > 1) {
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+		printk(KERN_WARNING "cciss: Device busy for volume"
+		       " revalidation (usage=%d)\n", host->usage_count);
+		return -EBUSY;
+	}
+	host->usage_count++;
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
-	for(i=0; i< NWD; i++) {
+	for (i = 0; i < NWD; i++) {
 		struct gendisk *disk = host->gendisk[i];
 		if (disk) {
 			request_queue_t *q = disk->queue;
@@ -1149,22 +1189,22 @@
 		}
 	}
 
-        /*
-         * Set the partition and block size structures for all volumes
-         * on this controller to zero.  We will reread all of this data
-         */
-        memset(host->drv,        0, sizeof(drive_info_struct)
-						* CISS_MAX_LUN);
-        /*
-         * Tell the array controller not to give us any interrupts while
-         * we check the new geometry.  Then turn interrupts back on when
-         * we're done.
-         */
-        host->access.set_intr_mask(host, CCISS_INTR_OFF);
-        cciss_getgeometry(ctlr);
-        host->access.set_intr_mask(host, CCISS_INTR_ON);
+	/*
+	 * Set the partition and block size structures for all volumes
+	 * on this controller to zero.  We will reread all of this data
+	 */
+	memset(host->drv, 0, sizeof(drive_info_struct)
+	       * CISS_MAX_LUN);
+	/*
+	 * Tell the array controller not to give us any interrupts while
+	 * we check the new geometry.  Then turn interrupts back on when
+	 * we're done.
+	 */
+	host->access.set_intr_mask(host, CCISS_INTR_OFF);
+	cciss_getgeometry(ctlr);
+	host->access.set_intr_mask(host, CCISS_INTR_ON);
 
-	/* Loop through each real device */ 
+	/* Loop through each real device */
 	for (i = 0; i < NWD; i++) {
 		struct gendisk *disk = host->gendisk[i];
 		drive_info_struct *drv = &(host->drv[i]);
@@ -1176,8 +1216,8 @@
 		set_capacity(disk, drv->nr_blocks);
 		add_disk(disk);
 	}
-        host->usage_count--;
-        return 0;
+	host->usage_count--;
+	return 0;
 }
 
 static inline void complete_buffers(struct bio *bio, int status)
@@ -1191,7 +1231,6 @@
 		bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
 		bio = xbh;
 	}
-
 }
 
 static void cciss_softirq_done(struct request *rq)
@@ -1209,7 +1248,7 @@
 
 	/* command did not need to be retried */
 	/* unmap the DMA mapping for all the scatter gather elements */
-	for(i=0; i<cmd->Header.SGList; i++) {
+	for (i = 0; i < cmd->Header.SGList; i++) {
 		temp64.val32.lower = cmd->SG[i].Addr.lower;
 		temp64.val32.upper = cmd->SG[i].Addr.upper;
 		pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
@@ -1219,11 +1258,12 @@
 
 #ifdef CCISS_DEBUG
 	printk("Done with %p\n", rq);
-#endif /* CCISS_DEBUG */
+#endif				/* CCISS_DEBUG */
 
+	add_disk_randomness(rq->rq_disk);
 	spin_lock_irqsave(&h->lock, flags);
 	end_that_request_last(rq, rq->errors);
-	cmd_free(h, cmd,1);
+	cmd_free(h, cmd, 1);
 	spin_unlock_irqrestore(&h->lock, flags);
 }
 
@@ -1234,9 +1274,9 @@
  * will always be left registered with the kernel since it is also the
  * controller node.  Any changes to disk 0 will show up on the next
  * reboot.
-*/
+ */
 static void cciss_update_drive_info(int ctlr, int drv_index)
-  {
+{
 	ctlr_info_t *h = hba[ctlr];
 	struct gendisk *disk;
 	ReadCapdata_struct *size_buff = NULL;
@@ -1246,13 +1286,13 @@
 	unsigned long flags = 0;
 	int ret = 0;
 
-	/* if the disk already exists then deregister it before proceeding*/
-	if (h->drv[drv_index].raid_level != -1){
+	/* if the disk already exists then deregister it before proceeding */
+	if (h->drv[drv_index].raid_level != -1) {
 		spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
 		h->drv[drv_index].busy_configuring = 1;
 		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 		ret = deregister_disk(h->gendisk[drv_index],
-			&h->drv[drv_index], 0);
+				      &h->drv[drv_index], 0);
 		h->drv[drv_index].busy_configuring = 0;
 	}
 
@@ -1260,27 +1300,25 @@
 	if (ret)
 		return;
 
-
-	/* Get information about the disk and modify the driver sturcture */
-	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
+	/* Get information about the disk and modify the driver structure */
+	size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL)
 		goto mem_msg;
-	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
 	if (inq_buff == NULL)
 		goto mem_msg;
 
 	cciss_read_capacity(ctlr, drv_index, size_buff, 1,
-		&total_size, &block_size);
+			    &total_size, &block_size);
 	cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
-		inq_buff, &h->drv[drv_index]);
+			       inq_buff, &h->drv[drv_index]);
 
 	++h->num_luns;
 	disk = h->gendisk[drv_index];
 	set_capacity(disk, h->drv[drv_index].nr_blocks);
 
-
 	/* if it's the controller it's already added */
-	if (drv_index){
+	if (drv_index) {
 		disk->queue = blk_init_queue(do_cciss_request, &h->lock);
 
 		/* Set up queue information */
@@ -1300,17 +1338,17 @@
 		disk->queue->queuedata = hba[ctlr];
 
 		blk_queue_hardsect_size(disk->queue,
-			hba[ctlr]->drv[drv_index].block_size);
+					hba[ctlr]->drv[drv_index].block_size);
 
 		h->drv[drv_index].queue = disk->queue;
 		add_disk(disk);
 	}
 
-freeret:
+      freeret:
 	kfree(size_buff);
 	kfree(inq_buff);
 	return;
-mem_msg:
+      mem_msg:
 	printk(KERN_ERR "cciss: out of memory\n");
 	goto freeret;
 }
@@ -1320,13 +1358,13 @@
  * where new drives will be added.  If the index to be returned is greater
  * than the highest_lun index for the controller then highest_lun is set
  * to this new index.  If there are no available indexes then -1 is returned.
-*/
+ */
 static int cciss_find_free_drive_index(int ctlr)
 {
 	int i;
 
-	for (i=0; i < CISS_MAX_LUN; i++){
-		if (hba[ctlr]->drv[i].raid_level == -1){
+	for (i = 0; i < CISS_MAX_LUN; i++) {
+		if (hba[ctlr]->drv[i].raid_level == -1) {
 			if (i > hba[ctlr]->highest_lun)
 				hba[ctlr]->highest_lun = i;
 			return i;
@@ -1336,7 +1374,7 @@
 }
 
 /* This function will add and remove logical drives from the Logical
- * drive array of the controller and maintain persistancy of ordering
+ * drive array of the controller and maintain persistency of ordering
  * so that mount points are preserved until the next reboot.  This allows
  * for the removal of logical drives in the middle of the drive array
  * without a re-ordering of those drives.
@@ -1344,7 +1382,7 @@
  * h		= The controller to perform the operations on
  * del_disk	= The disk to remove if specified.  If the value given
  *		  is NULL then no disk is removed.
-*/
+ */
 static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
 {
 	int ctlr = h->ctlr;
@@ -1361,12 +1399,12 @@
 
 	/* Set busy_configuring flag for this operation */
 	spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-	if (h->num_luns >= CISS_MAX_LUN){
+	if (h->num_luns >= CISS_MAX_LUN) {
 		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 		return -EINVAL;
 	}
 
-	if (h->busy_configuring){
+	if (h->busy_configuring) {
 		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 		return -EBUSY;
 	}
@@ -1376,7 +1414,7 @@
 	 * and update the logical drive table.  If it is not NULL then
 	 * we will check if the disk is in use or not.
 	 */
-	if (del_disk != NULL){
+	if (del_disk != NULL) {
 		drv = get_drv(del_disk);
 		drv->busy_configuring = 1;
 		spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
@@ -1394,61 +1432,67 @@
 			goto mem_msg;
 
 		return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
-				sizeof(ReportLunData_struct), 0, 0, 0,
-				TYPE_CMD);
+					      sizeof(ReportLunData_struct), 0,
+					      0, 0, TYPE_CMD);
 
-		if (return_code == IO_OK){
-			listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
-			listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
-			listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
-			listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-		} else{ /* reading number of logical volumes failed */
+		if (return_code == IO_OK) {
+			listlength |=
+			    (0xff & (unsigned int)(ld_buff->LUNListLength[0]))
+			    << 24;
+			listlength |=
+			    (0xff & (unsigned int)(ld_buff->LUNListLength[1]))
+			    << 16;
+			listlength |=
+			    (0xff & (unsigned int)(ld_buff->LUNListLength[2]))
+			    << 8;
+			listlength |=
+			    0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+		} else {	/* reading number of logical volumes failed */
 			printk(KERN_WARNING "cciss: report logical volume"
-				" command failed\n");
+			       " command failed\n");
 			listlength = 0;
 			goto freeret;
 		}
 
 		num_luns = listlength / 8;	/* 8 bytes per entry */
-		if (num_luns > CISS_MAX_LUN){
+		if (num_luns > CISS_MAX_LUN) {
 			num_luns = CISS_MAX_LUN;
 			printk(KERN_WARNING "cciss: more luns configured"
-				" on controller than can be handled by"
-				" this driver.\n");
+			       " on controller than can be handled by"
+			       " this driver.\n");
 		}
 
 		/* Compare controller drive array to drivers drive array.
-	 	* Check for updates in the drive information and any new drives
-	 	* on the controller.
-	 	*/
-		for (i=0; i < num_luns; i++){
+		 * Check for updates in the drive information and any new drives
+		 * on the controller.
+		 */
+		for (i = 0; i < num_luns; i++) {
 			int j;
 
 			drv_found = 0;
 
-	  		lunid = (0xff &
-				(unsigned int)(ld_buff->LUN[i][3])) << 24;
-        		lunid |= (0xff &
-				(unsigned int)(ld_buff->LUN[i][2])) << 16;
-        		lunid |= (0xff &
-				(unsigned int)(ld_buff->LUN[i][1])) << 8;
-        		lunid |= 0xff &
-				(unsigned int)(ld_buff->LUN[i][0]);
+			lunid = (0xff &
+				 (unsigned int)(ld_buff->LUN[i][3])) << 24;
+			lunid |= (0xff &
+				  (unsigned int)(ld_buff->LUN[i][2])) << 16;
+			lunid |= (0xff &
+				  (unsigned int)(ld_buff->LUN[i][1])) << 8;
+			lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
 
 			/* Find if the LUN is already in the drive array
 			 * of the controller.  If so then update its info
 			 * if not is use.  If it does not exist then find
 			 * the first free index and add it.
-			*/
-			for (j=0; j <= h->highest_lun; j++){
-				if (h->drv[j].LunID == lunid){
+			 */
+			for (j = 0; j <= h->highest_lun; j++) {
+				if (h->drv[j].LunID == lunid) {
 					drv_index = j;
 					drv_found = 1;
 				}
 			}
 
 			/* check if the drive was found already in the array */
-			if (!drv_found){
+			if (!drv_found) {
 				drv_index = cciss_find_free_drive_index(ctlr);
 				if (drv_index == -1)
 					goto freeret;
@@ -1456,18 +1500,18 @@
 			}
 			h->drv[drv_index].LunID = lunid;
 			cciss_update_drive_info(ctlr, drv_index);
-		} /* end for */
-	} /* end else */
+		}		/* end for */
+	}			/* end else */
 
-freeret:
+      freeret:
 	kfree(ld_buff);
 	h->busy_configuring = 0;
 	/* We return -1 here to tell the ACU that we have registered/updated
 	 * all of the drives that we can and to keep it from calling us
 	 * additional times.
-	*/
+	 */
 	return -1;
-mem_msg:
+      mem_msg:
 	printk(KERN_ERR "cciss: out of memory\n");
 	goto freeret;
 }
@@ -1483,7 +1527,7 @@
  * clear_all = This flag determines whether or not the disk information
  *             is going to be completely cleared out and the highest_lun
  *             reset.  Sometimes we want to clear out information about
- *             the disk in preperation for re-adding it.  In this case
+ *             the disk in preparation for re-adding it.  In this case
  *             the highest_lun should be left unchanged and the LunID
  *             should not be cleared.
 */
@@ -1496,19 +1540,17 @@
 		return -EPERM;
 
 	/* make sure logical volume is NOT is use */
-	if(clear_all || (h->gendisk[0] == disk)) {
-	if (drv->usage_count > 1)
-                return -EBUSY;
-	}
-        else
-        	if( drv->usage_count > 0 )
-                	return -EBUSY;
+	if (clear_all || (h->gendisk[0] == disk)) {
+		if (drv->usage_count > 1)
+			return -EBUSY;
+	} else if (drv->usage_count > 0)
+		return -EBUSY;
 
 	/* invalidate the devices and deregister the disk.  If it is disk
 	 * zero do not deregister it but just zero out it's values.  This
 	 * allows us to delete disk zero but keep the controller registered.
-	*/
-	if (h->gendisk[0] != disk){
+	 */
+	if (h->gendisk[0] != disk) {
 		if (disk) {
 			request_queue_t *q = disk->queue;
 			if (disk->flags & GENHD_FL_UP)
@@ -1530,91 +1572,90 @@
 	drv->raid_level = -1;	/* This can be used as a flag variable to
 				 * indicate that this element of the drive
 				 * array is free.
-				*/
+				 */
 
-	if (clear_all){
-	/* check to see if it was the last disk */
-	if (drv == h->drv + h->highest_lun) {
-		/* if so, find the new hightest lun */
-		int i, newhighest =-1;
-		for(i=0; i<h->highest_lun; i++) {
-			/* if the disk has size > 0, it is available */
+	if (clear_all) {
+		/* check to see if it was the last disk */
+		if (drv == h->drv + h->highest_lun) {
+			/* if so, find the new hightest lun */
+			int i, newhighest = -1;
+			for (i = 0; i < h->highest_lun; i++) {
+				/* if the disk has size > 0, it is available */
 				if (h->drv[i].heads)
-				newhighest = i;
+					newhighest = i;
+			}
+			h->highest_lun = newhighest;
 		}
-		h->highest_lun = newhighest;
-	}
 
-	drv->LunID = 0;
+		drv->LunID = 0;
 	}
-	return(0);
+	return 0;
 }
 
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
-	size_t size,
-	unsigned int use_unit_num, /* 0: address the controller,
-				      1: address logical volume log_unit,
-				      2: periph device address is scsi3addr */
-	unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr,
-	int cmd_type)
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num,	/* 0: address the controller,
+															   1: address logical volume log_unit,
+															   2: periph device address is scsi3addr */
+		    unsigned int log_unit, __u8 page_code,
+		    unsigned char *scsi3addr, int cmd_type)
 {
-	ctlr_info_t *h= hba[ctlr];
+	ctlr_info_t *h = hba[ctlr];
 	u64bit buff_dma_handle;
 	int status = IO_OK;
 
 	c->cmd_type = CMD_IOCTL_PEND;
 	c->Header.ReplyQueue = 0;
-	if( buff != NULL) {
+	if (buff != NULL) {
 		c->Header.SGList = 1;
-		c->Header.SGTotal= 1;
+		c->Header.SGTotal = 1;
 	} else {
 		c->Header.SGList = 0;
-                c->Header.SGTotal= 0;
+		c->Header.SGTotal = 0;
 	}
 	c->Header.Tag.lower = c->busaddr;
 
 	c->Request.Type.Type = cmd_type;
 	if (cmd_type == TYPE_CMD) {
-		switch(cmd) {
-		case  CISS_INQUIRY:
+		switch (cmd) {
+		case CISS_INQUIRY:
 			/* If the logical unit number is 0 then, this is going
-			to controller so It's a physical command
-			mode = 0 target = 0.  So we have nothing to write.
-			otherwise, if use_unit_num == 1,
-			mode = 1(volume set addressing) target = LUNID
-			otherwise, if use_unit_num == 2,
-			mode = 0(periph dev addr) target = scsi3addr */
+			   to controller so It's a physical command
+			   mode = 0 target = 0.  So we have nothing to write.
+			   otherwise, if use_unit_num == 1,
+			   mode = 1(volume set addressing) target = LUNID
+			   otherwise, if use_unit_num == 2,
+			   mode = 0(periph dev addr) target = scsi3addr */
 			if (use_unit_num == 1) {
-				c->Header.LUN.LogDev.VolId=
-					h->drv[log_unit].LunID;
-                        	c->Header.LUN.LogDev.Mode = 1;
+				c->Header.LUN.LogDev.VolId =
+				    h->drv[log_unit].LunID;
+				c->Header.LUN.LogDev.Mode = 1;
 			} else if (use_unit_num == 2) {
-				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+				memcpy(c->Header.LUN.LunAddrBytes, scsi3addr,
+				       8);
 				c->Header.LUN.LogDev.Mode = 0;
 			}
 			/* are we trying to read a vital product page */
-			if(page_code != 0) {
+			if (page_code != 0) {
 				c->Request.CDB[1] = 0x01;
 				c->Request.CDB[2] = page_code;
 			}
 			c->Request.CDBLen = 6;
-			c->Request.Type.Attribute = ATTR_SIMPLE;  
+			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_READ;
 			c->Request.Timeout = 0;
-			c->Request.CDB[0] =  CISS_INQUIRY;
-			c->Request.CDB[4] = size  & 0xFF;  
-		break;
+			c->Request.CDB[0] = CISS_INQUIRY;
+			c->Request.CDB[4] = size & 0xFF;
+			break;
 		case CISS_REPORT_LOG:
 		case CISS_REPORT_PHYS:
-                        /* Talking to controller so It's a physical command
+			/* Talking to controller so It's a physical command
 			   mode = 00 target = 0.  Nothing to write.
-                        */
+			 */
 			c->Request.CDBLen = 12;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_READ;
 			c->Request.Timeout = 0;
 			c->Request.CDB[0] = cmd;
-			c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+			c->Request.CDB[6] = (size >> 24) & 0xFF;	//MSB
 			c->Request.CDB[7] = (size >> 16) & 0xFF;
 			c->Request.CDB[8] = (size >> 8) & 0xFF;
 			c->Request.CDB[9] = size & 0xFF;
@@ -1628,7 +1669,7 @@
 			c->Request.Type.Direction = XFER_READ;
 			c->Request.Timeout = 0;
 			c->Request.CDB[0] = cmd;
-		break;
+			break;
 		case CCISS_CACHE_FLUSH:
 			c->Request.CDBLen = 12;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1636,32 +1677,32 @@
 			c->Request.Timeout = 0;
 			c->Request.CDB[0] = BMIC_WRITE;
 			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
-		break;
+			break;
 		default:
 			printk(KERN_WARNING
-				"cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
-			return(IO_ERROR);
+			       "cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
+			return IO_ERROR;
 		}
 	} else if (cmd_type == TYPE_MSG) {
 		switch (cmd) {
-		case 0: /* ABORT message */
+		case 0:	/* ABORT message */
 			c->Request.CDBLen = 12;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_WRITE;
 			c->Request.Timeout = 0;
-			c->Request.CDB[0] = cmd; /* abort */
-			c->Request.CDB[1] = 0;   /* abort a command */
+			c->Request.CDB[0] = cmd;	/* abort */
+			c->Request.CDB[1] = 0;	/* abort a command */
 			/* buff contains the tag of the command to abort */
 			memcpy(&c->Request.CDB[4], buff, 8);
 			break;
-		case 1: /* RESET message */
+		case 1:	/* RESET message */
 			c->Request.CDBLen = 12;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
 			c->Request.Type.Direction = XFER_WRITE;
 			c->Request.Timeout = 0;
 			memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
-			c->Request.CDB[0] = cmd;  /* reset */
-			c->Request.CDB[1] = 0x04; /* reset a LUN */
+			c->Request.CDB[0] = cmd;	/* reset */
+			c->Request.CDB[1] = 0x04;	/* reset a LUN */
 		case 3:	/* No-Op message */
 			c->Request.CDBLen = 1;
 			c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1671,168 +1712,164 @@
 			break;
 		default:
 			printk(KERN_WARNING
-				"cciss%d: unknown message type %d\n",
-				ctlr, cmd);
+			       "cciss%d: unknown message type %d\n", ctlr, cmd);
 			return IO_ERROR;
 		}
 	} else {
 		printk(KERN_WARNING
-			"cciss%d: unknown command type %d\n", ctlr, cmd_type);
+		       "cciss%d: unknown command type %d\n", ctlr, cmd_type);
 		return IO_ERROR;
 	}
 	/* Fill in the scatter gather information */
 	if (size > 0) {
 		buff_dma_handle.val = (__u64) pci_map_single(h->pdev,
-			buff, size, PCI_DMA_BIDIRECTIONAL);
+							     buff, size,
+							     PCI_DMA_BIDIRECTIONAL);
 		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
 		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
 		c->SG[0].Len = size;
-		c->SG[0].Ext = 0;  /* we are not chaining */
+		c->SG[0].Ext = 0;	/* we are not chaining */
 	}
 	return status;
 }
-static int sendcmd_withirq(__u8	cmd,
-	int	ctlr,
-	void	*buff,
-	size_t	size,
-	unsigned int use_unit_num,
-	unsigned int log_unit,
-	__u8	page_code,
-	int cmd_type)
+
+static int sendcmd_withirq(__u8 cmd,
+			   int ctlr,
+			   void *buff,
+			   size_t size,
+			   unsigned int use_unit_num,
+			   unsigned int log_unit, __u8 page_code, int cmd_type)
 {
 	ctlr_info_t *h = hba[ctlr];
 	CommandList_struct *c;
-	u64bit	buff_dma_handle;
+	u64bit buff_dma_handle;
 	unsigned long flags;
 	int return_status;
 	DECLARE_COMPLETION(wait);
-	
-	if ((c = cmd_alloc(h , 0)) == NULL)
+
+	if ((c = cmd_alloc(h, 0)) == NULL)
 		return -ENOMEM;
 	return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
-		log_unit, page_code, NULL, cmd_type);
+				 log_unit, page_code, NULL, cmd_type);
 	if (return_status != IO_OK) {
 		cmd_free(h, c, 0);
 		return return_status;
 	}
-resend_cmd2:
+      resend_cmd2:
 	c->waiting = &wait;
-	
+
 	/* Put the request on the tail of the queue and send it */
 	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 	addQ(&h->reqQ, c);
 	h->Qdepth++;
 	start_io(h);
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-	
+
 	wait_for_completion(&wait);
 
-	if(c->err_info->CommandStatus != 0) 
-	{ /* an error has occurred */ 
-		switch(c->err_info->CommandStatus)
-		{
-			case CMD_TARGET_STATUS:
-				printk(KERN_WARNING "cciss: cmd %p has "
-					" completed with errors\n", c);
-				if( c->err_info->ScsiStatus)
-                		{
-                    			printk(KERN_WARNING "cciss: cmd %p "
-					"has SCSI Status = %x\n",
-                        			c,  
-						c->err_info->ScsiStatus);
-                		}
+	if (c->err_info->CommandStatus != 0) {	/* an error has occurred */
+		switch (c->err_info->CommandStatus) {
+		case CMD_TARGET_STATUS:
+			printk(KERN_WARNING "cciss: cmd %p has "
+			       " completed with errors\n", c);
+			if (c->err_info->ScsiStatus) {
+				printk(KERN_WARNING "cciss: cmd %p "
+				       "has SCSI Status = %x\n",
+				       c, c->err_info->ScsiStatus);
+			}
 
 			break;
-			case CMD_DATA_UNDERRUN:
-			case CMD_DATA_OVERRUN:
+		case CMD_DATA_UNDERRUN:
+		case CMD_DATA_OVERRUN:
 			/* expected for inquire and report lun commands */
 			break;
-			case CMD_INVALID:
-				printk(KERN_WARNING "cciss: Cmd %p is "
-					"reported invalid\n", c);
-				return_status = IO_ERROR;
+		case CMD_INVALID:
+			printk(KERN_WARNING "cciss: Cmd %p is "
+			       "reported invalid\n", c);
+			return_status = IO_ERROR;
 			break;
-			case CMD_PROTOCOL_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p has "
-					"protocol error \n", c);
-                                return_status = IO_ERROR;
-                        break;
-case CMD_HARDWARE_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p had " 
-                                        " hardware error\n", c);
-                                return_status = IO_ERROR;
-                        break;
-			case CMD_CONNECTION_LOST:
-				printk(KERN_WARNING "cciss: cmd %p had "
-					"connection lost\n", c);
-				return_status = IO_ERROR;
+		case CMD_PROTOCOL_ERR:
+			printk(KERN_WARNING "cciss: cmd %p has "
+			       "protocol error \n", c);
+			return_status = IO_ERROR;
 			break;
-			case CMD_ABORTED:
-				printk(KERN_WARNING "cciss: cmd %p was "
-					"aborted\n", c);
-				return_status = IO_ERROR;
+		case CMD_HARDWARE_ERR:
+			printk(KERN_WARNING "cciss: cmd %p had "
+			       " hardware error\n", c);
+			return_status = IO_ERROR;
 			break;
-			case CMD_ABORT_FAILED:
-				printk(KERN_WARNING "cciss: cmd %p reports "
-					"abort failed\n", c);
-				return_status = IO_ERROR;
+		case CMD_CONNECTION_LOST:
+			printk(KERN_WARNING "cciss: cmd %p had "
+			       "connection lost\n", c);
+			return_status = IO_ERROR;
 			break;
-			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING 
-					"cciss%d: unsolicited abort %p\n",
-					ctlr, c);
-				if (c->retry_count < MAX_CMD_RETRIES) {
-					printk(KERN_WARNING 
-						"cciss%d: retrying %p\n", 
-						ctlr, c);
-					c->retry_count++;
-					/* erase the old error information */
-					memset(c->err_info, 0,
-						sizeof(ErrorInfo_struct));
-					return_status = IO_OK;
-					INIT_COMPLETION(wait);
-					goto resend_cmd2;
-				}
-				return_status = IO_ERROR;
+		case CMD_ABORTED:
+			printk(KERN_WARNING "cciss: cmd %p was "
+			       "aborted\n", c);
+			return_status = IO_ERROR;
 			break;
-			default:
-				printk(KERN_WARNING "cciss: cmd %p returned "
-					"unknown status %x\n", c, 
-						c->err_info->CommandStatus); 
-				return_status = IO_ERROR;
+		case CMD_ABORT_FAILED:
+			printk(KERN_WARNING "cciss: cmd %p reports "
+			       "abort failed\n", c);
+			return_status = IO_ERROR;
+			break;
+		case CMD_UNSOLICITED_ABORT:
+			printk(KERN_WARNING
+			       "cciss%d: unsolicited abort %p\n", ctlr, c);
+			if (c->retry_count < MAX_CMD_RETRIES) {
+				printk(KERN_WARNING
+				       "cciss%d: retrying %p\n", ctlr, c);
+				c->retry_count++;
+				/* erase the old error information */
+				memset(c->err_info, 0,
+				       sizeof(ErrorInfo_struct));
+				return_status = IO_OK;
+				INIT_COMPLETION(wait);
+				goto resend_cmd2;
+			}
+			return_status = IO_ERROR;
+			break;
+		default:
+			printk(KERN_WARNING "cciss: cmd %p returned "
+			       "unknown status %x\n", c,
+			       c->err_info->CommandStatus);
+			return_status = IO_ERROR;
 		}
-	}	
+	}
 	/* unlock the buffers from DMA */
 	buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
 	buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
-	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
-			c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+	pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
+			 c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(h, c, 0);
-        return(return_status);
-
+	return return_status;
 }
+
 static void cciss_geometry_inquiry(int ctlr, int logvol,
-			int withirq, unsigned int total_size,
-			unsigned int block_size, InquiryData_struct *inq_buff,
-			drive_info_struct *drv)
+				   int withirq, unsigned int total_size,
+				   unsigned int block_size,
+				   InquiryData_struct *inq_buff,
+				   drive_info_struct *drv)
 {
 	int return_code;
 	memset(inq_buff, 0, sizeof(InquiryData_struct));
 	if (withirq)
 		return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
-			inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD);
+					      inq_buff, sizeof(*inq_buff), 1,
+					      logvol, 0xC1, TYPE_CMD);
 	else
 		return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
-			sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD);
+				      sizeof(*inq_buff), 1, logvol, 0xC1, NULL,
+				      TYPE_CMD);
 	if (return_code == IO_OK) {
-		if(inq_buff->data_byte[8] == 0xFF) {
+		if (inq_buff->data_byte[8] == 0xFF) {
 			printk(KERN_WARNING
-				"cciss: reading geometry failed, volume "
-				"does not support reading geometry\n");
+			       "cciss: reading geometry failed, volume "
+			       "does not support reading geometry\n");
 			drv->block_size = block_size;
 			drv->nr_blocks = total_size;
 			drv->heads = 255;
-			drv->sectors = 32; // Sectors per track
+			drv->sectors = 32;	// Sectors per track
 			drv->cylinders = total_size / 255 / 32;
 		} else {
 			unsigned int t;
@@ -1846,37 +1883,42 @@
 			drv->raid_level = inq_buff->data_byte[8];
 			t = drv->heads * drv->sectors;
 			if (t > 1) {
-				drv->cylinders = total_size/t;
+				drv->cylinders = total_size / t;
 			}
 		}
-	} else { /* Get geometry failed */
+	} else {		/* Get geometry failed */
 		printk(KERN_WARNING "cciss: reading geometry failed\n");
 	}
 	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
-		drv->heads, drv->sectors, drv->cylinders);
+	       drv->heads, drv->sectors, drv->cylinders);
 }
+
 static void
 cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
-		int withirq, unsigned int *total_size, unsigned int *block_size)
+		    int withirq, unsigned int *total_size,
+		    unsigned int *block_size)
 {
 	int return_code;
 	memset(buf, 0, sizeof(*buf));
 	if (withirq)
 		return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
-			ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD);
+					      ctlr, buf, sizeof(*buf), 1,
+					      logvol, 0, TYPE_CMD);
 	else
 		return_code = sendcmd(CCISS_READ_CAPACITY,
-			ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);
+				      ctlr, buf, sizeof(*buf), 1, logvol, 0,
+				      NULL, TYPE_CMD);
 	if (return_code == IO_OK) {
-		*total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1;
-		*block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0]));
-	} else { /* read capacity command failed */
+		*total_size =
+		    be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
+		*block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
+	} else {		/* read capacity command failed */
 		printk(KERN_WARNING "cciss: read capacity failed\n");
 		*total_size = 0;
 		*block_size = BLOCK_SIZE;
 	}
 	printk(KERN_INFO "      blocks= %u block_size= %d\n",
-		*total_size, *block_size);
+	       *total_size, *block_size);
 	return;
 }
 
@@ -1885,38 +1927,38 @@
 	ctlr_info_t *h = get_host(disk);
 	drive_info_struct *drv = get_drv(disk);
 	int logvol;
-	int FOUND=0;
+	int FOUND = 0;
 	unsigned int block_size;
 	unsigned int total_size;
 	ReadCapdata_struct *size_buff = NULL;
 	InquiryData_struct *inq_buff = NULL;
 
-	for(logvol=0; logvol < CISS_MAX_LUN; logvol++)
-	{
-		if(h->drv[logvol].LunID == drv->LunID) {
-			FOUND=1;
+	for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+		if (h->drv[logvol].LunID == drv->LunID) {
+			FOUND = 1;
 			break;
 		}
 	}
 
-	if (!FOUND) return 1;
+	if (!FOUND)
+		return 1;
 
-	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
-                printk(KERN_WARNING "cciss: out of memory\n");
-                return 1;
-        }
-	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
-                printk(KERN_WARNING "cciss: out of memory\n");
+	size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_WARNING "cciss: out of memory\n");
+		return 1;
+	}
+	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_WARNING "cciss: out of memory\n");
 		kfree(size_buff);
-                return 1;
-        }
+		return 1;
+	}
 
-	cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size);
-	cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv);
+	cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
+			    &block_size);
+	cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
+			       inq_buff, drv);
 
 	blk_queue_hardsect_size(drv->queue, drv->block_size);
 	set_capacity(disk, drv->nr_blocks);
@@ -1943,7 +1985,7 @@
 		if (done == FIFO_EMPTY)
 			schedule_timeout_uninterruptible(1);
 		else
-			return (done);
+			return done;
 	}
 	/* Invalid address to tell caller we ran out of time */
 	return 1;
@@ -1952,28 +1994,28 @@
 static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
 {
 	/* We get in here if sendcmd() is polling for completions
-	   and gets some command back that it wasn't expecting -- 
-	   something other than that which it just sent down.  
-	   Ordinarily, that shouldn't happen, but it can happen when 
+	   and gets some command back that it wasn't expecting --
+	   something other than that which it just sent down.
+	   Ordinarily, that shouldn't happen, but it can happen when
 	   the scsi tape stuff gets into error handling mode, and
-	   starts using sendcmd() to try to abort commands and 
+	   starts using sendcmd() to try to abort commands and
 	   reset tape drives.  In that case, sendcmd may pick up
 	   completions of commands that were sent to logical drives
-	   through the block i/o system, or cciss ioctls completing, etc. 
+	   through the block i/o system, or cciss ioctls completing, etc.
 	   In that case, we need to save those completions for later
 	   processing by the interrupt handler.
-	*/
+	 */
 
 #ifdef CONFIG_CISS_SCSI_TAPE
-	struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;	
+	struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
 
 	/* If it's not the scsi tape stuff doing error handling, (abort */
 	/* or reset) then we don't expect anything weird. */
 	if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
 #endif
-		printk( KERN_WARNING "cciss cciss%d: SendCmd "
-		      "Invalid command list address returned! (%lx)\n",
-			ctlr, complete);
+		printk(KERN_WARNING "cciss cciss%d: SendCmd "
+		       "Invalid command list address returned! (%lx)\n",
+		       ctlr, complete);
 		/* not much we can do. */
 #ifdef CONFIG_CISS_SCSI_TAPE
 		return 1;
@@ -1984,7 +2026,7 @@
 	if (srl->ncompletions >= (NR_CMDS + 2)) {
 		/* Uh oh.  No room to save it for later... */
 		printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
-			"reject list overflow, command lost!\n", ctlr);
+		       "reject list overflow, command lost!\n", ctlr);
 		return 1;
 	}
 	/* Save it for later */
@@ -1995,340 +2037,327 @@
 }
 
 /*
- * Send a command to the controller, and wait for it to complete.  
- * Only used at init time. 
+ * Send a command to the controller, and wait for it to complete.
+ * Only used at init time.
  */
-static int sendcmd(
-	__u8	cmd,
-	int	ctlr,
-	void	*buff,
-	size_t	size,
-	unsigned int use_unit_num, /* 0: address the controller,
-				      1: address logical volume log_unit, 
-				      2: periph device address is scsi3addr */
-	unsigned int log_unit,
-	__u8	page_code,
-	unsigned char *scsi3addr,
-	int cmd_type)
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num,	/* 0: address the controller,
+												   1: address logical volume log_unit,
+												   2: periph device address is scsi3addr */
+		   unsigned int log_unit,
+		   __u8 page_code, unsigned char *scsi3addr, int cmd_type)
 {
 	CommandList_struct *c;
 	int i;
 	unsigned long complete;
-	ctlr_info_t *info_p= hba[ctlr];
+	ctlr_info_t *info_p = hba[ctlr];
 	u64bit buff_dma_handle;
 	int status, done = 0;
 
 	if ((c = cmd_alloc(info_p, 1)) == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
-		return(IO_ERROR);
+		return IO_ERROR;
 	}
 	status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
-		log_unit, page_code, scsi3addr, cmd_type);
+			  log_unit, page_code, scsi3addr, cmd_type);
 	if (status != IO_OK) {
 		cmd_free(info_p, c, 1);
 		return status;
 	}
-resend_cmd1:
+      resend_cmd1:
 	/*
-         * Disable interrupt
-         */
+	 * Disable interrupt
+	 */
 #ifdef CCISS_DEBUG
 	printk(KERN_DEBUG "cciss: turning intr off\n");
-#endif /* CCISS_DEBUG */ 
-        info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
-	
+#endif				/* CCISS_DEBUG */
+	info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
+
 	/* Make sure there is room in the command FIFO */
-        /* Actually it should be completely empty at this time */
+	/* Actually it should be completely empty at this time */
 	/* unless we are in here doing error handling for the scsi */
 	/* tape side of the driver. */
-        for (i = 200000; i > 0; i--) 
-	{
+	for (i = 200000; i > 0; i--) {
 		/* if fifo isn't full go */
-                if (!(info_p->access.fifo_full(info_p))) 
-		{
-			
-                        break;
-                }
-                udelay(10);
-                printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
-                        " waiting!\n", ctlr);
-        }
-        /*
-         * Send the cmd
-         */
-        info_p->access.submit_command(info_p, c);
+		if (!(info_p->access.fifo_full(info_p))) {
+
+			break;
+		}
+		udelay(10);
+		printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
+		       " waiting!\n", ctlr);
+	}
+	/*
+	 * Send the cmd
+	 */
+	info_p->access.submit_command(info_p, c);
 	done = 0;
 	do {
 		complete = pollcomplete(ctlr);
 
 #ifdef CCISS_DEBUG
 		printk(KERN_DEBUG "cciss: command completed\n");
-#endif /* CCISS_DEBUG */
+#endif				/* CCISS_DEBUG */
 
 		if (complete == 1) {
-			printk( KERN_WARNING
-				"cciss cciss%d: SendCmd Timeout out, "
-				"No command list address returned!\n",
-				ctlr);
+			printk(KERN_WARNING
+			       "cciss cciss%d: SendCmd Timeout out, "
+			       "No command list address returned!\n", ctlr);
 			status = IO_ERROR;
 			done = 1;
 			break;
 		}
 
 		/* This will need to change for direct lookup completions */
-		if ( (complete & CISS_ERROR_BIT)
-		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
-		     {
-			/* if data overrun or underun on Report command 
-				ignore it 
-			*/
+		if ((complete & CISS_ERROR_BIT)
+		    && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
+			/* if data overrun or underun on Report command
+			   ignore it
+			 */
 			if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
 			     (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
 			     (c->Request.CDB[0] == CISS_INQUIRY)) &&
-				((c->err_info->CommandStatus == 
-					CMD_DATA_OVERRUN) || 
-				 (c->err_info->CommandStatus == 
-					CMD_DATA_UNDERRUN)
-			 	))
-			{
+			    ((c->err_info->CommandStatus ==
+			      CMD_DATA_OVERRUN) ||
+			     (c->err_info->CommandStatus == CMD_DATA_UNDERRUN)
+			    )) {
 				complete = c->busaddr;
 			} else {
 				if (c->err_info->CommandStatus ==
-						CMD_UNSOLICITED_ABORT) {
+				    CMD_UNSOLICITED_ABORT) {
 					printk(KERN_WARNING "cciss%d: "
-						"unsolicited abort %p\n",
-						ctlr, c);
+					       "unsolicited abort %p\n",
+					       ctlr, c);
 					if (c->retry_count < MAX_CMD_RETRIES) {
 						printk(KERN_WARNING
-						   "cciss%d: retrying %p\n",
-						   ctlr, c);
+						       "cciss%d: retrying %p\n",
+						       ctlr, c);
 						c->retry_count++;
 						/* erase the old error */
 						/* information */
 						memset(c->err_info, 0,
-						   sizeof(ErrorInfo_struct));
+						       sizeof
+						       (ErrorInfo_struct));
 						goto resend_cmd1;
 					} else {
 						printk(KERN_WARNING
-						   "cciss%d: retried %p too "
-						   "many times\n", ctlr, c);
+						       "cciss%d: retried %p too "
+						       "many times\n", ctlr, c);
 						status = IO_ERROR;
 						goto cleanup1;
 					}
-				} else if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
-					printk(KERN_WARNING "cciss%d: command could not be aborted.\n", ctlr);
+				} else if (c->err_info->CommandStatus ==
+					   CMD_UNABORTABLE) {
+					printk(KERN_WARNING
+					       "cciss%d: command could not be aborted.\n",
+					       ctlr);
 					status = IO_ERROR;
 					goto cleanup1;
 				}
 				printk(KERN_WARNING "ciss ciss%d: sendcmd"
-				" Error %x \n", ctlr, 
-					c->err_info->CommandStatus); 
+				       " Error %x \n", ctlr,
+				       c->err_info->CommandStatus);
 				printk(KERN_WARNING "ciss ciss%d: sendcmd"
-				" offensive info\n"
-				"  size %x\n   num %x   value %x\n", ctlr,
-				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
-				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
-				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+				       " offensive info\n"
+				       "  size %x\n   num %x   value %x\n",
+				       ctlr,
+				       c->err_info->MoreErrInfo.Invalid_Cmd.
+				       offense_size,
+				       c->err_info->MoreErrInfo.Invalid_Cmd.
+				       offense_num,
+				       c->err_info->MoreErrInfo.Invalid_Cmd.
+				       offense_value);
 				status = IO_ERROR;
 				goto cleanup1;
 			}
 		}
 		/* This will need changing for direct lookup completions */
-                if (complete != c->busaddr) {
+		if (complete != c->busaddr) {
 			if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
-				BUG(); /* we are pretty much hosed if we get here. */
+				BUG();	/* we are pretty much hosed if we get here. */
 			}
 			continue;
-                } else
+		} else
 			done = 1;
-        } while (!done);
-		
-cleanup1:	
+	} while (!done);
+
+      cleanup1:
 	/* unlock the data buffer from DMA */
 	buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
 	buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
 	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-				c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+			 c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
 #ifdef CONFIG_CISS_SCSI_TAPE
 	/* if we saved some commands for later, process them now. */
 	if (info_p->scsi_rejects.ncompletions > 0)
 		do_cciss_intr(0, info_p, NULL);
 #endif
 	cmd_free(info_p, c, 1);
-	return (status);
-} 
+	return status;
+}
+
 /*
  * Map (physical) PCI mem into (virtual) kernel space
  */
 static void __iomem *remap_pci_mem(ulong base, ulong size)
 {
-        ulong page_base        = ((ulong) base) & PAGE_MASK;
-        ulong page_offs        = ((ulong) base) - page_base;
-        void __iomem *page_remapped = ioremap(page_base, page_offs+size);
+	ulong page_base = ((ulong) base) & PAGE_MASK;
+	ulong page_offs = ((ulong) base) - page_base;
+	void __iomem *page_remapped = ioremap(page_base, page_offs + size);
 
-        return page_remapped ? (page_remapped + page_offs) : NULL;
+	return page_remapped ? (page_remapped + page_offs) : NULL;
 }
 
-/* 
- * Takes jobs of the Q and sends them to the hardware, then puts it on 
- * the Q to wait for completion. 
- */ 
-static void start_io( ctlr_info_t *h)
+/*
+ * Takes jobs of the Q and sends them to the hardware, then puts it on
+ * the Q to wait for completion.
+ */
+static void start_io(ctlr_info_t *h)
 {
 	CommandList_struct *c;
-	
-	while(( c = h->reqQ) != NULL )
-	{
+
+	while ((c = h->reqQ) != NULL) {
 		/* can't do anything if fifo is full */
 		if ((h->access.fifo_full(h))) {
 			printk(KERN_WARNING "cciss: fifo full\n");
 			break;
 		}
 
-		/* Get the first entry from the Request Q */ 
+		/* Get the first entry from the Request Q */
 		removeQ(&(h->reqQ), c);
 		h->Qdepth--;
-	
-		/* Tell the controller execute command */ 
+
+		/* Tell the controller execute command */
 		h->access.submit_command(h, c);
-		
-		/* Put job onto the completed Q */ 
-		addQ (&(h->cmpQ), c); 
+
+		/* Put job onto the completed Q */
+		addQ(&(h->cmpQ), c);
 	}
 }
+
 /* Assumes that CCISS_LOCK(h->ctlr) is held. */
 /* Zeros out the error record and then resends the command back */
 /* to the controller */
-static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
 {
 	/* erase the old error information */
 	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
 
 	/* add it to software queue and then send it to the controller */
-	addQ(&(h->reqQ),c);
+	addQ(&(h->reqQ), c);
 	h->Qdepth++;
-	if(h->Qdepth > h->maxQsinceinit)
+	if (h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth;
 
 	start_io(h);
 }
 
-/* checks the status of the job and calls complete buffers to mark all 
+/* checks the status of the job and calls complete buffers to mark all
  * buffers for the completed job. Note that this function does not need
  * to hold the hba/queue lock.
- */ 
-static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
-		int timeout)
+ */
+static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
+				    int timeout)
 {
 	int status = 1;
 	int retry_cmd = 0;
-		
-	if (timeout)
-		status = 0; 
 
-	if(cmd->err_info->CommandStatus != 0) 
-	{ /* an error has occurred */ 
-		switch(cmd->err_info->CommandStatus)
-		{
+	if (timeout)
+		status = 0;
+
+	if (cmd->err_info->CommandStatus != 0) {	/* an error has occurred */
+		switch (cmd->err_info->CommandStatus) {
 			unsigned char sense_key;
-			case CMD_TARGET_STATUS:
-				status = 0;
-			
-				if( cmd->err_info->ScsiStatus == 0x02)
-				{
-					printk(KERN_WARNING "cciss: cmd %p "
-                                        	"has CHECK CONDITION "
-						" byte 2 = 0x%x\n", cmd,
-						cmd->err_info->SenseInfo[2]
-					);
-					/* check the sense key */
-					sense_key = 0xf & 
-						cmd->err_info->SenseInfo[2];
-					/* no status or recovered error */
-					if((sense_key == 0x0) ||
-					    (sense_key == 0x1))
-					{
-							status = 1;
-					}
-				} else
-				{
-					printk(KERN_WARNING "cciss: cmd %p "
-                                                "has SCSI Status 0x%x\n",
-						cmd, cmd->err_info->ScsiStatus);
+		case CMD_TARGET_STATUS:
+			status = 0;
+
+			if (cmd->err_info->ScsiStatus == 0x02) {
+				printk(KERN_WARNING "cciss: cmd %p "
+				       "has CHECK CONDITION "
+				       " byte 2 = 0x%x\n", cmd,
+				       cmd->err_info->SenseInfo[2]
+				    );
+				/* check the sense key */
+				sense_key = 0xf & cmd->err_info->SenseInfo[2];
+				/* no status or recovered error */
+				if ((sense_key == 0x0) || (sense_key == 0x1)) {
+					status = 1;
 				}
+			} else {
+				printk(KERN_WARNING "cciss: cmd %p "
+				       "has SCSI Status 0x%x\n",
+				       cmd, cmd->err_info->ScsiStatus);
+			}
 			break;
-			case CMD_DATA_UNDERRUN:
-				printk(KERN_WARNING "cciss: cmd %p has"
-					" completed with data underrun "
-					"reported\n", cmd);
+		case CMD_DATA_UNDERRUN:
+			printk(KERN_WARNING "cciss: cmd %p has"
+			       " completed with data underrun "
+			       "reported\n", cmd);
 			break;
-			case CMD_DATA_OVERRUN:
-				printk(KERN_WARNING "cciss: cmd %p has"
-					" completed with data overrun "
-					"reported\n", cmd);
+		case CMD_DATA_OVERRUN:
+			printk(KERN_WARNING "cciss: cmd %p has"
+			       " completed with data overrun "
+			       "reported\n", cmd);
 			break;
-			case CMD_INVALID:
-				printk(KERN_WARNING "cciss: cmd %p is "
-					"reported invalid\n", cmd);
-				status = 0;
+		case CMD_INVALID:
+			printk(KERN_WARNING "cciss: cmd %p is "
+			       "reported invalid\n", cmd);
+			status = 0;
 			break;
-			case CMD_PROTOCOL_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p has "
-					"protocol error \n", cmd);
-                                status = 0;
-                        break;
-			case CMD_HARDWARE_ERR:
-                                printk(KERN_WARNING "cciss: cmd %p had " 
-                                        " hardware error\n", cmd);
-                                status = 0;
-                        break;
-			case CMD_CONNECTION_LOST:
-				printk(KERN_WARNING "cciss: cmd %p had "
-					"connection lost\n", cmd);
-				status=0;
+		case CMD_PROTOCOL_ERR:
+			printk(KERN_WARNING "cciss: cmd %p has "
+			       "protocol error \n", cmd);
+			status = 0;
 			break;
-			case CMD_ABORTED:
-				printk(KERN_WARNING "cciss: cmd %p was "
-					"aborted\n", cmd);
-				status=0;
+		case CMD_HARDWARE_ERR:
+			printk(KERN_WARNING "cciss: cmd %p had "
+			       " hardware error\n", cmd);
+			status = 0;
 			break;
-			case CMD_ABORT_FAILED:
-				printk(KERN_WARNING "cciss: cmd %p reports "
-					"abort failed\n", cmd);
-				status=0;
+		case CMD_CONNECTION_LOST:
+			printk(KERN_WARNING "cciss: cmd %p had "
+			       "connection lost\n", cmd);
+			status = 0;
 			break;
-			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss%d: unsolicited "
-					"abort %p\n", h->ctlr, cmd);
-				if (cmd->retry_count < MAX_CMD_RETRIES) {
-					retry_cmd=1;
-					printk(KERN_WARNING
-						"cciss%d: retrying %p\n",
-						h->ctlr, cmd);
-					cmd->retry_count++;
-				} else
-					printk(KERN_WARNING
-						"cciss%d: %p retried too "
-						"many times\n", h->ctlr, cmd);
-				status=0;
+		case CMD_ABORTED:
+			printk(KERN_WARNING "cciss: cmd %p was "
+			       "aborted\n", cmd);
+			status = 0;
 			break;
-			case CMD_TIMEOUT:
-				printk(KERN_WARNING "cciss: cmd %p timedout\n",
-					cmd);
-				status=0;
+		case CMD_ABORT_FAILED:
+			printk(KERN_WARNING "cciss: cmd %p reports "
+			       "abort failed\n", cmd);
+			status = 0;
 			break;
-			default:
-				printk(KERN_WARNING "cciss: cmd %p returned "
-					"unknown status %x\n", cmd, 
-						cmd->err_info->CommandStatus); 
-				status=0;
+		case CMD_UNSOLICITED_ABORT:
+			printk(KERN_WARNING "cciss%d: unsolicited "
+			       "abort %p\n", h->ctlr, cmd);
+			if (cmd->retry_count < MAX_CMD_RETRIES) {
+				retry_cmd = 1;
+				printk(KERN_WARNING
+				       "cciss%d: retrying %p\n", h->ctlr, cmd);
+				cmd->retry_count++;
+			} else
+				printk(KERN_WARNING
+				       "cciss%d: %p retried too "
+				       "many times\n", h->ctlr, cmd);
+			status = 0;
+			break;
+		case CMD_TIMEOUT:
+			printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+			status = 0;
+			break;
+		default:
+			printk(KERN_WARNING "cciss: cmd %p returned "
+			       "unknown status %x\n", cmd,
+			       cmd->err_info->CommandStatus);
+			status = 0;
 		}
 	}
 	/* We need to return this command */
-	if(retry_cmd) {
-		resend_cciss_cmd(h,cmd);
+	if (retry_cmd) {
+		resend_cciss_cmd(h, cmd);
 		return;
-	}	
+	}
 
 	cmd->rq->completion_data = cmd;
 	cmd->rq->errors = status;
@@ -2336,12 +2365,12 @@
 	blk_complete_request(cmd->rq);
 }
 
-/* 
- * Get a request and submit it to the controller. 
+/*
+ * Get a request and submit it to the controller.
  */
 static void do_cciss_request(request_queue_t *q)
 {
-	ctlr_info_t *h= q->queuedata; 
+	ctlr_info_t *h = q->queuedata;
 	CommandList_struct *c;
 	int start_blk, seg;
 	struct request *creq;
@@ -2352,18 +2381,18 @@
 
 	/* We call start_io here in case there is a command waiting on the
 	 * queue that has not been sent.
-	*/
+	 */
 	if (blk_queue_plugged(q))
 		goto startio;
 
-queue:
+      queue:
 	creq = elv_next_request(q);
 	if (!creq)
 		goto startio;
 
 	BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
 
-	if (( c = cmd_alloc(h, 1)) == NULL)
+	if ((c = cmd_alloc(h, 1)) == NULL)
 		goto full;
 
 	blkdev_dequeue_request(creq);
@@ -2372,81 +2401,82 @@
 
 	c->cmd_type = CMD_RWREQ;
 	c->rq = creq;
-	
-	/* fill in the request */ 
+
+	/* fill in the request */
 	drv = creq->rq_disk->private_data;
-	c->Header.ReplyQueue = 0;  // unused in simple mode
+	c->Header.ReplyQueue = 0;	// unused in simple mode
 	/* got command from pool, so use the command block index instead */
 	/* for direct lookups. */
 	/* The first 2 bits are reserved for controller error reporting. */
 	c->Header.Tag.lower = (c->cmdindex << 3);
-	c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
-	c->Header.LUN.LogDev.VolId= drv->LunID;
+	c->Header.Tag.lower |= 0x04;	/* flag for direct lookup. */
+	c->Header.LUN.LogDev.VolId = drv->LunID;
 	c->Header.LUN.LogDev.Mode = 1;
-	c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-	c->Request.Type.Type =  TYPE_CMD; // It is a command. 
-	c->Request.Type.Attribute = ATTR_SIMPLE; 
-	c->Request.Type.Direction = 
-		(rq_data_dir(creq) == READ) ? XFER_READ: XFER_WRITE; 
-	c->Request.Timeout = 0; // Don't time out	
-	c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
+	c->Request.CDBLen = 10;	// 12 byte commands not in FW yet;
+	c->Request.Type.Type = TYPE_CMD;	// It is a command.
+	c->Request.Type.Attribute = ATTR_SIMPLE;
+	c->Request.Type.Direction =
+	    (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
+	c->Request.Timeout = 0;	// Don't time out
+	c->Request.CDB[0] =
+	    (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
 	start_blk = creq->sector;
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
-		(int) creq->nr_sectors);	
-#endif /* CCISS_DEBUG */
+	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
+	       (int)creq->nr_sectors);
+#endif				/* CCISS_DEBUG */
 
 	seg = blk_rq_map_sg(q, creq, tmp_sg);
 
-	/* get the DMA records for the setup */ 
+	/* get the DMA records for the setup */
 	if (c->Request.Type.Direction == XFER_READ)
 		dir = PCI_DMA_FROMDEVICE;
 	else
 		dir = PCI_DMA_TODEVICE;
 
-	for (i=0; i<seg; i++)
-	{
+	for (i = 0; i < seg; i++) {
 		c->SG[i].Len = tmp_sg[i].length;
 		temp64.val = (__u64) pci_map_page(h->pdev, tmp_sg[i].page,
-			 		  tmp_sg[i].offset, tmp_sg[i].length,
-					  dir);
+						  tmp_sg[i].offset,
+						  tmp_sg[i].length, dir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
-                c->SG[i].Addr.upper = temp64.val32.upper;
-                c->SG[i].Ext = 0;  // we are not chaining
+		c->SG[i].Addr.upper = temp64.val32.upper;
+		c->SG[i].Ext = 0;	// we are not chaining
 	}
-	/* track how many SG entries we are using */ 
-	if( seg > h->maxSG)
-		h->maxSG = seg; 
+	/* track how many SG entries we are using */
+	if (seg > h->maxSG)
+		h->maxSG = seg;
 
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, seg);
-#endif /* CCISS_DEBUG */
+	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n",
+	       creq->nr_sectors, seg);
+#endif				/* CCISS_DEBUG */
 
 	c->Header.SGList = c->Header.SGTotal = seg;
-	c->Request.CDB[1]= 0;
-	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	//MSB
-	c->Request.CDB[3]= (start_blk >> 16) & 0xff;
-	c->Request.CDB[4]= (start_blk >>  8) & 0xff;
-	c->Request.CDB[5]= start_blk & 0xff;
-	c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
-	c->Request.CDB[7]= (creq->nr_sectors >>  8) & 0xff; 
-	c->Request.CDB[8]= creq->nr_sectors & 0xff; 
+	c->Request.CDB[1] = 0;
+	c->Request.CDB[2] = (start_blk >> 24) & 0xff;	//MSB
+	c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+	c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+	c->Request.CDB[5] = start_blk & 0xff;
+	c->Request.CDB[6] = 0;	// (sect >> 24) & 0xff; MSB
+	c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+	c->Request.CDB[8] = creq->nr_sectors & 0xff;
 	c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
 
 	spin_lock_irq(q->queue_lock);
 
-	addQ(&(h->reqQ),c);
+	addQ(&(h->reqQ), c);
 	h->Qdepth++;
-	if(h->Qdepth > h->maxQsinceinit)
-		h->maxQsinceinit = h->Qdepth; 
+	if (h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth;
 
 	goto queue;
-full:
+      full:
 	blk_stop_queue(q);
-startio:
+      startio:
 	/* We will already have the driver lock here so not need
 	 * to lock it.
-	*/
+	 */
 	start_io(h);
 }
 
@@ -2473,7 +2503,7 @@
 static inline int interrupt_pending(ctlr_info_t *h)
 {
 #ifdef CONFIG_CISS_SCSI_TAPE
-	return ( h->access.intr_pending(h) 
+	return (h->access.intr_pending(h)
 		|| (h->scsi_rejects.ncompletions > 0));
 #else
 	return h->access.intr_pending(h);
@@ -2483,11 +2513,11 @@
 static inline long interrupt_not_for_us(ctlr_info_t *h)
 {
 #ifdef CONFIG_CISS_SCSI_TAPE
-	return (((h->access.intr_pending(h) == 0) || 
-		 (h->interrupts_enabled == 0)) 
-	      && (h->scsi_rejects.ncompletions == 0));
+	return (((h->access.intr_pending(h) == 0) ||
+		 (h->interrupts_enabled == 0))
+		&& (h->scsi_rejects.ncompletions == 0));
 #else
-	return (((h->access.intr_pending(h) == 0) || 
+	return (((h->access.intr_pending(h) == 0) ||
 		 (h->interrupts_enabled == 0)));
 #endif
 }
@@ -2509,12 +2539,14 @@
 	 */
 	spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
 	while (interrupt_pending(h)) {
-		while((a = get_next_completion(h)) != FIFO_EMPTY) {
+		while ((a = get_next_completion(h)) != FIFO_EMPTY) {
 			a1 = a;
 			if ((a & 0x04)) {
 				a2 = (a >> 3);
 				if (a2 >= NR_CMDS) {
-					printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+					printk(KERN_WARNING
+					       "cciss: controller cciss%d failed, stopping.\n",
+					       h->ctlr);
 					fail_all_cmds(h->ctlr);
 					return IRQ_HANDLED;
 				}
@@ -2523,22 +2555,24 @@
 				a = c->busaddr;
 
 			} else {
-			a &= ~3;
+				a &= ~3;
 				if ((c = h->cmpQ) == NULL) {
-					printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
-				continue;	
-			} 
-			while(c->busaddr != a) {
-				c = c->next;
-				if (c == h->cmpQ) 
-					break;
-			}
+					printk(KERN_WARNING
+					       "cciss: Completion of %08x ignored\n",
+					       a1);
+					continue;
+				}
+				while (c->busaddr != a) {
+					c = c->next;
+					if (c == h->cmpQ)
+						break;
+				}
 			}
 			/*
 			 * If we've found the command, take it off the
 			 * completion Q and free it
 			 */
-			 if (c->busaddr == a) {
+			if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
 				if (c->cmd_type == CMD_RWREQ) {
 					complete_command(h, c, 0);
@@ -2554,130 +2588,118 @@
 		}
 	}
 
- 	/* check to see if we have maxed out the number of commands that can
- 	 * be placed on the queue.  If so then exit.  We do this check here
- 	 * in case the interrupt we serviced was from an ioctl and did not
- 	 * free any new commands.
+	/* check to see if we have maxed out the number of commands that can
+	 * be placed on the queue.  If so then exit.  We do this check here
+	 * in case the interrupt we serviced was from an ioctl and did not
+	 * free any new commands.
 	 */
- 	if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- 		goto cleanup;
+	if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+		goto cleanup;
 
- 	/* We have room on the queue for more commands.  Now we need to queue
- 	 * them up.  We will also keep track of the next queue to run so
- 	 * that every queue gets a chance to be started first.
- 	*/
-	for (j=0; j < h->highest_lun + 1; j++){
+	/* We have room on the queue for more commands.  Now we need to queue
+	 * them up.  We will also keep track of the next queue to run so
+	 * that every queue gets a chance to be started first.
+	 */
+	for (j = 0; j < h->highest_lun + 1; j++) {
 		int curr_queue = (start_queue + j) % (h->highest_lun + 1);
- 		/* make sure the disk has been added and the drive is real
- 		 * because this can be called from the middle of init_one.
- 		*/
-		if(!(h->drv[curr_queue].queue) ||
-		 		   !(h->drv[curr_queue].heads))
- 			continue;
- 		blk_start_queue(h->gendisk[curr_queue]->queue);
+		/* make sure the disk has been added and the drive is real
+		 * because this can be called from the middle of init_one.
+		 */
+		if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+			continue;
+		blk_start_queue(h->gendisk[curr_queue]->queue);
 
- 		/* check to see if we have maxed out the number of commands
- 		 * that can be placed on the queue.
- 		*/
- 		if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- 		{
- 			if (curr_queue == start_queue){
-				h->next_to_run = (start_queue + 1) % (h->highest_lun + 1);
- 				goto cleanup;
- 			} else {
- 				h->next_to_run = curr_queue;
- 				goto cleanup;
- 	}
- 		} else {
+		/* check to see if we have maxed out the number of commands
+		 * that can be placed on the queue.
+		 */
+		if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+			if (curr_queue == start_queue) {
+				h->next_to_run =
+				    (start_queue + 1) % (h->highest_lun + 1);
+				goto cleanup;
+			} else {
+				h->next_to_run = curr_queue;
+				goto cleanup;
+			}
+		} else {
 			curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
- 		}
- 	}
+		}
+	}
 
-cleanup:
+      cleanup:
 	spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 	return IRQ_HANDLED;
 }
-/* 
- *  We cannot read the structure directly, for portablity we must use 
+
+/*
+ *  We cannot read the structure directly, for portability we must use
  *   the io functions.
- *   This is for debug only. 
+ *   This is for debug only.
  */
 #ifdef CCISS_DEBUG
-static void print_cfg_table( CfgTable_struct *tb)
+static void print_cfg_table(CfgTable_struct *tb)
 {
 	int i;
 	char temp_name[17];
 
 	printk("Controller Configuration information\n");
 	printk("------------------------------------\n");
-	for(i=0;i<4;i++)
+	for (i = 0; i < 4; i++)
 		temp_name[i] = readb(&(tb->Signature[i]));
-	temp_name[4]='\0';
-	printk("   Signature = %s\n", temp_name); 
+	temp_name[4] = '\0';
+	printk("   Signature = %s\n", temp_name);
 	printk("   Spec Number = %d\n", readl(&(tb->SpecValence)));
-	printk("   Transport methods supported = 0x%x\n", 
-				readl(&(tb-> TransportSupport)));
-	printk("   Transport methods active = 0x%x\n", 
-				readl(&(tb->TransportActive)));
-	printk("   Requested transport Method = 0x%x\n", 
-			readl(&(tb->HostWrite.TransportRequest)));
-	printk("   Coalese Interrupt Delay = 0x%x\n", 
-			readl(&(tb->HostWrite.CoalIntDelay)));
-	printk("   Coalese Interrupt Count = 0x%x\n", 
-			readl(&(tb->HostWrite.CoalIntCount)));
-	printk("   Max outstanding commands = 0x%d\n", 
-			readl(&(tb->CmdsOutMax)));
-	printk("   Bus Types = 0x%x\n", readl(&(tb-> BusTypes)));
-	for(i=0;i<16;i++)
+	printk("   Transport methods supported = 0x%x\n",
+	       readl(&(tb->TransportSupport)));
+	printk("   Transport methods active = 0x%x\n",
+	       readl(&(tb->TransportActive)));
+	printk("   Requested transport Method = 0x%x\n",
+	       readl(&(tb->HostWrite.TransportRequest)));
+	printk("   Coalesce Interrupt Delay = 0x%x\n",
+	       readl(&(tb->HostWrite.CoalIntDelay)));
+	printk("   Coalesce Interrupt Count = 0x%x\n",
+	       readl(&(tb->HostWrite.CoalIntCount)));
+	printk("   Max outstanding commands = 0x%d\n",
+	       readl(&(tb->CmdsOutMax)));
+	printk("   Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
+	for (i = 0; i < 16; i++)
 		temp_name[i] = readb(&(tb->ServerName[i]));
 	temp_name[16] = '\0';
 	printk("   Server Name = %s\n", temp_name);
-	printk("   Heartbeat Counter = 0x%x\n\n\n", 
-			readl(&(tb->HeartBeat)));
+	printk("   Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat)));
 }
-#endif /* CCISS_DEBUG */ 
+#endif				/* CCISS_DEBUG */
 
-static void release_io_mem(ctlr_info_t *c)
-{
-	/* if IO mem was not protected do nothing */
-	if( c->io_mem_addr == 0)
-		return;
-	release_region(c->io_mem_addr, c->io_mem_length);
-	c->io_mem_addr = 0;
-	c->io_mem_length = 0;
-}
-
-static int find_PCI_BAR_index(struct pci_dev *pdev,
-				unsigned long pci_bar_addr)
+static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
 {
 	int i, offset, mem_type, bar_type;
-	if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
+	if (pci_bar_addr == PCI_BASE_ADDRESS_0)	/* looking for BAR zero? */
 		return 0;
 	offset = 0;
-	for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
-		bar_type = pci_resource_flags(pdev, i) &
-			PCI_BASE_ADDRESS_SPACE;
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
 		if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
 			offset += 4;
 		else {
 			mem_type = pci_resource_flags(pdev, i) &
-				PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+			    PCI_BASE_ADDRESS_MEM_TYPE_MASK;
 			switch (mem_type) {
-				case PCI_BASE_ADDRESS_MEM_TYPE_32:
-				case PCI_BASE_ADDRESS_MEM_TYPE_1M:
-					offset += 4; /* 32 bit */
-					break;
-				case PCI_BASE_ADDRESS_MEM_TYPE_64:
-					offset += 8;
-					break;
-				default: /* reserved in PCI 2.2 */
-					printk(KERN_WARNING "Base address is invalid\n");
-			       		return -1;
+			case PCI_BASE_ADDRESS_MEM_TYPE_32:
+			case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+				offset += 4;	/* 32 bit */
+				break;
+			case PCI_BASE_ADDRESS_MEM_TYPE_64:
+				offset += 8;
+				break;
+			default:	/* reserved in PCI 2.2 */
+				printk(KERN_WARNING
+				       "Base address is invalid\n");
+				return -1;
 				break;
 			}
 		}
- 		if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
-			return i+1;
+		if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
+			return i + 1;
 	}
 	return -1;
 }
@@ -2686,53 +2708,54 @@
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id)
+static void __devinit cciss_interrupt_mode(ctlr_info_t *c,
+					   struct pci_dev *pdev, __u32 board_id)
 {
 #ifdef CONFIG_PCI_MSI
-        int err;
-        struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1},
-						   {0,2}, {0,3}};
+	int err;
+	struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1},
+	{0, 2}, {0, 3}
+	};
 
 	/* Some boards advertise MSI but don't really support it */
 	if ((board_id == 0x40700E11) ||
-		(board_id == 0x40800E11) ||
-		(board_id == 0x40820E11) ||
-		(board_id == 0x40830E11))
+	    (board_id == 0x40800E11) ||
+	    (board_id == 0x40820E11) || (board_id == 0x40830E11))
 		goto default_int_mode;
 
-        if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
-                err = pci_enable_msix(pdev, cciss_msix_entries, 4);
-                if (!err) {
-                        c->intr[0] = cciss_msix_entries[0].vector;
-                        c->intr[1] = cciss_msix_entries[1].vector;
-                        c->intr[2] = cciss_msix_entries[2].vector;
-                        c->intr[3] = cciss_msix_entries[3].vector;
-                        c->msix_vector = 1;
-                        return;
-                }
-                if (err > 0) {
-                        printk(KERN_WARNING "cciss: only %d MSI-X vectors "
-                                        "available\n", err);
-                } else {
-                        printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
-						err);
-                }
-        }
-        if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
-                if (!pci_enable_msi(pdev)) {
-                        c->intr[SIMPLE_MODE_INT] = pdev->irq;
-                        c->msi_vector = 1;
-                        return;
-                } else {
-                        printk(KERN_WARNING "cciss: MSI init failed\n");
-        		c->intr[SIMPLE_MODE_INT] = pdev->irq;
-                        return;
-                }
-        }
-default_int_mode:
-#endif /* CONFIG_PCI_MSI */
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+		err = pci_enable_msix(pdev, cciss_msix_entries, 4);
+		if (!err) {
+			c->intr[0] = cciss_msix_entries[0].vector;
+			c->intr[1] = cciss_msix_entries[1].vector;
+			c->intr[2] = cciss_msix_entries[2].vector;
+			c->intr[3] = cciss_msix_entries[3].vector;
+			c->msix_vector = 1;
+			return;
+		}
+		if (err > 0) {
+			printk(KERN_WARNING "cciss: only %d MSI-X vectors "
+			       "available\n", err);
+		} else {
+			printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
+			       err);
+		}
+	}
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+		if (!pci_enable_msi(pdev)) {
+			c->intr[SIMPLE_MODE_INT] = pdev->irq;
+			c->msi_vector = 1;
+			return;
+		} else {
+			printk(KERN_WARNING "cciss: MSI init failed\n");
+			c->intr[SIMPLE_MODE_INT] = pdev->irq;
+			return;
+		}
+	}
+      default_int_mode:
+#endif				/* CONFIG_PCI_MSI */
 	/* if we get here we're going to use the default interrupt mode */
-        c->intr[SIMPLE_MODE_INT] = pdev->irq;
+	c->intr[SIMPLE_MODE_INT] = pdev->irq;
 	return;
 }
 
@@ -2743,58 +2766,40 @@
 	__u64 cfg_offset;
 	__u32 cfg_base_addr;
 	__u64 cfg_base_addr_index;
-	int i;
+	int i, err;
 
 	/* check to see if controller has been disabled */
 	/* BEFORE trying to enable it */
-	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
-	if(!(command & 0x02))
-	{
-		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
-		return(-1);
+	(void)pci_read_config_word(pdev, PCI_COMMAND, &command);
+	if (!(command & 0x02)) {
+		printk(KERN_WARNING
+		       "cciss: controller appears to be disabled\n");
+		return -ENODEV;
 	}
 
-	if (pci_enable_device(pdev))
-	{
+	err = pci_enable_device(pdev);
+	if (err) {
 		printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-		return( -1);
+		return err;
+	}
+
+	err = pci_request_regions(pdev, "cciss");
+	if (err) {
+		printk(KERN_ERR "cciss: Cannot obtain PCI resources, "
+		       "aborting\n");
+		goto err_out_disable_pdev;
 	}
 
 	subsystem_vendor_id = pdev->subsystem_vendor;
 	subsystem_device_id = pdev->subsystem_device;
 	board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
-					subsystem_vendor_id);
-
-	/* search for our IO range so we can protect it */
-	for(i=0; i<DEVICE_COUNT_RESOURCE; i++)
-	{
-		/* is this an IO range */ 
-		if( pci_resource_flags(pdev, i) & 0x01 ) {
-			c->io_mem_addr = pci_resource_start(pdev, i);
-			c->io_mem_length = pci_resource_end(pdev, i) -
-				pci_resource_start(pdev, i) +1;
-#ifdef CCISS_DEBUG
-			printk("IO value found base_addr[%d] %lx %lx\n", i,
-				c->io_mem_addr, c->io_mem_length);
-#endif /* CCISS_DEBUG */
-			/* register the IO range */ 
-			if(!request_region( c->io_mem_addr,
-                                        c->io_mem_length, "cciss"))
-			{
-				printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
-				c->io_mem_addr, c->io_mem_length);
-				c->io_mem_addr= 0;
-				c->io_mem_length = 0;
-			} 
-			break;
-		}
-	}
+		    subsystem_vendor_id);
 
 #ifdef CCISS_DEBUG
 	printk("command = %x\n", command);
 	printk("irq = %x\n", pdev->irq);
 	printk("board_id = %x\n", board_id);
-#endif /* CCISS_DEBUG */ 
+#endif				/* CCISS_DEBUG */
 
 /* If the kernel supports MSI/MSI-X we will try to enable that functionality,
  * else we use the IO-APIC interrupt assigned to us by system ROM.
@@ -2803,27 +2808,28 @@
 
 	/*
 	 * Memory base addr is first addr , the second points to the config
-         *   table
+	 *   table
 	 */
 
-	c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
+	c->paddr = pci_resource_start(pdev, 0);	/* addressing mode bits already removed */
 #ifdef CCISS_DEBUG
 	printk("address 0 = %x\n", c->paddr);
-#endif /* CCISS_DEBUG */ 
+#endif				/* CCISS_DEBUG */
 	c->vaddr = remap_pci_mem(c->paddr, 200);
 
 	/* Wait for the board to become ready.  (PCI hotplug needs this.)
 	 * We poll for up to 120 secs, once per 100ms. */
-	for (i=0; i < 1200; i++) {
+	for (i = 0; i < 1200; i++) {
 		scratchpad = readl(c->vaddr + SA5_SCRATCHPAD_OFFSET);
 		if (scratchpad == CCISS_FIRMWARE_READY)
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ / 10); /* wait 100ms */
+		schedule_timeout(HZ / 10);	/* wait 100ms */
 	}
 	if (scratchpad != CCISS_FIRMWARE_READY) {
 		printk(KERN_WARNING "cciss: Board not ready.  Timed out.\n");
-		return -1;
+		err = -ENODEV;
+		goto err_out_free_res;
 	}
 
 	/* get the address index number */
@@ -2831,103 +2837,108 @@
 	cfg_base_addr &= (__u32) 0x0000ffff;
 #ifdef CCISS_DEBUG
 	printk("cfg base address = %x\n", cfg_base_addr);
-#endif /* CCISS_DEBUG */
-	cfg_base_addr_index =
-		find_PCI_BAR_index(pdev, cfg_base_addr);
+#endif				/* CCISS_DEBUG */
+	cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
 #ifdef CCISS_DEBUG
 	printk("cfg base address index = %x\n", cfg_base_addr_index);
-#endif /* CCISS_DEBUG */
+#endif				/* CCISS_DEBUG */
 	if (cfg_base_addr_index == -1) {
 		printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n");
-		release_io_mem(c);
-		return -1;
+		err = -ENODEV;
+		goto err_out_free_res;
 	}
 
 	cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);
 #ifdef CCISS_DEBUG
 	printk("cfg offset = %x\n", cfg_offset);
-#endif /* CCISS_DEBUG */
-	c->cfgtable =  remap_pci_mem(pci_resource_start(pdev,
-				cfg_base_addr_index) + cfg_offset,
-				sizeof(CfgTable_struct));
+#endif				/* CCISS_DEBUG */
+	c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
+						       cfg_base_addr_index) +
+				    cfg_offset, sizeof(CfgTable_struct));
 	c->board_id = board_id;
 
 #ifdef CCISS_DEBUG
 	print_cfg_table(c->cfgtable);
-#endif /* CCISS_DEBUG */
+#endif				/* CCISS_DEBUG */
 
-	for(i=0; i<NR_PRODUCTS; i++) {
+	for (i = 0; i < ARRAY_SIZE(products); i++) {
 		if (board_id == products[i].board_id) {
 			c->product_name = products[i].product_name;
 			c->access = *(products[i].access);
 			break;
 		}
 	}
-	if (i == NR_PRODUCTS) {
+	if (i == ARRAY_SIZE(products)) {
 		printk(KERN_WARNING "cciss: Sorry, I don't know how"
-			" to access the Smart Array controller %08lx\n", 
-				(unsigned long)board_id);
-		return -1;
+		       " to access the Smart Array controller %08lx\n",
+		       (unsigned long)board_id);
+		err = -ENODEV;
+		goto err_out_free_res;
 	}
-	if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
-	      (readb(&c->cfgtable->Signature[1]) != 'I') ||
-	      (readb(&c->cfgtable->Signature[2]) != 'S') ||
-	      (readb(&c->cfgtable->Signature[3]) != 'S') )
-	{
+	if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
+	    (readb(&c->cfgtable->Signature[1]) != 'I') ||
+	    (readb(&c->cfgtable->Signature[2]) != 'S') ||
+	    (readb(&c->cfgtable->Signature[3]) != 'S')) {
 		printk("Does not appear to be a valid CISS config table\n");
-		return -1;
+		err = -ENODEV;
+		goto err_out_free_res;
 	}
-
 #ifdef CONFIG_X86
-{
-	/* Need to enable prefetch in the SCSI core for 6400 in x86 */
-	__u32 prefetch;
-	prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
-	prefetch |= 0x100;
-	writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
-}
+	{
+		/* Need to enable prefetch in the SCSI core for 6400 in x86 */
+		__u32 prefetch;
+		prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
+		prefetch |= 0x100;
+		writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
+	}
 #endif
 
 #ifdef CCISS_DEBUG
 	printk("Trying to put board into Simple mode\n");
-#endif /* CCISS_DEBUG */ 
+#endif				/* CCISS_DEBUG */
 	c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
-	/* Update the field, and then ring the doorbell */ 
-	writel( CFGTBL_Trans_Simple, 
-		&(c->cfgtable->HostWrite.TransportRequest));
-	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+	/* Update the field, and then ring the doorbell */
+	writel(CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest));
+	writel(CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
 	/* under certain very rare conditions, this can take awhile.
 	 * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
 	 * as we enter this code.) */
-	for(i=0;i<MAX_CONFIG_WAIT;i++) {
+	for (i = 0; i < MAX_CONFIG_WAIT; i++) {
 		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
 		/* delay and try again */
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(10);
-	}	
+	}
 
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));
-#endif /* CCISS_DEBUG */
+	printk(KERN_DEBUG "I counter got to %d %x\n", i,
+	       readl(c->vaddr + SA5_DOORBELL));
+#endif				/* CCISS_DEBUG */
 #ifdef CCISS_DEBUG
-	print_cfg_table(c->cfgtable);	
-#endif /* CCISS_DEBUG */ 
+	print_cfg_table(c->cfgtable);
+#endif				/* CCISS_DEBUG */
 
-	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
-	{
+	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
 		printk(KERN_WARNING "cciss: unable to get board into"
-					" simple mode\n");
-		return -1;
+		       " simple mode\n");
+		err = -ENODEV;
+		goto err_out_free_res;
 	}
 	return 0;
 
+      err_out_free_res:
+	pci_release_regions(pdev);
+
+      err_out_disable_pdev:
+	pci_disable_device(pdev);
+	return err;
 }
 
-/* 
- * Gets information about the local volumes attached to the controller. 
- */ 
+/*
+ * Gets information about the local volumes attached to the controller.
+ */
 static void cciss_getgeometry(int cntl_num)
 {
 	ReportLunData_struct *ld_buff;
@@ -2938,102 +2949,102 @@
 	int listlength = 0;
 	__u32 lunid = 0;
 	int block_size;
-	int total_size; 
+	int total_size;
 
 	ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-	if (ld_buff == NULL)
-	{
+	if (ld_buff == NULL) {
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
-	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
-                printk(KERN_ERR "cciss: out of memory\n");
+	size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
 		kfree(ld_buff);
-                return;
-        }
-	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
-                printk(KERN_ERR "cciss: out of memory\n");
-                kfree(ld_buff);
+		return;
+	}
+	inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
 		kfree(size_buff);
-                return;
-        }
-	/* Get the firmware version */ 
-	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
-		sizeof(InquiryData_struct), 0, 0 ,0, NULL, TYPE_CMD);
-	if (return_code == IO_OK)
-	{
+		return;
+	}
+	/* Get the firmware version */
+	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+			      sizeof(InquiryData_struct), 0, 0, 0, NULL,
+			      TYPE_CMD);
+	if (return_code == IO_OK) {
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
 		hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
 		hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
 		hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
-	} else /* send command failed */
-	{
-		printk(KERN_WARNING "cciss: unable to determine firmware"
-			" version of controller\n");
-	}
-	/* Get the number of logical volumes */ 
-	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
-			sizeof(ReportLunData_struct), 0, 0, 0, NULL, TYPE_CMD);
+	} else {		/* send command failed */
 
-	if( return_code == IO_OK)
-	{
+		printk(KERN_WARNING "cciss: unable to determine firmware"
+		       " version of controller\n");
+	}
+	/* Get the number of logical volumes */
+	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
+			      sizeof(ReportLunData_struct), 0, 0, 0, NULL,
+			      TYPE_CMD);
+
+	if (return_code == IO_OK) {
 #ifdef CCISS_DEBUG
 		printk("LUN Data\n--------------------------\n");
-#endif /* CCISS_DEBUG */ 
+#endif				/* CCISS_DEBUG */
 
-		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
-		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
-		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
+		listlength |=
+		    (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |=
+		    (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |=
+		    (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
 		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-	} else /* reading number of logical volumes failed */
-	{
+	} else {		/* reading number of logical volumes failed */
+
 		printk(KERN_WARNING "cciss: report logical volume"
-			" command failed\n");
+		       " command failed\n");
 		listlength = 0;
 	}
-	hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
-	if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
-	{
-		printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
-			CISS_MAX_LUN);
+	hba[cntl_num]->num_luns = listlength / 8;	// 8 bytes pre entry
+	if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+		printk(KERN_ERR
+		       "ciss:  only %d number of logical volumes supported\n",
+		       CISS_MAX_LUN);
 		hba[cntl_num]->num_luns = CISS_MAX_LUN;
 	}
 #ifdef CCISS_DEBUG
-	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
-		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
-		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
-#endif /* CCISS_DEBUG */
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n",
+	       ld_buff->LUNListLength[0], ld_buff->LUNListLength[1],
+	       ld_buff->LUNListLength[2], ld_buff->LUNListLength[3],
+	       hba[cntl_num]->num_luns);
+#endif				/* CCISS_DEBUG */
 
-	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
-//	for(i=0; i<  hba[cntl_num]->num_luns; i++)
-	for(i=0; i < CISS_MAX_LUN; i++)
-	{
-		if (i < hba[cntl_num]->num_luns){
-		  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
-				 << 24;
-        		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
-				 << 16;
-        		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
-				 << 8;
-        	lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-		
-		hba[cntl_num]->drv[i].LunID = lunid;
+	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
+//      for(i=0; i<  hba[cntl_num]->num_luns; i++)
+	for (i = 0; i < CISS_MAX_LUN; i++) {
+		if (i < hba[cntl_num]->num_luns) {
+			lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+			    << 24;
+			lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+			    << 16;
+			lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+			    << 8;
+			lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
 
+			hba[cntl_num]->drv[i].LunID = lunid;
 
 #ifdef CCISS_DEBUG
-	  	printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
-			ld_buff->LUN[i][0], ld_buff->LUN[i][1],
-			ld_buff->LUN[i][2], ld_buff->LUN[i][3],
-			hba[cntl_num]->drv[i].LunID);
-#endif /* CCISS_DEBUG */
-		cciss_read_capacity(cntl_num, i, size_buff, 0,
-			&total_size, &block_size);
+			printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i,
+			       ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+			       ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+			       hba[cntl_num]->drv[i].LunID);
+#endif				/* CCISS_DEBUG */
+			cciss_read_capacity(cntl_num, i, size_buff, 0,
+					    &total_size, &block_size);
 			cciss_geometry_inquiry(cntl_num, i, 0, total_size,
-				block_size, inq_buff, &hba[cntl_num]->drv[i]);
+					       block_size, inq_buff,
+					       &hba[cntl_num]->drv[i]);
 		} else {
 			/* initialize raid_level to indicate a free space */
 			hba[cntl_num]->drv[i].raid_level = -1;
@@ -3042,7 +3053,7 @@
 	kfree(ld_buff);
 	kfree(size_buff);
 	kfree(inq_buff);
-}	
+}
 
 /* Function to find the first free pointer into our hba[] array */
 /* Returns -1 if no free entries are left.  */
@@ -3056,7 +3067,7 @@
 			goto out;
 	}
 
-	for(i=0; i< MAX_CTLR; i++) {
+	for (i = 0; i < MAX_CTLR; i++) {
 		if (!hba[i]) {
 			ctlr_info_t *p;
 			p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
@@ -3069,11 +3080,11 @@
 		}
 	}
 	printk(KERN_WARNING "cciss: This driver supports a maximum"
-		" of %d controllers.\n", MAX_CTLR);
+	       " of %d controllers.\n", MAX_CTLR);
 	goto out;
-Enomem:
+      Enomem:
 	printk(KERN_ERR "cciss: out of memory.\n");
-out:
+      out:
 	while (n--)
 		put_disk(disk[n]);
 	return -1;
@@ -3096,20 +3107,17 @@
  *  returns the number of block devices registered.
  */
 static int __devinit cciss_init_one(struct pci_dev *pdev,
-	const struct pci_device_id *ent)
+				    const struct pci_device_id *ent)
 {
 	request_queue_t *q;
 	int i;
 	int j;
 	int rc;
+	int dac;
 
-	printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
-			" bus %d dev %d func %d\n",
-		pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
-			PCI_FUNC(pdev->devfn));
 	i = alloc_cciss_hba();
-	if(i < 0)
-		return (-1);
+	if (i < 0)
+		return -1;
 
 	hba[i]->busy_initializing = 1;
 
@@ -3122,11 +3130,11 @@
 
 	/* configure PCI DMA stuff */
 	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
-		printk("cciss: using DAC cycles\n");
+		dac = 1;
 	else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
-		printk("cciss: not using DAC cycles\n");
+		dac = 0;
 	else {
-		printk("cciss: no suitable DMA available\n");
+		printk(KERN_ERR "cciss: no suitable DMA available\n");
 		goto clean1;
 	}
 
@@ -3138,60 +3146,69 @@
 	if (i < MAX_CTLR_ORIG)
 		hba[i]->major = COMPAQ_CISS_MAJOR + i;
 	rc = register_blkdev(hba[i]->major, hba[i]->devname);
-	if(rc == -EBUSY || rc == -EINVAL) {
+	if (rc == -EBUSY || rc == -EINVAL) {
 		printk(KERN_ERR
-			"cciss:  Unable to get major number %d for %s "
-			"on hba %d\n", hba[i]->major, hba[i]->devname, i);
+		       "cciss:  Unable to get major number %d for %s "
+		       "on hba %d\n", hba[i]->major, hba[i]->devname, i);
 		goto clean1;
-	}
-	else {
+	} else {
 		if (i >= MAX_CTLR_ORIG)
 			hba[i]->major = rc;
 	}
 
 	/* make sure the board interrupts are off */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-	if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
-		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-			hba[i]->devname, hba[i])) {
+	if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
+			SA_INTERRUPT | SA_SHIRQ, hba[i]->devname, hba[i])) {
 		printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
-			hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
+		       hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
 		goto clean2;
 	}
-	hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
-	hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent(
-		hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), 
-		&(hba[i]->cmd_pool_dhandle));
-	hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
-		hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), 
-		&(hba[i]->errinfo_pool_dhandle));
-	if((hba[i]->cmd_pool_bits == NULL) 
-		|| (hba[i]->cmd_pool == NULL)
-		|| (hba[i]->errinfo_pool == NULL)) {
-                printk( KERN_ERR "cciss: out of memory");
+
+	printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
+	       hba[i]->devname, pdev->device, pci_name(pdev),
+	       hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+
+	hba[i]->cmd_pool_bits =
+	    kmalloc(((NR_CMDS + BITS_PER_LONG -
+		      1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+	hba[i]->cmd_pool = (CommandList_struct *)
+	    pci_alloc_consistent(hba[i]->pdev,
+		    NR_CMDS * sizeof(CommandList_struct),
+		    &(hba[i]->cmd_pool_dhandle));
+	hba[i]->errinfo_pool = (ErrorInfo_struct *)
+	    pci_alloc_consistent(hba[i]->pdev,
+		    NR_CMDS * sizeof(ErrorInfo_struct),
+		    &(hba[i]->errinfo_pool_dhandle));
+	if ((hba[i]->cmd_pool_bits == NULL)
+	    || (hba[i]->cmd_pool == NULL)
+	    || (hba[i]->errinfo_pool == NULL)) {
+		printk(KERN_ERR "cciss: out of memory");
 		goto clean4;
 	}
 #ifdef CONFIG_CISS_SCSI_TAPE
-	hba[i]->scsi_rejects.complete = 
-		kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) * 
-			(NR_CMDS + 5), GFP_KERNEL);
+	hba[i]->scsi_rejects.complete =
+	    kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
+		    (NR_CMDS + 5), GFP_KERNEL);
 	if (hba[i]->scsi_rejects.complete == NULL) {
-                printk( KERN_ERR "cciss: out of memory");
+		printk(KERN_ERR "cciss: out of memory");
 		goto clean4;
 	}
 #endif
 	spin_lock_init(&hba[i]->lock);
 
-	/* Initialize the pdev driver private data. 
-		have it point to hba[i].  */
+	/* Initialize the pdev driver private data.
+	   have it point to hba[i].  */
 	pci_set_drvdata(pdev, hba[i]);
-	/* command and error info recs zeroed out before 
-			they are used */
-        memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
+	/* command and error info recs zeroed out before
+	   they are used */
+	memset(hba[i]->cmd_pool_bits, 0,
+	       ((NR_CMDS + BITS_PER_LONG -
+		 1) / BITS_PER_LONG) * sizeof(unsigned long));
 
-#ifdef CCISS_DEBUG	
-	printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
-#endif /* CCISS_DEBUG */
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n", i);
+#endif				/* CCISS_DEBUG */
 
 	cciss_getgeometry(i);
 
@@ -3203,15 +3220,15 @@
 	cciss_procinit(i);
 	hba[i]->busy_initializing = 0;
 
-	for(j=0; j < NWD; j++) { /* mfm */
+	for (j = 0; j < NWD; j++) {	/* mfm */
 		drive_info_struct *drv = &(hba[i]->drv[j]);
 		struct gendisk *disk = hba[i]->gendisk[j];
 
 		q = blk_init_queue(do_cciss_request, &hba[i]->lock);
 		if (!q) {
 			printk(KERN_ERR
-			   "cciss:  unable to allocate queue for disk %d\n",
-			   j);
+			       "cciss:  unable to allocate queue for disk %d\n",
+			       j);
 			break;
 		}
 		drv->queue = q;
@@ -3240,92 +3257,87 @@
 		disk->driverfs_dev = &pdev->dev;
 		/* we must register the controller even if no disks exist */
 		/* this is for the online array utilities */
-		if(!drv->heads && j)
+		if (!drv->heads && j)
 			continue;
 		blk_queue_hardsect_size(q, drv->block_size);
 		set_capacity(disk, drv->nr_blocks);
 		add_disk(disk);
 	}
 
-	return(1);
+	return 1;
 
-clean4:
+      clean4:
 #ifdef CONFIG_CISS_SCSI_TAPE
 	kfree(hba[i]->scsi_rejects.complete);
 #endif
 	kfree(hba[i]->cmd_pool_bits);
-	if(hba[i]->cmd_pool)
+	if (hba[i]->cmd_pool)
 		pci_free_consistent(hba[i]->pdev,
-			NR_CMDS * sizeof(CommandList_struct),
-			hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-	if(hba[i]->errinfo_pool)
+				    NR_CMDS * sizeof(CommandList_struct),
+				    hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
+	if (hba[i]->errinfo_pool)
 		pci_free_consistent(hba[i]->pdev,
-			NR_CMDS * sizeof( ErrorInfo_struct),
-			hba[i]->errinfo_pool,
-			hba[i]->errinfo_pool_dhandle);
+				    NR_CMDS * sizeof(ErrorInfo_struct),
+				    hba[i]->errinfo_pool,
+				    hba[i]->errinfo_pool_dhandle);
 	free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
-clean2:
+      clean2:
 	unregister_blkdev(hba[i]->major, hba[i]->devname);
-clean1:
-	release_io_mem(hba[i]);
+      clean1:
 	hba[i]->busy_initializing = 0;
 	free_hba(i);
-	return(-1);
+	return -1;
 }
 
-static void __devexit cciss_remove_one (struct pci_dev *pdev)
+static void __devexit cciss_remove_one(struct pci_dev *pdev)
 {
 	ctlr_info_t *tmp_ptr;
 	int i, j;
 	char flush_buf[4];
-	int return_code; 
+	int return_code;
 
-	if (pci_get_drvdata(pdev) == NULL)
-	{
-		printk( KERN_ERR "cciss: Unable to remove device \n");
+	if (pci_get_drvdata(pdev) == NULL) {
+		printk(KERN_ERR "cciss: Unable to remove device \n");
 		return;
 	}
 	tmp_ptr = pci_get_drvdata(pdev);
 	i = tmp_ptr->ctlr;
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cciss: device appears to "
-			"already be removed \n");
+		       "already be removed \n");
 		return;
 	}
 	/* Turn board interrupts off  and send the flush cache command */
 	/* sendcmd will turn off interrupt, and send the flush...
-	* To write all data in the battery backed cache to disks */
+	 * To write all data in the battery backed cache to disks */
 	memset(flush_buf, 0, 4);
 	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
-				TYPE_CMD);
-	if(return_code != IO_OK)
-	{
-		printk(KERN_WARNING "Error Flushing cache on controller %d\n", 
-			i);
+			      TYPE_CMD);
+	if (return_code != IO_OK) {
+		printk(KERN_WARNING "Error Flushing cache on controller %d\n",
+		       i);
 	}
 	free_irq(hba[i]->intr[2], hba[i]);
 
 #ifdef CONFIG_PCI_MSI
-        if (hba[i]->msix_vector)
-                pci_disable_msix(hba[i]->pdev);
-        else if (hba[i]->msi_vector)
-                pci_disable_msi(hba[i]->pdev);
-#endif /* CONFIG_PCI_MSI */
+	if (hba[i]->msix_vector)
+		pci_disable_msix(hba[i]->pdev);
+	else if (hba[i]->msi_vector)
+		pci_disable_msi(hba[i]->pdev);
+#endif				/* CONFIG_PCI_MSI */
 
-	pci_set_drvdata(pdev, NULL);
 	iounmap(hba[i]->vaddr);
-	cciss_unregister_scsi(i);  /* unhook from SCSI subsystem */
+	cciss_unregister_scsi(i);	/* unhook from SCSI subsystem */
 	unregister_blkdev(hba[i]->major, hba[i]->devname);
-	remove_proc_entry(hba[i]->devname, proc_cciss);	
-	
+	remove_proc_entry(hba[i]->devname, proc_cciss);
+
 	/* remove it from the disk list */
 	for (j = 0; j < NWD; j++) {
 		struct gendisk *disk = hba[i]->gendisk[j];
 		if (disk) {
 			request_queue_t *q = disk->queue;
 
-			if (disk->flags & GENHD_FL_UP) 
+			if (disk->flags & GENHD_FL_UP)
 				del_gendisk(disk);
 			if (q)
 				blk_cleanup_queue(q);
@@ -3334,26 +3346,28 @@
 
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
 			    hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
-		hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
+	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(ErrorInfo_struct),
+			    hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
 	kfree(hba[i]->cmd_pool_bits);
 #ifdef CONFIG_CISS_SCSI_TAPE
 	kfree(hba[i]->scsi_rejects.complete);
 #endif
- 	release_io_mem(hba[i]);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
 	free_hba(i);
-}	
+}
 
 static struct pci_driver cciss_pci_driver = {
-	.name =		"cciss",
-	.probe =	cciss_init_one,
-	.remove =	__devexit_p(cciss_remove_one),
-	.id_table =	cciss_pci_device_id, /* id_table */
+	.name = "cciss",
+	.probe = cciss_init_one,
+	.remove = __devexit_p(cciss_remove_one),
+	.id_table = cciss_pci_device_id,	/* id_table */
 };
 
 /*
  *  This is it.  Register the PCI driver information for the cards we control
- *  the OS will call our registered routines when it finds one of our cards. 
+ *  the OS will call our registered routines when it finds one of our cards.
  */
 static int __init cciss_init(void)
 {
@@ -3369,12 +3383,10 @@
 
 	pci_unregister_driver(&cciss_pci_driver);
 	/* double check that all controller entrys have been removed */
-	for (i=0; i< MAX_CTLR; i++) 
-	{
-		if (hba[i] != NULL)
-		{
+	for (i = 0; i < MAX_CTLR; i++) {
+		if (hba[i] != NULL) {
 			printk(KERN_WARNING "cciss: had to remove"
-					" controller %d\n", i);
+			       " controller %d\n", i);
 			cciss_remove_one(hba[i]->pdev);
 		}
 	}
@@ -3389,21 +3401,21 @@
 	unsigned long flags;
 
 	printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
-	h->alive = 0;	/* the controller apparently died... */
+	h->alive = 0;		/* the controller apparently died... */
 
 	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 
-	pci_disable_device(h->pdev); /* Make sure it is really dead. */
+	pci_disable_device(h->pdev);	/* Make sure it is really dead. */
 
 	/* move everything off the request queue onto the completed queue */
-	while( (c = h->reqQ) != NULL ) {
+	while ((c = h->reqQ) != NULL) {
 		removeQ(&(h->reqQ), c);
 		h->Qdepth--;
-		addQ (&(h->cmpQ), c);
+		addQ(&(h->cmpQ), c);
 	}
 
 	/* Now, fail everything on the completed queue with a HW error */
-	while( (c = h->cmpQ) != NULL ) {
+	while ((c = h->cmpQ) != NULL) {
 		removeQ(&h->cmpQ, c);
 		c->err_info->CommandStatus = CMD_HARDWARE_ERR;
 		if (c->cmd_type == CMD_RWREQ) {
@@ -3411,8 +3423,8 @@
 		} else if (c->cmd_type == CMD_IOCTL_PEND)
 			complete(c->waiting);
 #ifdef CONFIG_CISS_SCSI_TAPE
-			else if (c->cmd_type == CMD_SCSI)
-				complete_scsi_command(c, 0, 0);
+		else if (c->cmd_type == CMD_SCSI)
+			complete_scsi_command(c, 0, 0);
 #endif
 	}
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index b24fc05..868e0d8 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -60,8 +60,6 @@
 	__u32	board_id;
 	void __iomem *vaddr;
 	unsigned long paddr;
-	unsigned long io_mem_addr;
-	unsigned long io_mem_length;
 	CfgTable_struct __iomem *cfgtable;
 	int	interrupts_enabled;
 	int	major;
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index b6ea2f0..5eb6fb7 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -392,7 +392,7 @@
 }
 
 /* pdev is NULL for eisa */
-static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
+static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
 {
 	request_queue_t *q;
 	int j;
@@ -410,8 +410,7 @@
 	}
 	hba[i]->access.set_intr_mask(hba[i], 0);
 	if (request_irq(hba[i]->intr, do_ida_intr,
-		SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM,
-		hba[i]->devname, hba[i]))
+		SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
 	{
 		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
 				hba[i]->intr, hba[i]->devname);
@@ -745,7 +744,7 @@
 /*
  * Find an EISA controller's signature.  Set up an hba if we find it.
  */
-static int cpqarray_eisa_detect(void)
+static int __init cpqarray_eisa_detect(void)
 {
 	int i=0, j;
 	__u32 board_id;
@@ -1036,6 +1035,8 @@
 
 	complete_buffers(cmd->rq->bio, ok);
 
+	add_disk_randomness(cmd->rq->rq_disk);
+
         DBGPX(printk("Done with %p\n", cmd->rq););
 	end_that_request_last(cmd->rq, ok ? 1 : -EIO);
 }
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8bca490..7f554f2 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -7,39 +7,9 @@
  * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
  * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
  *
- * (part of code stolen from loop.c)
+ * This file is released under GPLv2 or later.
  *
- * 97-3-25 compiled 0-th version, not yet tested it 
- *   (it did not work, BTW) (later that day) HEY! it works!
- *   (bit later) hmm, not that much... 2:00am next day:
- *   yes, it works, but it gives something like 50kB/sec
- * 97-4-01 complete rewrite to make it possible for many requests at 
- *   once to be processed
- * 97-4-11 Making protocol independent of endianity etc.
- * 97-9-13 Cosmetic changes
- * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines
- * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines <ankry@mif.pg.gda.pl>
- * 01-2-27 Fix to store proper blockcount for kernel (calculated using
- *   BLOCK_SIZE_BITS, not device blocksize) <aga@permonline.ru>
- * 01-3-11 Make nbd work with new Linux block layer code. It now supports
- *   plugging like all the other block devices. Also added in MSG_MORE to
- *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
- * 01-12-6 Fix deadlock condition by making queue locks independent of
- *   the transmit lock. <steve@chygwyn.com>
- * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
- *   <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
- * 03-06-22 Make nbd work with new linux 2.5 block layer design. This fixes
- *   memory corruption from module removal and possible memory corruption
- *   from sending/receiving disk data. <ldl@aros.net>
- * 03-06-23 Cosmetic changes. <ldl@aros.net>
- * 03-06-23 Enhance diagnostics support. <ldl@aros.net>
- * 03-06-24 Remove unneeded blksize_bits field from nbd_device struct.
- *   <ldl@aros.net>
- * 03-06-24 Cleanup PARANOIA usage & code. <ldl@aros.net>
- * 04-02-19 Remove PARANOIA, plus various cleanups (Paul Clements)
- * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
- * why not: would need access_ok and friends, would share yet another
- *          structure with userland
+ * (part of code stolen from loop.c)
  */
 
 #include <linux/major.h>
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index a71a240..ed8dca8 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -423,6 +423,9 @@
 	nsh.len = skb->len;
 
 	s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+	if (!s)
+		return -ENOMEM;
+
 	skb_reserve(s, NSHL);
 	memcpy(skb_put(s, skb->len), skb->data, skb->len);
 	if (skb->len & 0x0001)
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index a0b580c..0f6e7aa 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -1006,7 +1006,7 @@
 
 /* MODULE STUFF ***********************************************************/
 
-int __mcdx_init(void)
+static int __init __mcdx_init(void)
 {
 	int i;
 	int drives = 0;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 78d928f..3610c57 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -62,6 +62,23 @@
 	depends on VT && !S390 && !UML
 	default y
 
+config VT_HW_CONSOLE_BINDING
+       bool "Support for binding and unbinding console drivers"
+       depends on HW_CONSOLE
+       default n
+       ---help---
+         The virtual terminal is the device that interacts with the physical
+         terminal through console drivers. On these systems, at least one
+         console driver is loaded. In other configurations, additional console
+         drivers may be enabled, such as the framebuffer console. If more than
+         1 console driver is enabled, setting this to 'y' will allow you to
+         select the console driver that will serve as the backend for the
+         virtual terminals.
+
+	 See <file:Documentation/console/console.txt> for more
+	 information. For framebuffer console users, please refer to
+	 <file:Documentation/fb/fbcon.txt>.
+
 config SERIAL_NONSTANDARD
 	bool "Non-standard serial port support"
 	---help---
@@ -670,20 +687,7 @@
 
 	  If you're not sure, say N.
 
-config HW_RANDOM
-	tristate "Intel/AMD/VIA HW Random Number Generator support"
-	depends on (X86 || IA64) && PCI
-	---help---
-	  This driver provides kernel-side support for the Random Number
-	  Generator hardware found on Intel i8xx-based motherboards,
-	  AMD 76x-based motherboards, and Via Nehemiah CPUs.
-
-	  Provides a character driver, used to read() entropy data.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called hw_random.
-
-	  If unsure, say N.
+source "drivers/char/hw_random/Kconfig"
 
 config NVRAM
 	tristate "/dev/nvram support"
@@ -865,6 +869,7 @@
 config TANBAC_TB0219
 	tristate "TANBAC TB0219 base board support"
 	depends TANBAC_TB022X
+	select GPIO_VR41XX
 
 menu "Ftape, the floppy tape device driver"
 
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index fb919bf..5241055 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -75,7 +75,7 @@
 obj-$(CONFIG_TOSHIBA)		+= toshiba.o
 obj-$(CONFIG_I8K)		+= i8k.o
 obj-$(CONFIG_DS1620)		+= ds1620.o
-obj-$(CONFIG_HW_RANDOM)		+= hw_random.o
+obj-$(CONFIG_HW_RANDOM)		+= hw_random/
 obj-$(CONFIG_FTAPE)		+= ftape/
 obj-$(CONFIG_COBALT_LCD)	+= lcd.o
 obj-$(CONFIG_PPDEV)		+= ppdev.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 46685a5..9826a39 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -55,9 +55,9 @@
 	  X on AMD Irongate, 761, and 762 chipsets.
 
 config AGP_AMD64
-	tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU
+	tristate "AMD Opteron/Athlon64 on-CPU GART support" if !IOMMU
 	depends on AGP && X86
-	default y if GART_IOMMU
+	default y if IOMMU
 	help
 	  This option gives you AGP support for the GLX component of
 	  X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 1f77665..51d0d56 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -118,7 +118,7 @@
 	return retval;
 }
 
-/* Since we don't need contigious memory we just try
+/* Since we don't need contiguous memory we just try
  * to get the gatt table once
  */
 
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index ac3c33a..f690ee8 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -15,11 +15,9 @@
 #include <linux/agp_backend.h>
 #include <linux/mmzone.h>
 #include <asm/page.h>		/* PAGE_SIZE */
+#include <asm/k8.h>
 #include "agp.h"
 
-/* Will need to be increased if AMD64 ever goes >8-way. */
-#define MAX_HAMMER_GARTS   8
-
 /* PTE bits. */
 #define GPTE_VALID	1
 #define GPTE_COHERENT	2
@@ -53,28 +51,12 @@
 #define ULI_X86_64_HTT_FEA_REG		0x50
 #define ULI_X86_64_ENU_SCR_REG		0x54
 
-static int nr_garts;
-static struct pci_dev * hammers[MAX_HAMMER_GARTS];
-
 static struct resource *aperture_resource;
 static int __initdata agp_try_unsupported = 1;
 
-#define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++)
-
-static void flush_amd64_tlb(struct pci_dev *dev)
-{
-	u32 tmp;
-
-	pci_read_config_dword (dev, AMD64_GARTCACHECTL, &tmp);
-	tmp |= INVGART;
-	pci_write_config_dword (dev, AMD64_GARTCACHECTL, tmp);
-}
-
 static void amd64_tlbflush(struct agp_memory *temp)
 {
-	int gart_iterator;
-	for_each_nb()
-		flush_amd64_tlb(hammers[gart_iterator]);
+	k8_flush_garts();
 }
 
 static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
@@ -153,7 +135,7 @@
 	u32 temp;
 	struct aper_size_info_32 *values;
 
-	dev = hammers[0];
+	dev = k8_northbridges[0];
 	if (dev==NULL)
 		return 0;
 
@@ -201,9 +183,6 @@
 	tmp &= ~(DISGARTCPU | DISGARTIO);
 	pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp);
 
-	/* keep CPU's coherent. */
-	flush_amd64_tlb (hammer);
-
 	return aper_base;
 }
 
@@ -222,13 +201,14 @@
 static int amd_8151_configure(void)
 {
 	unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real);
-	int gart_iterator;
+	int i;
 
 	/* Configure AGP regs in each x86-64 host bridge. */
-	for_each_nb() {
+        for (i = 0; i < num_k8_northbridges; i++) {
 		agp_bridge->gart_bus_addr =
-				amd64_configure(hammers[gart_iterator],gatt_bus);
+				amd64_configure(k8_northbridges[i], gatt_bus);
 	}
+	k8_flush_garts();
 	return 0;
 }
 
@@ -236,12 +216,13 @@
 static void amd64_cleanup(void)
 {
 	u32 tmp;
-	int gart_iterator;
-	for_each_nb() {
+	int i;
+        for (i = 0; i < num_k8_northbridges; i++) {
+		struct pci_dev *dev = k8_northbridges[i];
 		/* disable gart translation */
-		pci_read_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, &tmp);
+		pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp);
 		tmp &= ~AMD64_GARTEN;
-		pci_write_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, tmp);
+		pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp);
 	}
 }
 
@@ -311,7 +292,7 @@
 /*
  * W*s centric BIOS sometimes only set up the aperture in the AGP
  * bridge, not the northbridge. On AMD64 this is handled early
- * in aperture.c, but when GART_IOMMU is not enabled or we run
+ * in aperture.c, but when IOMMU is not enabled or we run
  * on a 32bit kernel this needs to be redone.
  * Unfortunately it is impossible to fix the aperture here because it's too late
  * to allocate that much memory. But at least error out cleanly instead of
@@ -361,17 +342,15 @@
 
 static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
 {
-	struct pci_dev *loop_dev = NULL;
-	int i = 0;
+	int i;
 
-	/* cache pci_devs of northbridges. */
-	while ((loop_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev))
-			!= NULL) {
-		if (i == MAX_HAMMER_GARTS) {
-			printk(KERN_ERR PFX "Too many northbridges for AGP\n");
-			return -1;
-		}
-		if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) {
+	if (cache_k8_northbridges() < 0)
+		return -ENODEV;
+
+	i = 0;
+	for (i = 0; i < num_k8_northbridges; i++) {
+		struct pci_dev *dev = k8_northbridges[i];
+		if (fix_northbridge(dev, pdev, cap_ptr) < 0) {
 			printk(KERN_ERR PFX "No usable aperture found.\n");
 #ifdef __x86_64__
 			/* should port this to i386 */
@@ -379,10 +358,8 @@
 #endif
 			return -1;
 		}
-		hammers[i++] = loop_dev;
 	}
-		nr_garts = i;
-	return i == 0 ? -1 : 0;
+	return 0;
 }
 
 /* Handle AMD 8151 quirks */
@@ -450,7 +427,7 @@
 	}
 
 	/* shadow x86-64 registers into ULi registers */
-	pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea);
+	pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea);
 
 	/* if x86-64 aperture base is beyond 4G, exit here */
 	if ((httfea & 0x7fff) >> (32 - 25))
@@ -513,7 +490,7 @@
 	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp);
 
 	/* shadow x86-64 registers into NVIDIA registers */
-	pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase);
+	pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase);
 
 	/* if x86-64 aperture base is beyond 4G, exit here */
 	if ( (apbase & 0x7fff) >> (32 - 25) ) {
@@ -754,10 +731,6 @@
 int __init agp_amd64_init(void)
 {
 	int err = 0;
-	static struct pci_device_id amd64nb[] = {
-		{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
-		{ },
-	};
 
 	if (agp_off)
 		return -EINVAL;
@@ -774,7 +747,7 @@
 		}
 
 		/* First check that we have at least one AMD64 NB */
-		if (!pci_dev_present(amd64nb))
+		if (!pci_dev_present(k8_nb_ids))
 			return -ENODEV;
 
 		/* Look for any AGP bridge */
@@ -802,7 +775,7 @@
 
 /* On AMD64 the PCI driver needs to initialize this driver early
    for the IOMMU, so it has to be called via a backdoor. */
-#ifndef CONFIG_GART_IOMMU
+#ifndef CONFIG_IOMMU
 module_init(agp_amd64_init);
 module_exit(agp_amd64_cleanup);
 #endif
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 06fd10b..1605643 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -261,7 +261,7 @@
 #endif
 
 /*
- *Since we don't need contigious memory we just try
+ *Since we don't need contiguous memory we just try
  * to get the gatt table once
  */
 
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 86a966b..b788b0a 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -177,7 +177,7 @@
 
 
 /*
- * Since we don't need contigious memory we just try
+ * Since we don't need contiguous memory we just try
  * to get the gatt table once
  */
 
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index a370e7a..9275d5e 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -166,11 +166,7 @@
 	return boardno + 1;
 }
 
-#ifdef MODULE
-
-#define applicom_init init_module
-
-void cleanup_module(void)
+static void __exit applicom_exit(void)
 {
 	unsigned int i;
 
@@ -188,9 +184,7 @@
 	}
 }
 
-#endif				/* MODULE */
-
-int __init applicom_init(void)
+static int __init applicom_init(void)
 {
 	int i, numisa = 0;
 	struct pci_dev *dev = NULL;
@@ -355,10 +349,9 @@
 	return ret;
 }
 
+module_init(applicom_init);
+module_exit(applicom_exit);
 
-#ifndef MODULE
-__initcall(applicom_init);
-#endif
 
 static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 {
@@ -851,28 +844,3 @@
 	return 0;
 }
 
-#ifndef MODULE
-static int __init applicom_setup(char *str)
-{
-	int ints[4];
-
-	(void) get_options(str, 4, ints);
-
-	if (ints[0] > 2) {
-		printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
-	}
-
-	if (ints[0] < 2) {
-		printk(KERN_INFO"applicom numargs: %d\n", ints[0]);
-		return 0;
-	}
-
-	mem = ints[1];
-	irq = ints[2];
-	return 1;
-}
-
-__setup("applicom=", applicom_setup);
-
-#endif				/* MODULE */
-
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index cc7acf8..122e7a7 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -2833,9 +2833,8 @@
         return 0;
     }
         
-    if (!tty || !info->xmit_buf || !tmp_buf){
-        return 0;
-    }
+    if (!info->xmit_buf || !tmp_buf)
+	return 0;
 
     CY_LOCK(info, flags);
     while (1) {
@@ -2884,7 +2883,7 @@
     if (serial_paranoia_check(info, tty->name, "cy_put_char"))
         return;
 
-    if (!tty || !info->xmit_buf)
+    if (!info->xmit_buf)
         return;
 
     CY_LOCK(info, flags);
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 09dc4b0..922174d 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1212,7 +1212,7 @@
 	if (serial_paranoia_check(info, tty->name, "rs_put_char"))
 		return;
 
-	if (!tty || !info->xmit_buf)
+	if (!info->xmit_buf)
 		return;
 
 	spin_lock_irqsave(&info->lock, flags);
@@ -1256,7 +1256,7 @@
 	if (serial_paranoia_check(info, tty->name, "rs_write"))
 		return 0;
 
-	if (!tty || !info->xmit_buf)
+	if (!info->xmit_buf)
 		return 0;
 	    
 	while (1) {
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index ac62641..d69f2ad 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -117,12 +117,12 @@
 __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
 #endif /* not MODULE */
 
-#if defined(CONFIG_X86) || defined(CONFIG_S390)
+#if defined(CONFIG_X86_64) || defined(CONFIG_S390)
 # define HAVE_MONOTONIC
 # define TIMER_FREQ 1000000000ULL
 #elif defined(CONFIG_IA64)
 # define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq)
-#elif defined(CONFIG_PPC64)
+#else
 # define TIMER_FREQ (HZ*loops_per_jiffy)
 #endif
 
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c
deleted file mode 100644
index 29dc87e..0000000
--- a/drivers/char/hw_random.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
-        Added support for the AMD Geode LX RNG
-	(c) Copyright 2004-2005 Advanced Micro Devices, Inc.
-
-	derived from
-
- 	Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
-	(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
- 
- 	derived from
- 
-        Hardware driver for the AMD 768 Random Number Generator (RNG)
-        (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
-
- 	derived from
- 
-	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
-	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
-
-	Please read Documentation/hw_random.txt for details on use.
-
-	----------------------------------------------------------
-	This software may be used and distributed according to the terms
-        of the GNU General Public License, incorporated herein by reference.
-
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/random.h>
-#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#ifdef __i386__
-#include <asm/msr.h>
-#include <asm/cpufeature.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-
-/*
- * core module and version information
- */
-#define RNG_VERSION "1.0.0"
-#define RNG_MODULE_NAME "hw_random"
-#define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
-#define PFX RNG_MODULE_NAME ": "
-
-
-/*
- * debugging macros
- */
-
-/* pr_debug() collapses to a no-op if DEBUG is not defined */
-#define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args)
-
-
-#undef RNG_NDEBUG        /* define to enable lightweight runtime checks */
-#ifdef RNG_NDEBUG
-#define assert(expr)							\
-		if(!(expr)) {						\
-		printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s,"	\
-		"line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__);	\
-		}
-#else
-#define assert(expr)
-#endif
-
-#define RNG_MISCDEV_MINOR		183 /* official */
-
-static int rng_dev_open (struct inode *inode, struct file *filp);
-static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
-				loff_t * offp);
-
-static int __init intel_init (struct pci_dev *dev);
-static void intel_cleanup(void);
-static unsigned int intel_data_present (void);
-static u32 intel_data_read (void);
-
-static int __init amd_init (struct pci_dev *dev);
-static void amd_cleanup(void);
-static unsigned int amd_data_present (void);
-static u32 amd_data_read (void);
-
-#ifdef __i386__
-static int __init via_init(struct pci_dev *dev);
-static void via_cleanup(void);
-static unsigned int via_data_present (void);
-static u32 via_data_read (void);
-#endif
-
-static int __init geode_init(struct pci_dev *dev);
-static void geode_cleanup(void);
-static unsigned int geode_data_present (void);
-static u32 geode_data_read (void);
-
-struct rng_operations {
-	int (*init) (struct pci_dev *dev);
-	void (*cleanup) (void);
-	unsigned int (*data_present) (void);
-	u32 (*data_read) (void);
-	unsigned int n_bytes; /* number of bytes per ->data_read */
-};
-static struct rng_operations *rng_ops;
-
-static struct file_operations rng_chrdev_ops = {
-	.owner		= THIS_MODULE,
-	.open		= rng_dev_open,
-	.read		= rng_dev_read,
-};
-
-
-static struct miscdevice rng_miscdev = {
-	RNG_MISCDEV_MINOR,
-	RNG_MODULE_NAME,
-	&rng_chrdev_ops,
-};
-
-enum {
-	rng_hw_none,
-	rng_hw_intel,
-	rng_hw_amd,
-#ifdef __i386__
-	rng_hw_via,
-#endif
-	rng_hw_geode,
-};
-
-static struct rng_operations rng_vendor_ops[] = {
-	/* rng_hw_none */
-	{ },
-
-	/* rng_hw_intel */
-	{ intel_init, intel_cleanup, intel_data_present,
-	  intel_data_read, 1 },
-
-	/* rng_hw_amd */
-	{ amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
-
-#ifdef __i386__
-	/* rng_hw_via */
-	{ via_init, via_cleanup, via_data_present, via_data_read, 1 },
-#endif
-
-	/* rng_hw_geode */
-	{ geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
-};
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id rng_pci_tbl[] = {
-	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
-	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
-
-	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-	{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-
-	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode },
-
-	{ 0, },	/* terminate list */
-};
-MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
-
-
-/***********************************************************************
- *
- * Intel RNG operations
- *
- */
-
-/*
- * RNG registers (offsets from rng_mem)
- */
-#define INTEL_RNG_HW_STATUS			0
-#define         INTEL_RNG_PRESENT		0x40
-#define         INTEL_RNG_ENABLED		0x01
-#define INTEL_RNG_STATUS			1
-#define         INTEL_RNG_DATA_PRESENT		0x01
-#define INTEL_RNG_DATA				2
-
-/*
- * Magic address at which Intel PCI bridges locate the RNG
- */
-#define INTEL_RNG_ADDR				0xFFBC015F
-#define INTEL_RNG_ADDR_LEN			3
-
-/* token to our ioremap'd RNG register area */
-static void __iomem *rng_mem;
-
-static inline u8 intel_hwstatus (void)
-{
-	assert (rng_mem != NULL);
-	return readb (rng_mem + INTEL_RNG_HW_STATUS);
-}
-
-static inline u8 intel_hwstatus_set (u8 hw_status)
-{
-	assert (rng_mem != NULL);
-	writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
-	return intel_hwstatus ();
-}
-
-static unsigned int intel_data_present(void)
-{
-	assert (rng_mem != NULL);
-
-	return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
-		1 : 0;
-}
-
-static u32 intel_data_read(void)
-{
-	assert (rng_mem != NULL);
-
-	return readb (rng_mem + INTEL_RNG_DATA);
-}
-
-static int __init intel_init (struct pci_dev *dev)
-{
-	int rc;
-	u8 hw_status;
-
-	DPRINTK ("ENTER\n");
-
-	rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
-	if (rng_mem == NULL) {
-		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
-		rc = -EBUSY;
-		goto err_out;
-	}
-
-	/* Check for Intel 82802 */
-	hw_status = intel_hwstatus ();
-	if ((hw_status & INTEL_RNG_PRESENT) == 0) {
-		printk (KERN_ERR PFX "RNG not detected\n");
-		rc = -ENODEV;
-		goto err_out_free_map;
-	}
-
-	/* turn RNG h/w on, if it's off */
-	if ((hw_status & INTEL_RNG_ENABLED) == 0)
-		hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
-	if ((hw_status & INTEL_RNG_ENABLED) == 0) {
-		printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
-		rc = -EIO;
-		goto err_out_free_map;
-	}
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-
-err_out_free_map:
-	iounmap (rng_mem);
-	rng_mem = NULL;
-err_out:
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
-}
-
-static void intel_cleanup(void)
-{
-	u8 hw_status;
-
-	hw_status = intel_hwstatus ();
-	if (hw_status & INTEL_RNG_ENABLED)
-		intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
-	else
-		printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
-	iounmap(rng_mem);
-	rng_mem = NULL;
-}
-
-/***********************************************************************
- *
- * AMD RNG operations
- *
- */
-
-static u32 pmbase;			/* PMxx I/O base */
-static struct pci_dev *amd_dev;
-
-static unsigned int amd_data_present (void)
-{
-      	return inl(pmbase + 0xF4) & 1;
-}
-
-
-static u32 amd_data_read (void)
-{
-	return inl(pmbase + 0xF0);
-}
-
-static int __init amd_init (struct pci_dev *dev)
-{
-	int rc;
-	u8 rnen;
-
-	DPRINTK ("ENTER\n");
-
-	pci_read_config_dword(dev, 0x58, &pmbase);
-
-	pmbase &= 0x0000FF00;
-
-	if (pmbase == 0)
-	{
-		printk (KERN_ERR PFX "power management base not set\n");
-		rc = -EIO;
-		goto err_out;
-	}
-
-	pci_read_config_byte(dev, 0x40, &rnen);
-	rnen |= (1 << 7);	/* RNG on */
-	pci_write_config_byte(dev, 0x40, rnen);
-
-	pci_read_config_byte(dev, 0x41, &rnen);
-	rnen |= (1 << 7);	/* PMIO enable */
-	pci_write_config_byte(dev, 0x41, rnen);
-
-	pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
-			pmbase);
-
-	amd_dev = dev;
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-
-err_out:
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
-}
-
-static void amd_cleanup(void)
-{
-	u8 rnen;
-
-	pci_read_config_byte(amd_dev, 0x40, &rnen);
-	rnen &= ~(1 << 7);	/* RNG off */
-	pci_write_config_byte(amd_dev, 0x40, rnen);
-
-	/* FIXME: twiddle pmio, also? */
-}
-
-#ifdef __i386__
-/***********************************************************************
- *
- * VIA RNG operations
- *
- */
-
-enum {
-	VIA_STRFILT_CNT_SHIFT	= 16,
-	VIA_STRFILT_FAIL	= (1 << 15),
-	VIA_STRFILT_ENABLE	= (1 << 14),
-	VIA_RAWBITS_ENABLE	= (1 << 13),
-	VIA_RNG_ENABLE		= (1 << 6),
-	VIA_XSTORE_CNT_MASK	= 0x0F,
-
-	VIA_RNG_CHUNK_8		= 0x00,	/* 64 rand bits, 64 stored bits */
-	VIA_RNG_CHUNK_4		= 0x01,	/* 32 rand bits, 32 stored bits */
-	VIA_RNG_CHUNK_4_MASK	= 0xFFFFFFFF,
-	VIA_RNG_CHUNK_2		= 0x02,	/* 16 rand bits, 32 stored bits */
-	VIA_RNG_CHUNK_2_MASK	= 0xFFFF,
-	VIA_RNG_CHUNK_1		= 0x03,	/* 8 rand bits, 32 stored bits */
-	VIA_RNG_CHUNK_1_MASK	= 0xFF,
-};
-
-static u32 via_rng_datum;
-
-/*
- * Investigate using the 'rep' prefix to obtain 32 bits of random data
- * in one insn.  The upside is potentially better performance.  The
- * downside is that the instruction becomes no longer atomic.  Due to
- * this, just like familiar issues with /dev/random itself, the worst
- * case of a 'rep xstore' could potentially pause a cpu for an
- * unreasonably long time.  In practice, this condition would likely
- * only occur when the hardware is failing.  (or so we hope :))
- *
- * Another possible performance boost may come from simply buffering
- * until we have 4 bytes, thus returning a u32 at a time,
- * instead of the current u8-at-a-time.
- */
-
-static inline u32 xstore(u32 *addr, u32 edx_in)
-{
-	u32 eax_out;
-
-	asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
-		:"=m"(*addr), "=a"(eax_out)
-		:"D"(addr), "d"(edx_in));
-
-	return eax_out;
-}
-
-static unsigned int via_data_present(void)
-{
-	u32 bytes_out;
-
-	/* We choose the recommended 1-byte-per-instruction RNG rate,
-	 * for greater randomness at the expense of speed.  Larger
-	 * values 2, 4, or 8 bytes-per-instruction yield greater
-	 * speed at lesser randomness.
-	 *
-	 * If you change this to another VIA_CHUNK_n, you must also
-	 * change the ->n_bytes values in rng_vendor_ops[] tables.
-	 * VIA_CHUNK_8 requires further code changes.
-	 *
-	 * A copy of MSR_VIA_RNG is placed in eax_out when xstore
-	 * completes.
-	 */
-	via_rng_datum = 0; /* paranoia, not really necessary */
-	bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
-	if (bytes_out == 0)
-		return 0;
-
-	return 1;
-}
-
-static u32 via_data_read(void)
-{
-	return via_rng_datum;
-}
-
-static int __init via_init(struct pci_dev *dev)
-{
-	u32 lo, hi, old_lo;
-
-	/* Control the RNG via MSR.  Tread lightly and pay very close
-	 * close attention to values written, as the reserved fields
-	 * are documented to be "undefined and unpredictable"; but it
-	 * does not say to write them as zero, so I make a guess that
-	 * we restore the values we find in the register.
-	 */
-	rdmsr(MSR_VIA_RNG, lo, hi);
-
-	old_lo = lo;
-	lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
-	lo &= ~VIA_XSTORE_CNT_MASK;
-	lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
-	lo |= VIA_RNG_ENABLE;
-
-	if (lo != old_lo)
-		wrmsr(MSR_VIA_RNG, lo, hi);
-
-	/* perhaps-unnecessary sanity check; remove after testing if
-	   unneeded */
-	rdmsr(MSR_VIA_RNG, lo, hi);
-	if ((lo & VIA_RNG_ENABLE) == 0) {
-		printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void via_cleanup(void)
-{
-	/* do nothing */
-}
-#endif
-
-/***********************************************************************
- *
- * AMD Geode RNG operations
- *
- */
-
-static void __iomem *geode_rng_base = NULL;
-
-#define GEODE_RNG_DATA_REG   0x50
-#define GEODE_RNG_STATUS_REG 0x54
-
-static u32 geode_data_read(void)
-{
-	u32 val;
-
-	assert(geode_rng_base != NULL);
-	val = readl(geode_rng_base + GEODE_RNG_DATA_REG);
-	return val;
-}
-
-static unsigned int geode_data_present(void)
-{
-	u32 val;
-
-	assert(geode_rng_base != NULL);
-	val = readl(geode_rng_base + GEODE_RNG_STATUS_REG);
-	return val;
-}
-
-static void geode_cleanup(void)
-{
-	iounmap(geode_rng_base);
-  	geode_rng_base = NULL;
-}
-
-static int geode_init(struct pci_dev *dev)
-{
-	unsigned long rng_base = pci_resource_start(dev, 0);
-
-	if (rng_base == 0)
-		return 1;
-
-	geode_rng_base = ioremap(rng_base, 0x58);
-
-	if (geode_rng_base == NULL) {
-		printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-/***********************************************************************
- *
- * /dev/hwrandom character device handling (major 10, minor 183)
- *
- */
-
-static int rng_dev_open (struct inode *inode, struct file *filp)
-{
-	/* enforce read-only access to this chrdev */
-	if ((filp->f_mode & FMODE_READ) == 0)
-		return -EINVAL;
-	if (filp->f_mode & FMODE_WRITE)
-		return -EINVAL;
-
-	return 0;
-}
-
-
-static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
-				loff_t * offp)
-{
-	static DEFINE_SPINLOCK(rng_lock);
-	unsigned int have_data;
-	u32 data = 0;
-	ssize_t ret = 0;
-
-	while (size) {
-		spin_lock(&rng_lock);
-
-		have_data = 0;
-		if (rng_ops->data_present()) {
-			data = rng_ops->data_read();
-			have_data = rng_ops->n_bytes;
-		}
-
-		spin_unlock (&rng_lock);
-
-		while (have_data && size) {
-			if (put_user((u8)data, buf++)) {
-				ret = ret ? : -EFAULT;
-				break;
-			}
-			size--;
-			ret++;
-			have_data--;
-			data>>=8;
-		}
-
-		if (filp->f_flags & O_NONBLOCK)
-			return ret ? : -EAGAIN;
-
-		if(need_resched())
-			schedule_timeout_interruptible(1);
-		else
-			udelay(200);	/* FIXME: We could poll for 250uS ?? */
-
-		if (signal_pending (current))
-			return ret ? : -ERESTARTSYS;
-	}
-	return ret;
-}
-
-
-
-/*
- * rng_init_one - look for and attempt to init a single RNG
- */
-static int __init rng_init_one (struct pci_dev *dev)
-{
-	int rc;
-
-	DPRINTK ("ENTER\n");
-
-	assert(rng_ops != NULL);
-
-	rc = rng_ops->init(dev);
-	if (rc)
-		goto err_out;
-
-	rc = misc_register (&rng_miscdev);
-	if (rc) {
-		printk (KERN_ERR PFX "misc device register failed\n");
-		goto err_out_cleanup_hw;
-	}
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-
-err_out_cleanup_hw:
-	rng_ops->cleanup();
-err_out:
-	DPRINTK ("EXIT, returning %d\n", rc);
-	return rc;
-}
-
-
-
-MODULE_AUTHOR("The Linux Kernel team");
-MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
-MODULE_LICENSE("GPL");
-
-
-/*
- * rng_init - initialize RNG module
- */
-static int __init rng_init (void)
-{
-	int rc;
-	struct pci_dev *pdev = NULL;
-	const struct pci_device_id *ent;
-
-	DPRINTK ("ENTER\n");
-
-	/* Probe for Intel, AMD, Geode RNGs */
-	for_each_pci_dev(pdev) {
-		ent = pci_match_id(rng_pci_tbl, pdev);
-		if (ent) {
-			rng_ops = &rng_vendor_ops[ent->driver_data];
-			goto match;
-		}
-	}
-
-#ifdef __i386__
-	/* Probe for VIA RNG */
-	if (cpu_has_xstore) {
-		rng_ops = &rng_vendor_ops[rng_hw_via];
-		pdev = NULL;
-		goto match;
-	}
-#endif
-
-	DPRINTK ("EXIT, returning -ENODEV\n");
-	return -ENODEV;
-
-match:
-	rc = rng_init_one (pdev);
-	if (rc)
-		return rc;
-
-	pr_info( RNG_DRIVER_NAME " loaded\n");
-
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
-}
-
-
-/*
- * rng_init - shutdown RNG module
- */
-static void __exit rng_cleanup (void)
-{
-	DPRINTK ("ENTER\n");
-
-	misc_deregister (&rng_miscdev);
-
-	if (rng_ops->cleanup)
-		rng_ops->cleanup();
-
-	DPRINTK ("EXIT\n");
-}
-
-
-module_init (rng_init);
-module_exit (rng_cleanup);
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
new file mode 100644
index 0000000..9f7635f
--- /dev/null
+++ b/drivers/char/hw_random/Kconfig
@@ -0,0 +1,90 @@
+#
+# Hardware Random Number Generator (RNG) configuration
+#
+
+config HW_RANDOM
+	bool "Hardware Random Number Generator Core support"
+	default y
+	---help---
+	  Hardware Random Number Generator Core infrastructure.
+
+	  If unsure, say Y.
+
+config HW_RANDOM_INTEL
+	tristate "Intel HW Random Number Generator support"
+	depends on HW_RANDOM && (X86 || IA64) && PCI
+	default y
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on Intel i8xx-based motherboards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called intel-rng.
+
+	  If unsure, say Y.
+
+config HW_RANDOM_AMD
+	tristate "AMD HW Random Number Generator support"
+	depends on HW_RANDOM && X86 && PCI
+	default y
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on AMD 76x-based motherboards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called amd-rng.
+
+	  If unsure, say Y.
+
+config HW_RANDOM_GEODE
+	tristate "AMD Geode HW Random Number Generator support"
+	depends on HW_RANDOM && X86 && PCI
+	default y
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on the AMD Geode LX.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called geode-rng.
+
+	  If unsure, say Y.
+
+config HW_RANDOM_VIA
+	tristate "VIA HW Random Number Generator support"
+	depends on HW_RANDOM && X86_32
+	default y
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on VIA based motherboards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called via-rng.
+
+	  If unsure, say Y.
+
+config HW_RANDOM_IXP4XX
+	tristate "Intel IXP4xx NPU HW Random Number Generator support"
+	depends on HW_RANDOM && ARCH_IXP4XX
+	default y
+	---help---
+	  This driver provides kernel-side support for the Random
+	  Number Generator hardware found on the Intel IXP4xx NPU.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ixp4xx-rng.
+
+	  If unsure, say Y.
+
+config HW_RANDOM_OMAP
+	tristate "OMAP Random Number Generator support"
+	depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+	default y
+ 	---help---
+ 	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on OMAP16xx and OMAP24xx multimedia
+	  processors.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called omap-rng.
+
+ 	  If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
new file mode 100644
index 0000000..e263ae9
--- /dev/null
+++ b/drivers/char/hw_random/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for HW Random Number Generator (RNG) device drivers.
+#
+
+obj-$(CONFIG_HW_RANDOM) += core.o
+obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
+obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
+obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
+obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
+obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
+obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
new file mode 100644
index 0000000..71e4e0f
--- /dev/null
+++ b/drivers/char/hw_random/amd-rng.c
@@ -0,0 +1,152 @@
+/*
+ * RNG driver for AMD RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+
+
+#define PFX	KBUILD_MODNAME ": "
+
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0, },	/* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct pci_dev *amd_pdev;
+
+
+static int amd_rng_data_present(struct hwrng *rng)
+{
+	u32 pmbase = (u32)rng->priv;
+
+      	return !!(inl(pmbase + 0xF4) & 1);
+}
+
+static int amd_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	u32 pmbase = (u32)rng->priv;
+
+	*data = inl(pmbase + 0xF0);
+
+	return 4;
+}
+
+static int amd_rng_init(struct hwrng *rng)
+{
+	u8 rnen;
+
+	pci_read_config_byte(amd_pdev, 0x40, &rnen);
+	rnen |= (1 << 7);	/* RNG on */
+	pci_write_config_byte(amd_pdev, 0x40, rnen);
+
+	pci_read_config_byte(amd_pdev, 0x41, &rnen);
+	rnen |= (1 << 7);	/* PMIO enable */
+	pci_write_config_byte(amd_pdev, 0x41, rnen);
+
+	return 0;
+}
+
+static void amd_rng_cleanup(struct hwrng *rng)
+{
+	u8 rnen;
+
+	pci_read_config_byte(amd_pdev, 0x40, &rnen);
+	rnen &= ~(1 << 7);	/* RNG off */
+	pci_write_config_byte(amd_pdev, 0x40, rnen);
+}
+
+
+static struct hwrng amd_rng = {
+	.name		= "amd",
+	.init		= amd_rng_init,
+	.cleanup	= amd_rng_cleanup,
+	.data_present	= amd_rng_data_present,
+	.data_read	= amd_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+	int err = -ENODEV;
+	struct pci_dev *pdev = NULL;
+	const struct pci_device_id *ent;
+	u32 pmbase;
+
+	for_each_pci_dev(pdev) {
+		ent = pci_match_id(pci_tbl, pdev);
+		if (ent)
+			goto found;
+	}
+	/* Device not found. */
+	goto out;
+
+found:
+	err = pci_read_config_dword(pdev, 0x58, &pmbase);
+	if (err)
+		goto out;
+	err = -EIO;
+	pmbase &= 0x0000FF00;
+	if (pmbase == 0)
+		goto out;
+	amd_rng.priv = (unsigned long)pmbase;
+	amd_pdev = pdev;
+
+	printk(KERN_INFO "AMD768 RNG detected\n");
+	err = hwrng_register(&amd_rng);
+	if (err) {
+		printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+		       err);
+		goto out;
+	}
+out:
+	return err;
+}
+
+static void __exit mod_exit(void)
+{
+	hwrng_unregister(&amd_rng);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("The Linux Kernel team");
+MODULE_DESCRIPTION("H/W RNG driver for AMD chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
new file mode 100644
index 0000000..88b0266
--- /dev/null
+++ b/drivers/char/hw_random/core.c
@@ -0,0 +1,354 @@
+/*
+        Added support for the AMD Geode LX RNG
+	(c) Copyright 2004-2005 Advanced Micro Devices, Inc.
+
+	derived from
+
+ 	Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+	(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+
+ 	derived from
+
+        Hardware driver for the AMD 768 Random Number Generator (RNG)
+        (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+
+ 	derived from
+
+	Hardware driver for Intel i810 Random Number Generator (RNG)
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+
+	Added generic RNG API
+	Copyright 2006 Michael Buesch <mbuesch@freenet.de>
+	Copyright 2005 (c) MontaVista Software, Inc.
+
+	Please read Documentation/hw_random.txt for details on use.
+
+	----------------------------------------------------------
+	This software may be used and distributed according to the terms
+        of the GNU General Public License, incorporated herein by reference.
+
+ */
+
+
+#include <linux/device.h>
+#include <linux/hw_random.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+
+#define RNG_MODULE_NAME		"hw_random"
+#define PFX			RNG_MODULE_NAME ": "
+#define RNG_MISCDEV_MINOR	183 /* official */
+
+
+static struct hwrng *current_rng;
+static LIST_HEAD(rng_list);
+static DEFINE_MUTEX(rng_mutex);
+
+
+static inline int hwrng_init(struct hwrng *rng)
+{
+	if (!rng->init)
+		return 0;
+	return rng->init(rng);
+}
+
+static inline void hwrng_cleanup(struct hwrng *rng)
+{
+	if (rng && rng->cleanup)
+		rng->cleanup(rng);
+}
+
+static inline int hwrng_data_present(struct hwrng *rng)
+{
+	if (!rng->data_present)
+		return 1;
+	return rng->data_present(rng);
+}
+
+static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
+{
+	return rng->data_read(rng, data);
+}
+
+
+static int rng_dev_open(struct inode *inode, struct file *filp)
+{
+	/* enforce read-only access to this chrdev */
+	if ((filp->f_mode & FMODE_READ) == 0)
+		return -EINVAL;
+	if (filp->f_mode & FMODE_WRITE)
+		return -EINVAL;
+	return 0;
+}
+
+static ssize_t rng_dev_read(struct file *filp, char __user *buf,
+			    size_t size, loff_t *offp)
+{
+	u32 data;
+	ssize_t ret = 0;
+	int i, err = 0;
+	int data_present;
+	int bytes_read;
+
+	while (size) {
+		err = -ERESTARTSYS;
+		if (mutex_lock_interruptible(&rng_mutex))
+			goto out;
+		if (!current_rng) {
+			mutex_unlock(&rng_mutex);
+			err = -ENODEV;
+			goto out;
+		}
+		if (filp->f_flags & O_NONBLOCK) {
+			data_present = hwrng_data_present(current_rng);
+		} else {
+			/* Some RNG require some time between data_reads to gather
+			 * new entropy. Poll it.
+			 */
+			for (i = 0; i < 20; i++) {
+				data_present = hwrng_data_present(current_rng);
+				if (data_present)
+					break;
+				udelay(10);
+			}
+		}
+		bytes_read = 0;
+		if (data_present)
+			bytes_read = hwrng_data_read(current_rng, &data);
+		mutex_unlock(&rng_mutex);
+
+		err = -EAGAIN;
+		if (!bytes_read && (filp->f_flags & O_NONBLOCK))
+			goto out;
+
+		err = -EFAULT;
+		while (bytes_read && size) {
+			if (put_user((u8)data, buf++))
+				goto out;
+			size--;
+			ret++;
+			bytes_read--;
+			data >>= 8;
+		}
+
+		if (need_resched())
+			schedule_timeout_interruptible(1);
+		err = -ERESTARTSYS;
+		if (signal_pending(current))
+			goto out;
+	}
+out:
+	return ret ? : err;
+}
+
+
+static struct file_operations rng_chrdev_ops = {
+	.owner		= THIS_MODULE,
+	.open		= rng_dev_open,
+	.read		= rng_dev_read,
+};
+
+static struct miscdevice rng_miscdev = {
+	.minor		= RNG_MISCDEV_MINOR,
+	.name		= RNG_MODULE_NAME,
+	.fops		= &rng_chrdev_ops,
+};
+
+
+static ssize_t hwrng_attr_current_store(struct class_device *class,
+					const char *buf, size_t len)
+{
+	int err;
+	struct hwrng *rng;
+
+	err = mutex_lock_interruptible(&rng_mutex);
+	if (err)
+		return -ERESTARTSYS;
+	err = -ENODEV;
+	list_for_each_entry(rng, &rng_list, list) {
+		if (strcmp(rng->name, buf) == 0) {
+			if (rng == current_rng) {
+				err = 0;
+				break;
+			}
+			err = hwrng_init(rng);
+			if (err)
+				break;
+			hwrng_cleanup(current_rng);
+			current_rng = rng;
+			err = 0;
+			break;
+		}
+	}
+	mutex_unlock(&rng_mutex);
+
+	return err ? : len;
+}
+
+static ssize_t hwrng_attr_current_show(struct class_device *class,
+				       char *buf)
+{
+	int err;
+	ssize_t ret;
+	const char *name = "none";
+
+	err = mutex_lock_interruptible(&rng_mutex);
+	if (err)
+		return -ERESTARTSYS;
+	if (current_rng)
+		name = current_rng->name;
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
+	mutex_unlock(&rng_mutex);
+
+	return ret;
+}
+
+static ssize_t hwrng_attr_available_show(struct class_device *class,
+					 char *buf)
+{
+	int err;
+	ssize_t ret = 0;
+	struct hwrng *rng;
+
+	err = mutex_lock_interruptible(&rng_mutex);
+	if (err)
+		return -ERESTARTSYS;
+	buf[0] = '\0';
+	list_for_each_entry(rng, &rng_list, list) {
+		strncat(buf, rng->name, PAGE_SIZE - ret - 1);
+		ret += strlen(rng->name);
+		strncat(buf, " ", PAGE_SIZE - ret - 1);
+		ret++;
+	}
+	strncat(buf, "\n", PAGE_SIZE - ret - 1);
+	ret++;
+	mutex_unlock(&rng_mutex);
+
+	return ret;
+}
+
+static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
+			 hwrng_attr_current_show,
+			 hwrng_attr_current_store);
+static CLASS_DEVICE_ATTR(rng_available, S_IRUGO,
+			 hwrng_attr_available_show,
+			 NULL);
+
+
+static void unregister_miscdev(void)
+{
+	class_device_remove_file(rng_miscdev.class,
+				 &class_device_attr_rng_available);
+	class_device_remove_file(rng_miscdev.class,
+				 &class_device_attr_rng_current);
+	misc_deregister(&rng_miscdev);
+}
+
+static int register_miscdev(void)
+{
+	int err;
+
+	err = misc_register(&rng_miscdev);
+	if (err)
+		goto out;
+	err = class_device_create_file(rng_miscdev.class,
+				       &class_device_attr_rng_current);
+	if (err)
+		goto err_misc_dereg;
+	err = class_device_create_file(rng_miscdev.class,
+				       &class_device_attr_rng_available);
+	if (err)
+		goto err_remove_current;
+out:
+	return err;
+
+err_remove_current:
+	class_device_remove_file(rng_miscdev.class,
+				 &class_device_attr_rng_current);
+err_misc_dereg:
+	misc_deregister(&rng_miscdev);
+	goto out;
+}
+
+int hwrng_register(struct hwrng *rng)
+{
+	int must_register_misc;
+	int err = -EINVAL;
+	struct hwrng *old_rng, *tmp;
+
+	if (rng->name == NULL ||
+	    rng->data_read == NULL)
+		goto out;
+
+	mutex_lock(&rng_mutex);
+
+	/* Must not register two RNGs with the same name. */
+	err = -EEXIST;
+	list_for_each_entry(tmp, &rng_list, list) {
+		if (strcmp(tmp->name, rng->name) == 0)
+			goto out_unlock;
+	}
+
+	must_register_misc = (current_rng == NULL);
+	old_rng = current_rng;
+	if (!old_rng) {
+		err = hwrng_init(rng);
+		if (err)
+			goto out_unlock;
+		current_rng = rng;
+	}
+	err = 0;
+	if (must_register_misc) {
+		err = register_miscdev();
+		if (err) {
+			if (!old_rng) {
+				hwrng_cleanup(rng);
+				current_rng = NULL;
+			}
+			goto out_unlock;
+		}
+	}
+	INIT_LIST_HEAD(&rng->list);
+	list_add_tail(&rng->list, &rng_list);
+out_unlock:
+	mutex_unlock(&rng_mutex);
+out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(hwrng_register);
+
+void hwrng_unregister(struct hwrng *rng)
+{
+	int err;
+
+	mutex_lock(&rng_mutex);
+
+	list_del(&rng->list);
+	if (current_rng == rng) {
+		hwrng_cleanup(rng);
+		if (list_empty(&rng_list)) {
+			current_rng = NULL;
+		} else {
+			current_rng = list_entry(rng_list.prev, struct hwrng, list);
+			err = hwrng_init(current_rng);
+			if (err)
+				current_rng = NULL;
+		}
+	}
+	if (list_empty(&rng_list))
+		unregister_miscdev();
+
+	mutex_unlock(&rng_mutex);
+}
+EXPORT_SYMBOL_GPL(hwrng_unregister);
+
+
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
new file mode 100644
index 0000000..be61f22
--- /dev/null
+++ b/drivers/char/hw_random/geode-rng.c
@@ -0,0 +1,128 @@
+/*
+ * RNG driver for AMD Geode RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+
+
+#define PFX	KBUILD_MODNAME ": "
+
+#define GEODE_RNG_DATA_REG   0x50
+#define GEODE_RNG_STATUS_REG 0x54
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0, },	/* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+
+static int geode_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	void __iomem *mem = (void __iomem *)rng->priv;
+
+	*data = readl(mem + GEODE_RNG_DATA_REG);
+
+	return 4;
+}
+
+static int geode_rng_data_present(struct hwrng *rng)
+{
+	void __iomem *mem = (void __iomem *)rng->priv;
+
+	return !!(readl(mem + GEODE_RNG_STATUS_REG));
+}
+
+
+static struct hwrng geode_rng = {
+	.name		= "geode",
+	.data_present	= geode_rng_data_present,
+	.data_read	= geode_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+	int err = -ENODEV;
+	struct pci_dev *pdev = NULL;
+	const struct pci_device_id *ent;
+	void __iomem *mem;
+	unsigned long rng_base;
+
+	for_each_pci_dev(pdev) {
+		ent = pci_match_id(pci_tbl, pdev);
+		if (ent)
+			goto found;
+	}
+	/* Device not found. */
+	goto out;
+
+found:
+	rng_base = pci_resource_start(pdev, 0);
+	if (rng_base == 0)
+		goto out;
+	err = -ENOMEM;
+	mem = ioremap(rng_base, 0x58);
+	if (!mem)
+		goto out;
+	geode_rng.priv = (unsigned long)mem;
+
+	printk(KERN_INFO "AMD Geode RNG detected\n");
+	err = hwrng_register(&geode_rng);
+	if (err) {
+		printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+		       err);
+		goto out;
+	}
+out:
+	return err;
+}
+
+static void __exit mod_exit(void)
+{
+	void __iomem *mem = (void __iomem *)geode_rng.priv;
+
+	hwrng_unregister(&geode_rng);
+	iounmap(mem);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
new file mode 100644
index 0000000..6594bd5
--- /dev/null
+++ b/drivers/char/hw_random/intel-rng.c
@@ -0,0 +1,189 @@
+/*
+ * RNG driver for Intel RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+
+
+#define PFX	KBUILD_MODNAME ": "
+
+/*
+ * RNG registers
+ */
+#define INTEL_RNG_HW_STATUS			0
+#define         INTEL_RNG_PRESENT		0x40
+#define         INTEL_RNG_ENABLED		0x01
+#define INTEL_RNG_STATUS			1
+#define         INTEL_RNG_DATA_PRESENT		0x01
+#define INTEL_RNG_DATA				2
+
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
+#define INTEL_RNG_ADDR				0xFFBC015F
+#define INTEL_RNG_ADDR_LEN			3
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+	{ 0, },	/* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+
+static inline u8 hwstatus_get(void __iomem *mem)
+{
+	return readb(mem + INTEL_RNG_HW_STATUS);
+}
+
+static inline u8 hwstatus_set(void __iomem *mem,
+			      u8 hw_status)
+{
+	writeb(hw_status, mem + INTEL_RNG_HW_STATUS);
+	return hwstatus_get(mem);
+}
+
+static int intel_rng_data_present(struct hwrng *rng)
+{
+	void __iomem *mem = (void __iomem *)rng->priv;
+
+	return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT);
+}
+
+static int intel_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	void __iomem *mem = (void __iomem *)rng->priv;
+
+	*data = readb(mem + INTEL_RNG_DATA);
+
+	return 1;
+}
+
+static int intel_rng_init(struct hwrng *rng)
+{
+	void __iomem *mem = (void __iomem *)rng->priv;
+	u8 hw_status;
+	int err = -EIO;
+
+	hw_status = hwstatus_get(mem);
+	/* turn RNG h/w on, if it's off */
+	if ((hw_status & INTEL_RNG_ENABLED) == 0)
+		hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED);
+	if ((hw_status & INTEL_RNG_ENABLED) == 0) {
+		printk(KERN_ERR PFX "cannot enable RNG, aborting\n");
+		goto out;
+	}
+	err = 0;
+out:
+	return err;
+}
+
+static void intel_rng_cleanup(struct hwrng *rng)
+{
+	void __iomem *mem = (void __iomem *)rng->priv;
+	u8 hw_status;
+
+	hw_status = hwstatus_get(mem);
+	if (hw_status & INTEL_RNG_ENABLED)
+		hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED);
+	else
+		printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
+}
+
+
+static struct hwrng intel_rng = {
+	.name		= "intel",
+	.init		= intel_rng_init,
+	.cleanup	= intel_rng_cleanup,
+	.data_present	= intel_rng_data_present,
+	.data_read	= intel_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+	int err = -ENODEV;
+	void __iomem *mem;
+	u8 hw_status;
+
+	if (!pci_dev_present(pci_tbl))
+		goto out; /* Device not found. */
+
+	err = -ENOMEM;
+	mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
+	if (!mem)
+		goto out;
+	intel_rng.priv = (unsigned long)mem;
+
+	/* Check for Intel 82802 */
+	err = -ENODEV;
+	hw_status = hwstatus_get(mem);
+	if ((hw_status & INTEL_RNG_PRESENT) == 0)
+		goto err_unmap;
+
+	printk(KERN_INFO "Intel 82802 RNG detected\n");
+	err = hwrng_register(&intel_rng);
+	if (err) {
+		printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+		       err);
+		goto out;
+	}
+out:
+	return err;
+
+err_unmap:
+	iounmap(mem);
+	goto out;
+}
+
+static void __exit mod_exit(void)
+{
+	void __iomem *mem = (void __iomem *)intel_rng.priv;
+
+	hwrng_unregister(&intel_rng);
+	iounmap(mem);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
new file mode 100644
index 0000000..ef71022
--- /dev/null
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -0,0 +1,73 @@
+/*
+ * drivers/char/rng/ixp4xx-rng.c
+ *
+ * RNG driver for Intel IXP4xx family of NPUs
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Fixes by Michael Buesch
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/hw_random.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+
+static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+	void __iomem * rng_base = (void __iomem *)rng->priv;
+
+	*buffer = __raw_readl(rng_base);
+
+	return 4;
+}
+
+static struct hwrng ixp4xx_rng_ops = {
+	.name		= "ixp4xx",
+	.data_read	= ixp4xx_rng_data_read,
+};
+
+static int __init ixp4xx_rng_init(void)
+{
+	void __iomem * rng_base;
+	int err;
+
+	rng_base = ioremap(0x70002100, 4);
+	if (!rng_base)
+		return -ENOMEM;
+	ixp4xx_rng_ops.priv = (unsigned long)rng_base;
+	err = hwrng_register(&ixp4xx_rng_ops);
+	if (err)
+		iounmap(rng_base);
+
+	return err;
+}
+
+static void __exit ixp4xx_rng_exit(void)
+{
+	void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv;
+
+	hwrng_unregister(&ixp4xx_rng_ops);
+	iounmap(rng_base);
+}
+
+subsys_initcall(ixp4xx_rng_init);
+module_exit(ixp4xx_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
new file mode 100644
index 0000000..819516b
--- /dev/null
+++ b/drivers/char/hw_random/omap-rng.c
@@ -0,0 +1,208 @@
+/*
+ * driver/char/hw_random/omap-rng.c
+ *
+ * RNG driver for TI OMAP CPU family
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrj��<juha.yrjola@nokia.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * TODO:
+ *
+ * - Make status updated be interrupt driven so we don't poll
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/hw_random.h>
+
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+
+#define RNG_OUT_REG		0x00		/* Output register */
+#define RNG_STAT_REG		0x04		/* Status register
+							[0] = STAT_BUSY */
+#define RNG_ALARM_REG		0x24		/* Alarm register
+							[7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG		0x28		/* Configuration register
+							[11:6] = RESET_COUNT
+							[5:3]  = RING2_DELAY
+							[2:0]  = RING1_DELAY */
+#define RNG_REV_REG		0x3c		/* Revision register
+							[7:0] = REV_NB */
+#define RNG_MASK_REG		0x40		/* Mask and reset register
+							[2] = IT_EN
+							[1] = SOFTRESET
+							[0] = AUTOIDLE */
+#define RNG_SYSSTATUS		0x44		/* System status
+							[0] = RESETDONE */
+
+static void __iomem *rng_base;
+static struct clk *rng_ick;
+static struct device *rng_dev;
+
+static u32 omap_rng_read_reg(int reg)
+{
+	return __raw_readl(rng_base + reg);
+}
+
+static void omap_rng_write_reg(int reg, u32 val)
+{
+	__raw_writel(val, rng_base + reg);
+}
+
+/* REVISIT: Does the status bit really work on 16xx? */
+static int omap_rng_data_present(struct hwrng *rng)
+{
+	return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+}
+
+static int omap_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	*data = omap_rng_read_reg(RNG_OUT_REG);
+
+	return 4;
+}
+
+static struct hwrng omap_rng_ops = {
+	.name		= "omap",
+	.data_present	= omap_rng_data_present,
+	.data_read	= omap_rng_data_read,
+};
+
+static int __init omap_rng_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res, *mem;
+	int ret;
+
+	/*
+	 * A bit ugly, and it will never actually happen but there can
+	 * be only one RNG and this catches any bork
+	 */
+	BUG_ON(rng_dev);
+
+    	if (cpu_is_omap24xx()) {
+		rng_ick = clk_get(NULL, "rng_ick");
+		if (IS_ERR(rng_ick)) {
+			dev_err(dev, "Could not get rng_ick\n");
+			ret = PTR_ERR(rng_ick);
+			return ret;
+		}
+		else {
+			clk_use(rng_ick);
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res)
+		return -ENOENT;
+
+	mem = request_mem_region(res->start, res->end - res->start + 1,
+				 pdev->name);
+	if (mem == NULL)
+		return -EBUSY;
+
+	dev_set_drvdata(dev, mem);
+	rng_base = (u32 __iomem *)io_p2v(res->start);
+
+	ret = hwrng_register(&omap_rng_ops);
+	if (ret) {
+		release_resource(mem);
+		rng_base = NULL;
+		return ret;
+	}
+
+	dev_info(dev, "OMAP Random Number Generator ver. %02x\n",
+		omap_rng_read_reg(RNG_REV_REG));
+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+	rng_dev = dev;
+
+	return 0;
+}
+
+static int __exit omap_rng_remove(struct device *dev)
+{
+	struct resource *mem = dev_get_drvdata(dev);
+
+	hwrng_unregister(&omap_rng_ops);
+
+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+	if (cpu_is_omap24xx()) {
+		clk_unuse(rng_ick);
+		clk_put(rng_ick);
+	}
+
+	release_resource(mem);
+	rng_base = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level)
+{
+	omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+	return 0;
+}
+
+static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level)
+{
+	omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+	return 1;
+}
+
+#else
+
+#define	omap_rng_suspend	NULL
+#define	omap_rng_resume		NULL
+
+#endif
+
+
+static struct device_driver omap_rng_driver = {
+	.name		= "omap_rng",
+	.bus		= &platform_bus_type,
+	.probe		= omap_rng_probe,
+	.remove		= __exit_p(omap_rng_remove),
+	.suspend	= omap_rng_suspend,
+	.resume		= omap_rng_resume
+};
+
+static int __init omap_rng_init(void)
+{
+	if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+		return -ENODEV;
+
+	return driver_register(&omap_rng_driver);
+}
+
+static void __exit omap_rng_exit(void)
+{
+	driver_unregister(&omap_rng_driver);
+}
+
+module_init(omap_rng_init);
+module_exit(omap_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena (and others)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
new file mode 100644
index 0000000..0e786b6
--- /dev/null
+++ b/drivers/char/hw_random/via-rng.c
@@ -0,0 +1,183 @@
+/*
+ * RNG driver for VIA RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+
+
+#define PFX	KBUILD_MODNAME ": "
+
+
+enum {
+	VIA_STRFILT_CNT_SHIFT	= 16,
+	VIA_STRFILT_FAIL	= (1 << 15),
+	VIA_STRFILT_ENABLE	= (1 << 14),
+	VIA_RAWBITS_ENABLE	= (1 << 13),
+	VIA_RNG_ENABLE		= (1 << 6),
+	VIA_XSTORE_CNT_MASK	= 0x0F,
+
+	VIA_RNG_CHUNK_8		= 0x00,	/* 64 rand bits, 64 stored bits */
+	VIA_RNG_CHUNK_4		= 0x01,	/* 32 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_4_MASK	= 0xFFFFFFFF,
+	VIA_RNG_CHUNK_2		= 0x02,	/* 16 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_2_MASK	= 0xFFFF,
+	VIA_RNG_CHUNK_1		= 0x03,	/* 8 rand bits, 32 stored bits */
+	VIA_RNG_CHUNK_1_MASK	= 0xFF,
+};
+
+/*
+ * Investigate using the 'rep' prefix to obtain 32 bits of random data
+ * in one insn.  The upside is potentially better performance.  The
+ * downside is that the instruction becomes no longer atomic.  Due to
+ * this, just like familiar issues with /dev/random itself, the worst
+ * case of a 'rep xstore' could potentially pause a cpu for an
+ * unreasonably long time.  In practice, this condition would likely
+ * only occur when the hardware is failing.  (or so we hope :))
+ *
+ * Another possible performance boost may come from simply buffering
+ * until we have 4 bytes, thus returning a u32 at a time,
+ * instead of the current u8-at-a-time.
+ */
+
+static inline u32 xstore(u32 *addr, u32 edx_in)
+{
+	u32 eax_out;
+
+	asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
+		:"=m"(*addr), "=a"(eax_out)
+		:"D"(addr), "d"(edx_in));
+
+	return eax_out;
+}
+
+static int via_rng_data_present(struct hwrng *rng)
+{
+	u32 bytes_out;
+	u32 *via_rng_datum = (u32 *)(&rng->priv);
+
+	/* We choose the recommended 1-byte-per-instruction RNG rate,
+	 * for greater randomness at the expense of speed.  Larger
+	 * values 2, 4, or 8 bytes-per-instruction yield greater
+	 * speed at lesser randomness.
+	 *
+	 * If you change this to another VIA_CHUNK_n, you must also
+	 * change the ->n_bytes values in rng_vendor_ops[] tables.
+	 * VIA_CHUNK_8 requires further code changes.
+	 *
+	 * A copy of MSR_VIA_RNG is placed in eax_out when xstore
+	 * completes.
+	 */
+
+	*via_rng_datum = 0; /* paranoia, not really necessary */
+	bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
+	bytes_out &= VIA_XSTORE_CNT_MASK;
+	if (bytes_out == 0)
+		return 0;
+	return 1;
+}
+
+static int via_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	u32 via_rng_datum = (u32)rng->priv;
+
+	*data = via_rng_datum;
+
+	return 1;
+}
+
+static int via_rng_init(struct hwrng *rng)
+{
+	u32 lo, hi, old_lo;
+
+	/* Control the RNG via MSR.  Tread lightly and pay very close
+	 * close attention to values written, as the reserved fields
+	 * are documented to be "undefined and unpredictable"; but it
+	 * does not say to write them as zero, so I make a guess that
+	 * we restore the values we find in the register.
+	 */
+	rdmsr(MSR_VIA_RNG, lo, hi);
+
+	old_lo = lo;
+	lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
+	lo &= ~VIA_XSTORE_CNT_MASK;
+	lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
+	lo |= VIA_RNG_ENABLE;
+
+	if (lo != old_lo)
+		wrmsr(MSR_VIA_RNG, lo, hi);
+
+	/* perhaps-unnecessary sanity check; remove after testing if
+	   unneeded */
+	rdmsr(MSR_VIA_RNG, lo, hi);
+	if ((lo & VIA_RNG_ENABLE) == 0) {
+		printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+static struct hwrng via_rng = {
+	.name		= "via",
+	.init		= via_rng_init,
+	.data_present	= via_rng_data_present,
+	.data_read	= via_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+	int err;
+
+	if (!cpu_has_xstore)
+		return -ENODEV;
+	printk(KERN_INFO "VIA RNG detected\n");
+	err = hwrng_register(&via_rng);
+	if (err) {
+		printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+		       err);
+		goto out;
+	}
+out:
+	return err;
+}
+
+static void __exit mod_exit(void)
+{
+	hwrng_unregister(&via_rng);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 03db1cb..9ab33c3 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -305,7 +305,7 @@
 
 // Some functions to keep track of what irq's we have
 
-static int __init
+static int
 is_valid_irq(int irq)
 {
 	int *i = Valid_Irqs;
@@ -316,14 +316,14 @@
 	return (*i);
 }
 
-static void __init
+static void
 mark_requested_irq( char irq )
 {
 	rirqs[iindx++] = irq;
 }
 
 #ifdef MODULE
-static int __init
+static int
 clear_requested_irq( char irq )
 {
 	int i;
@@ -337,7 +337,7 @@
 }
 #endif
 
-static int __init
+static int
 have_requested_irq( char irq )
 {
 	// array init to zeros so 0 irq will not be requested as a side effect
@@ -818,7 +818,7 @@
 /* the board, the channel structures are initialized, and the board details   */
 /* are reported on the console.                                               */
 /******************************************************************************/
-static void __init
+static void
 ip2_init_board( int boardnum )
 {
 	int i;
@@ -961,7 +961,7 @@
 /* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
 /* it returns the base address of the controller.                             */
 /******************************************************************************/
-static unsigned short __init
+static unsigned short
 find_eisa_board( int start_slot )
 {
 	int i, j;
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 9f2f8fd..b03ddab 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -936,11 +936,8 @@
 
 	if (val) {
 		/* Deliver any queued events. */
-		list_for_each_entry_safe(msg, msg2, &intf->waiting_events,
-					 link) {
-			list_del(&msg->link);
-			list_add_tail(&msg->link, &msgs);
-		}
+		list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
+			list_move_tail(&msg->link, &msgs);
 		intf->waiting_events_count = 0;
 	}
 
@@ -3677,7 +3674,7 @@
 }
 #endif /* CONFIG_IPMI_PANIC_EVENT */
 
-static int has_paniced = 0;
+static int has_panicked = 0;
 
 static int panic_event(struct notifier_block *this,
 		       unsigned long         event,
@@ -3686,9 +3683,9 @@
 	int        i;
 	ipmi_smi_t intf;
 
-	if (has_paniced)
+	if (has_panicked)
 		return NOTIFY_DONE;
-	has_paniced = 1;
+	has_panicked = 1;
 
 	/* For every registered interface, set it to run to completion. */
 	for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index e9ebaba..efaaa19 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1145,7 +1145,7 @@
 	if (isicom_paranoia_check(port, tty->name, "isicom_write"))
 		return 0;
 
-	if (!tty || !port->xmit_buf)
+	if (!port->xmit_buf)
 		return 0;
 
 	spin_lock_irqsave(&card->card_lock, flags);
@@ -1180,7 +1180,7 @@
 	if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
 		return;
 
-	if (!tty || !port->xmit_buf)
+	if (!port->xmit_buf)
 		return;
 
 	spin_lock_irqsave(&card->card_lock, flags);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 5755b7e..4bb3d22 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -39,6 +39,7 @@
 #include <linux/vt_kern.h>
 #include <linux/sysrq.h>
 #include <linux/input.h>
+#include <linux/reboot.h>
 
 static void kbd_disconnect(struct input_handle *handle);
 extern void ctrl_alt_del(void);
@@ -150,6 +151,7 @@
         "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
         "\r\000/";                                      /* 0x60 - 0x6f */
 static int sysrq_down;
+static int sysrq_alt_use;
 #endif
 static int sysrq_alt;
 
@@ -672,7 +674,7 @@
  */
 static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
 {
-	static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+	static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
 	value = ret_diacr[value];
 	k_deadunicode(vc, value, up_flag, regs);
 }
@@ -709,8 +711,8 @@
 
 static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
 {
-	static const char *pad_chars = "0123456789+-*/\015,.?()#";
-	static const char *app_map = "pqrstuvwxylSRQMnnmPQS";
+	static const char pad_chars[] = "0123456789+-*/\015,.?()#";
+	static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
 
 	if (up_flag)
 		return;		/* no action, if this is a key release */
@@ -1035,7 +1037,7 @@
 #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
 			((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
 
-static unsigned short x86_keycodes[256] =
+static const unsigned short x86_keycodes[256] =
 	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
@@ -1073,11 +1075,13 @@
 			put_queue(vc, 0x1d | up_flag);
 			put_queue(vc, 0x45 | up_flag);
 			return 0;
-		case KEY_HANGUEL:
-			if (!up_flag) put_queue(vc, 0xf1);
+		case KEY_HANGEUL:
+			if (!up_flag)
+				put_queue(vc, 0xf2);
 			return 0;
 		case KEY_HANJA:
-			if (!up_flag) put_queue(vc, 0xf2);
+			if (!up_flag)
+				put_queue(vc, 0xf1);
 			return 0;
 	}
 
@@ -1142,7 +1146,7 @@
 	kbd = kbd_table + fg_console;
 
 	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
-		sysrq_alt = down;
+		sysrq_alt = down ? keycode : 0;
 #ifdef CONFIG_SPARC
 	if (keycode == KEY_STOP)
 		sparc_l1_a_state = down;
@@ -1162,9 +1166,14 @@
 
 #ifdef CONFIG_MAGIC_SYSRQ	       /* Handle the SysRq Hack */
 	if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) {
-		sysrq_down = down;
+		if (!sysrq_down) {
+			sysrq_down = down;
+			sysrq_alt_use = sysrq_alt;
+		}
 		return;
 	}
+	if (sysrq_down && !down && keycode == sysrq_alt_use)
+		sysrq_down = 0;
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
 		return;
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 1b05fa6..d65b310 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -329,7 +329,6 @@
 	if (PAGE_SIZE > (1 << 16))
 		return -ENOSYS;
 
-	vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	mmtimer_addr = __pa(RTC_COUNTER_ADDR);
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 0fb2fb9..645d9d7 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -9,7 +9,7 @@
  *      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.
+ *      (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
@@ -71,8 +71,8 @@
 #define	MXSERMAJOR	 174
 #define	MXSERCUMAJOR	 175
 
-#define	MXSER_EVENT_TXLOW	 1
-#define	MXSER_EVENT_HANGUP	 2
+#define	MXSER_EVENT_TXLOW	1
+#define	MXSER_EVENT_HANGUP	2
 
 #define MXSER_BOARDS		4	/* Max. boards */
 #define MXSER_PORTS		32	/* Max. ports */
@@ -92,7 +92,8 @@
 #define UART_MCR_AFE		0x20
 #define UART_LSR_SPECIAL	0x1E
 
-#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|IXON|IXOFF))
+#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
+					  IXON|IXOFF))
 
 #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
 
@@ -152,27 +153,27 @@
 };
 
 static int mxser_numports[] = {
-	8,			// C168-ISA
-	4,			// C104-ISA
-	4,			// CI104J
-	8,			// C168-PCI
-	4,			// C104-PCI
-	2,			// C102-ISA
-	2,			// CI132
-	4,			// CI134
-	2,			// CP132
-	4,			// CP114
-	4,			// CT114
-	2,			// CP102
-	4,			// CP104U
-	8,			// CP168U
-	2,			// CP132U
-	4,			// CP134U
-	4,			// CP104JU
-	8,			// RC7000
-	8,			// CP118U 
-	2,			// CP102UL 
-	2,			// CP102U
+	8,			/* C168-ISA */
+	4,			/* C104-ISA */
+	4,			/* CI104J */
+	8,			/* C168-PCI */
+	4,			/* C104-PCI */
+	2,			/* C102-ISA */
+	2,			/* CI132 */
+	4,			/* CI134 */
+	2,			/* CP132 */
+	4,			/* CP114 */
+	4,			/* CT114 */
+	2,			/* CP102 */
+	4,			/* CP104U */
+	8,			/* CP168U */
+	2,			/* CP132U */
+	4,			/* CP134U */
+	4,			/* CP104JU */
+	8,			/* RC7000 */
+	8,			/* CP118U */
+	2,			/* CP102UL */
+	2,			/* CP102U */
 };
 
 #define UART_TYPE_NUM	2
@@ -182,7 +183,7 @@
 	MOXA_MUST_MU860_HWID
 };
 
-// This is only for PCI
+/* This is only for PCI */
 #define UART_INFO_NUM	3
 struct mxpciuart_info {
 	int type;
@@ -231,7 +232,7 @@
 typedef struct _moxa_pci_info {
 	unsigned short busNum;
 	unsigned short devNum;
-	struct pci_dev *pdev;	// add by Victor Yu. 06-23-2003
+	struct pci_dev *pdev;	/* add by Victor Yu. 06-23-2003 */
 } moxa_pci_info;
 
 static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
@@ -280,6 +281,7 @@
 	int fifo[32];
 	int iftype[32];
 };
+
 struct mxser_hwconf {
 	int board_type;
 	int ports;
@@ -290,9 +292,9 @@
 	int ioaddr[MXSER_PORTS_PER_BOARD];
 	int baud_base[MXSER_PORTS_PER_BOARD];
 	moxa_pci_info pciInfo;
-	int IsMoxaMustChipFlag;	// add by Victor Yu. 08-30-2002
-	int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD];	// add by Victor Yu. 09-04-2002
-	int opmode_ioaddr[MXSER_PORTS_PER_BOARD];	// add by Victor Yu. 01-05-2004
+	int IsMoxaMustChipFlag;	/* add by Victor Yu. 08-30-2002 */
+	int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD];	/* add by Victor Yu. 09-04-2002 */
+	int opmode_ioaddr[MXSER_PORTS_PER_BOARD];	/* add by Victor Yu. 01-05-2004 */
 };
 
 struct mxser_struct {
@@ -334,9 +336,9 @@
 	wait_queue_head_t delta_msr_wait;
 	struct async_icount icount;	/* kernel counters for the 4 input interrupts */
 	int timeout;
-	int IsMoxaMustChipFlag;	// add by Victor Yu. 08-30-2002
-	int MaxCanSetBaudRate;	// add by Victor Yu. 09-04-2002
-	int opmode_ioaddr;	// add by Victor Yu. 01-05-2004
+	int IsMoxaMustChipFlag;	/* add by Victor Yu. 08-30-2002 */
+	int MaxCanSetBaudRate;	/* add by Victor Yu. 09-04-2002 */
+	int opmode_ioaddr;	/* add by Victor Yu. 01-05-2004 */
 	unsigned char stop_rx;
 	unsigned char ldisc_stop_rx;
 	long realbaud;
@@ -345,7 +347,6 @@
 	spinlock_t slock;
 };
 
-
 struct mxser_mstatus {
 	tcflag_t cflag;
 	int cts;
@@ -358,7 +359,7 @@
 
 static int mxserBoardCAP[MXSER_BOARDS] = {
 	0, 0, 0, 0
-	    /*  0x180, 0x280, 0x200, 0x320   */
+	/*  0x180, 0x280, 0x200, 0x320 */
 };
 
 static struct tty_driver *mxvar_sdriver;
@@ -386,7 +387,7 @@
 static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
 static int mxser_init(void);
 
-//static void   mxser_poll(unsigned long);
+/* static void   mxser_poll(unsigned long); */
 static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
 static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
 static void mxser_do_softint(void *);
@@ -440,18 +441,18 @@
 	SET_MOXA_MUST_XON1_VALUE(io, 0x11);
 	if ((hwid = inb(io + UART_MCR)) != 0) {
 		outb(oldmcr, io + UART_MCR);
-		return (MOXA_OTHER_UART);
+		return MOXA_OTHER_UART;
 	}
 
 	GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
 	for (i = 0; i < UART_TYPE_NUM; i++) {
 		if (hwid == Gmoxa_uart_id[i])
-			return (int) hwid;
+			return (int)hwid;
 	}
 	return MOXA_OTHER_UART;
 }
 
-// above is modified by Victor Yu. 08-15-2002
+/* above is modified by Victor Yu. 08-15-2002 */
 
 static struct tty_operations mxser_ops = {
 	.open = mxser_open,
@@ -504,7 +505,6 @@
 	else
 		printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
 
-
 	for (i = 0; i < MXSER_BOARDS; i++) {
 		struct pci_dev *pdev;
 
@@ -513,7 +513,7 @@
 		else {
 			pdev = mxsercfg[i].pciInfo.pdev;
 			free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-			if (pdev != NULL) {	//PCI
+			if (pdev != NULL) {	/* PCI */
 				release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
 				release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
 			} else {
@@ -524,7 +524,6 @@
 	}
 	if (verbose)
 		printk(KERN_DEBUG "Done.\n");
-
 }
 
 static void process_txrx_fifo(struct mxser_struct *info)
@@ -558,8 +557,10 @@
 	n = board * MXSER_PORTS_PER_BOARD;
 	info = &mxvar_table[n];
 	/*if (verbose) */  {
-		printk(KERN_DEBUG "        ttyM%d - ttyM%d ", n, n + hwconf->ports - 1);
-		printk(" max. baud rate = %d bps.\n", hwconf->MaxCanSetBaudRate[0]);
+		printk(KERN_DEBUG "        ttyM%d - ttyM%d ",
+			n, n + hwconf->ports - 1);
+		printk(" max. baud rate = %d bps.\n",
+			hwconf->MaxCanSetBaudRate[0]);
 	}
 
 	for (i = 0; i < hwconf->ports; i++, n++, info++) {
@@ -568,12 +569,12 @@
 		info->irq = hwconf->irq;
 		info->vector = hwconf->vector;
 		info->vectormask = hwconf->vector_mask;
-		info->opmode_ioaddr = hwconf->opmode_ioaddr[i];	// add by Victor Yu. 01-05-2004
+		info->opmode_ioaddr = hwconf->opmode_ioaddr[i];	/* add by Victor Yu. 01-05-2004 */
 		info->stop_rx = 0;
 		info->ldisc_stop_rx = 0;
 
 		info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
-		//Enhance mode enabled here
+		/* Enhance mode enabled here */
 		if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
 			ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
 		}
@@ -606,22 +607,25 @@
 
 	/* before set INT ISR, disable all int */
 	for (i = 0; i < hwconf->ports; i++) {
-		outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0, hwconf->ioaddr[i] + UART_IER);
+		outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0,
+			hwconf->ioaddr[i] + UART_IER);
 	}
 
 	n = board * MXSER_PORTS_PER_BOARD;
 	info = &mxvar_table[n];
 
-	retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), "mxser", info);
+	retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+				"mxser", info);
 	if (retval) {
-		printk(KERN_ERR "Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
-		printk("  Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
+		printk(KERN_ERR "Board %d: %s",
+			board, mxser_brdname[hwconf->board_type - 1]);
+		printk("  Request irq failed, IRQ (%d) may conflict with"
+			" another device.\n", info->irq);
 		return retval;
 	}
 	return 0;
 }
 
-
 static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
 {
 	mxsercfg[board] = *hwconf;
@@ -631,26 +635,27 @@
 static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
 {
 	int i, j;
-//      unsigned int    val;
+	/* unsigned int val; */
 	unsigned int ioaddress;
 	struct pci_dev *pdev = hwconf->pciInfo.pdev;
 
-	//io address
+	/* io address */
 	hwconf->board_type = board_type;
 	hwconf->ports = mxser_numports[board_type - 1];
 	ioaddress = pci_resource_start(pdev, 2);
-	request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2), "mxser(IO)");
+	request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2),
+			"mxser(IO)");
 
-	for (i = 0; i < hwconf->ports; i++) {
+	for (i = 0; i < hwconf->ports; i++)
 		hwconf->ioaddr[i] = ioaddress + 8 * i;
-	}
 
-	//vector
+	/* vector */
 	ioaddress = pci_resource_start(pdev, 3);
-	request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3), "mxser(vector)");
+	request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3),
+			"mxser(vector)");
 	hwconf->vector = ioaddress;
 
-	//irq
+	/* irq */
 	hwconf->irq = hwconf->pciInfo.pdev->irq;
 
 	hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]);
@@ -663,7 +668,7 @@
 			if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) {
 				hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud;
 
-				//exception....CP-102
+				/* exception....CP-102 */
 				if (board_type == MXSER_BOARD_CP102)
 					hwconf->MaxCanSetBaudRate[i] = 921600;
 				break;
@@ -678,15 +683,15 @@
 			else
 				hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
 		}
-		outb(0, ioaddress + 4);	// default set to RS232 mode
-		outb(0, ioaddress + 0x0c);	//default set to RS232 mode
+		outb(0, ioaddress + 4);	/* default set to RS232 mode */
+		outb(0, ioaddress + 0x0c);	/* default set to RS232 mode */
 	}
 
 	for (i = 0; i < hwconf->ports; i++) {
 		hwconf->vector_mask |= (1 << i);
 		hwconf->baud_base[i] = 921600;
 	}
-	return (0);
+	return 0;
 }
 #endif
 
@@ -707,7 +712,8 @@
 		mxsercfg[i].board_type = -1;
 	}
 
-	printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", MXSER_VERSION);
+	printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+		MXSER_VERSION);
 
 	/* Initialize the tty_driver structure */
 	memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
@@ -719,7 +725,7 @@
 	mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
 	mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
 	mxvar_sdriver->init_termios = tty_std_termios;
-	mxvar_sdriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
 	mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
 	tty_set_operations(mxvar_sdriver, &mxser_ops);
 	mxvar_sdriver->ttys = mxvar_tty;
@@ -739,23 +745,29 @@
 	/* Start finding ISA boards here */
 	for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
 		int cap;
+
 		if (!(cap = mxserBoardCAP[b]))
 			continue;
 
 		retval = mxser_get_ISA_conf(cap, &hwconf);
 
 		if (retval != 0)
-			printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+			printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+				mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
 
 		if (retval <= 0) {
 			if (retval == MXSER_ERR_IRQ)
-				printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+				printk(KERN_ERR "Invalid interrupt number, "
+					"board not configured\n");
 			else if (retval == MXSER_ERR_IRQ_CONFLIT)
-				printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+				printk(KERN_ERR "Invalid interrupt number, "
+					"board not configured\n");
 			else if (retval == MXSER_ERR_VECTOR)
-				printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+				printk(KERN_ERR "Invalid interrupt vector, "
+					"board not configured\n");
 			else if (retval == MXSER_ERR_IOADDR)
-				printk(KERN_ERR "Invalid I/O address,board not configured\n");
+				printk(KERN_ERR "Invalid I/O address, "
+					"board not configured\n");
 
 			continue;
 		}
@@ -765,35 +777,43 @@
 		hwconf.pciInfo.pdev = NULL;
 
 		mxser_getcfg(m, &hwconf);
-		//init mxsercfg first, or mxsercfg data is not correct on ISR.
-		//mxser_initbrd will hook ISR.
+		/*
+		 * init mxsercfg first,
+		 * or mxsercfg data is not correct on ISR.
+		 */
+		/* mxser_initbrd will hook ISR. */
 		if (mxser_initbrd(m, &hwconf) < 0)
 			continue;
 
-
 		m++;
 	}
 
 	/* Start finding ISA boards from module arg */
 	for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
 		int cap;
+
 		if (!(cap = ioaddr[b]))
 			continue;
 
 		retval = mxser_get_ISA_conf(cap, &hwconf);
 
 		if (retval != 0)
-			printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+			printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+				mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
 
 		if (retval <= 0) {
 			if (retval == MXSER_ERR_IRQ)
-				printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+				printk(KERN_ERR "Invalid interrupt number, "
+					"board not configured\n");
 			else if (retval == MXSER_ERR_IRQ_CONFLIT)
-				printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+				printk(KERN_ERR "Invalid interrupt number, "
+					"board not configured\n");
 			else if (retval == MXSER_ERR_VECTOR)
-				printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+				printk(KERN_ERR "Invalid interrupt vector, "
+					"board not configured\n");
 			else if (retval == MXSER_ERR_IOADDR)
-				printk(KERN_ERR "Invalid I/O address,board not configured\n");
+				printk(KERN_ERR "Invalid I/O address, "
+					"board not configured\n");
 
 			continue;
 		}
@@ -803,8 +823,11 @@
 		hwconf.pciInfo.pdev = NULL;
 
 		mxser_getcfg(m, &hwconf);
-		//init mxsercfg first, or mxsercfg data is not correct on ISR.
-		//mxser_initbrd will hook ISR.
+		/*
+		 * init mxsercfg first,
+		 * or mxsercfg data is not correct on ISR.
+		 */
+		/* mxser_initbrd will hook ISR. */
 		if (mxser_initbrd(m, &hwconf) < 0)
 			continue;
 
@@ -817,7 +840,8 @@
 	index = 0;
 	b = 0;
 	while (b < n) {
-		pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev);
+		pdev = pci_find_device(mxser_pcibrds[b].vendor,
+				mxser_pcibrds[b].device, pdev);
 			if (pdev == NULL) {
 			b++;
 			continue;
@@ -825,30 +849,48 @@
 		hwconf.pciInfo.busNum = busnum = pdev->bus->number;
 		hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3;
 		hwconf.pciInfo.pdev = pdev;
-		printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], busnum, devnum >> 3);
+		printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+			mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
+			busnum, devnum >> 3);
 		index++;
-		if (m >= MXSER_BOARDS) {
-			printk(KERN_ERR "Too many Smartio/Industio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
-		} else {
+		if (m >= MXSER_BOARDS)
+			printk(KERN_ERR
+				"Too many Smartio/Industio family boards find "
+				"(maximum %d), board not configured\n",
+				MXSER_BOARDS);
+		else {
 			if (pci_enable_device(pdev)) {
-				printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+				printk(KERN_ERR "Moxa SmartI/O PCI enable "
+					"fail !\n");
 				continue;
 			}
-			retval = mxser_get_PCI_conf(busnum, devnum, (int) mxser_pcibrds[b].driver_data, &hwconf);
+			retval = mxser_get_PCI_conf(busnum, devnum,
+					(int)mxser_pcibrds[b].driver_data,
+					&hwconf);
 			if (retval < 0) {
 				if (retval == MXSER_ERR_IRQ)
-					printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+					printk(KERN_ERR
+						"Invalid interrupt number, "
+						"board not configured\n");
 				else if (retval == MXSER_ERR_IRQ_CONFLIT)
-					printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+					printk(KERN_ERR
+						"Invalid interrupt number, "
+						"board not configured\n");
 				else if (retval == MXSER_ERR_VECTOR)
-					printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+					printk(KERN_ERR
+						"Invalid interrupt vector, "
+						"board not configured\n");
 				else if (retval == MXSER_ERR_IOADDR)
-					printk(KERN_ERR "Invalid I/O address,board not configured\n");
+					printk(KERN_ERR
+						"Invalid I/O address, "
+						"board not configured\n");
 				continue;
 			}
 			mxser_getcfg(m, &hwconf);
-			//init mxsercfg first, or mxsercfg data is not correct on ISR.
-			//mxser_initbrd will hook ISR.
+			/* init mxsercfg first,
+			 * or mxsercfg data is not correct on ISR.
+			 */
+			/* mxser_initbrd will hook ISR. */
 			if (mxser_initbrd(m, &hwconf) < 0)
 				continue;
 			m++;
@@ -858,7 +900,8 @@
 
 	retval = tty_register_driver(mxvar_sdriver);
 	if (retval) {
-		printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family driver !\n");
+		printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
+				" driver !\n");
 		put_tty_driver(mxvar_sdriver);
 
 		for (i = 0; i < MXSER_BOARDS; i++) {
@@ -866,7 +909,7 @@
 				continue;
 			else {
 				free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-				//todo: release io, vector
+				/* todo: release io, vector */
 			}
 		}
 		return retval;
@@ -877,7 +920,7 @@
 
 static void mxser_do_softint(void *private_)
 {
-	struct mxser_struct *info = (struct mxser_struct *) private_;
+	struct mxser_struct *info = private_;
 	struct tty_struct *tty;
 
 	tty = info->tty;
@@ -926,7 +969,7 @@
 		return -ENODEV;
 	info = mxvar_table + line;
 	if (!info->base)
-		return (-ENODEV);
+		return -ENODEV;
 
 	tty->driver_data = info;
 	info->tty = tty;
@@ -935,11 +978,11 @@
 	 */
 	retval = mxser_startup(info);
 	if (retval)
-		return (retval);
+		return retval;
 
 	retval = mxser_block_til_ready(tty, filp, info);
 	if (retval)
-		return (retval);
+		return retval;
 
 	info->count++;
 
@@ -955,11 +998,12 @@
 	info->pgrp = process_group(current);
 	clear_bit(TTY_DONT_FLIP, &tty->flags);
 
-	//status = mxser_get_msr(info->base, 0, info->port);
-	//mxser_check_modem_status(info, status);
+	/*
+	status = mxser_get_msr(info->base, 0, info->port);
+	mxser_check_modem_status(info, status);
+	*/
 
-/* unmark here for very high baud rate (ex. 921600 bps) used
-*/
+/* unmark here for very high baud rate (ex. 921600 bps) used */
 	tty->low_latency = 1;
 	return 0;
 }
@@ -972,7 +1016,7 @@
  */
 static void mxser_close(struct tty_struct *tty, struct file *filp)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 
 	unsigned long timeout;
 	unsigned long flags;
@@ -997,11 +1041,13 @@
 		 * one, we've got real problems, since it means the
 		 * serial port won't be shutdown.
 		 */
-		printk(KERN_ERR "mxser_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count);
+		printk(KERN_ERR "mxser_close: bad serial port count; "
+			"tty->count is 1, info->count is %d\n", info->count);
 		info->count = 1;
 	}
 	if (--info->count < 0) {
-		printk(KERN_ERR "mxser_close: bad serial port count for ttys%d: %d\n", info->port, info->count);
+		printk(KERN_ERR "mxser_close: bad serial port count for "
+			"ttys%d: %d\n", info->port, info->count);
 		info->count = 0;
 	}
 	if (info->count) {
@@ -1056,7 +1102,7 @@
 		
 	ld = tty_ldisc_ref(tty);
 	if (ld) {
-		if(ld->flush_buffer)
+		if (ld->flush_buffer)
 			ld->flush_buffer(tty);
 		tty_ldisc_deref(ld);
 	}
@@ -1078,31 +1124,34 @@
 static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
 	int c, total = 0;
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
-	if (!tty || !info->xmit_buf)
-		return (0);
+	if (!info->xmit_buf)
+		return 0;
 
 	while (1) {
-		c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head));
+		c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+					  SERIAL_XMIT_SIZE - info->xmit_head));
 		if (c <= 0)
 			break;
 
 		memcpy(info->xmit_buf + info->xmit_head, buf, c);
 		spin_lock_irqsave(&info->slock, flags);
-		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+		info->xmit_head = (info->xmit_head + c) &
+				  (SERIAL_XMIT_SIZE - 1);
 		info->xmit_cnt += c;
 		spin_unlock_irqrestore(&info->slock, flags);
 
 		buf += c;
 		count -= c;
 		total += c;
-
 	}
 
 	if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
-		if (!tty->hw_stopped || (info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
+		if (!tty->hw_stopped ||
+				(info->type == PORT_16550A) ||
+				(info->IsMoxaMustChipFlag)) {
 			spin_lock_irqsave(&info->slock, flags);
 			info->IER |= UART_IER_THRI;
 			outb(info->IER, info->base + UART_IER);
@@ -1114,10 +1163,10 @@
 
 static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
-	if (!tty || !info->xmit_buf)
+	if (!info->xmit_buf)
 		return;
 
 	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
@@ -1129,7 +1178,9 @@
 	info->xmit_cnt++;
 	spin_unlock_irqrestore(&info->slock, flags);
 	if (!tty->stopped && !(info->IER & UART_IER_THRI)) {
-		if (!tty->hw_stopped || (info->type == PORT_16550A) || info->IsMoxaMustChipFlag) {
+		if (!tty->hw_stopped ||
+				(info->type == PORT_16550A) ||
+				info->IsMoxaMustChipFlag) {
 			spin_lock_irqsave(&info->slock, flags);
 			info->IER |= UART_IER_THRI;
 			outb(info->IER, info->base + UART_IER);
@@ -1141,10 +1192,16 @@
 
 static void mxser_flush_chars(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
-	if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf || (tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)))
+	if (info->xmit_cnt <= 0 ||
+			tty->stopped ||
+			!info->xmit_buf ||
+			(tty->hw_stopped &&
+			 (info->type != PORT_16550A) &&
+			 (!info->IsMoxaMustChipFlag)
+			))
 		return;
 
 	spin_lock_irqsave(&info->slock, flags);
@@ -1157,24 +1214,24 @@
 
 static int mxser_write_room(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	int ret;
 
 	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
 	if (ret < 0)
 		ret = 0;
-	return (ret);
+	return ret;
 }
 
 static int mxser_chars_in_buffer(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	return info->xmit_cnt;
 }
 
 static void mxser_flush_buffer(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	char fcr;
 	unsigned long flags;
 
@@ -1184,7 +1241,8 @@
 
 	/* below added by shinhay */
 	fcr = inb(info->base + UART_FCR);
-	outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+	outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+		info->base + UART_FCR);
 	outb(fcr, info->base + UART_FCR);
 
 	spin_unlock_irqrestore(&info->slock, flags);
@@ -1197,7 +1255,7 @@
 
 static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	int retval;
 	struct async_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct __user *p_cuser;
@@ -1206,9 +1264,9 @@
 	void __user *argp = (void __user *)arg;
 
 	if (tty->index == MXSER_PORTS)
-		return (mxser_ioctl_special(cmd, argp));
+		return mxser_ioctl_special(cmd, argp);
 
-	// following add by Victor Yu. 01-05-2004
+	/* following add by Victor Yu. 01-05-2004 */
 	if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
 		int opmode, p;
 		static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
@@ -1219,7 +1277,10 @@
 		if (cmd == MOXA_SET_OP_MODE) {
 			if (get_user(opmode, (int __user *) argp))
 				return -EFAULT;
-			if (opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE)
+			if (opmode != RS232_MODE &&
+					opmode != RS485_2WIRE_MODE &&
+					opmode != RS422_MODE &&
+					opmode != RS485_4WIRE_MODE)
 				return -EFAULT;
 			mask = ModeMask[p];
 			shiftbit = p * 2;
@@ -1236,36 +1297,36 @@
 		}
 		return 0;
 	}
-	// above add by Victor Yu. 01-05-2004
+	/* above add by Victor Yu. 01-05-2004 */
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 		if (tty->flags & (1 << TTY_IO_ERROR))
-			return (-EIO);
+			return -EIO;
 	}
 	switch (cmd) {
 	case TCSBRK:		/* SVID version: non-zero arg --> no break */
 		retval = tty_check_change(tty);
 		if (retval)
-			return (retval);
+			return retval;
 		tty_wait_until_sent(tty, 0);
 		if (!arg)
 			mxser_send_break(info, HZ / 4);	/* 1/4 second */
-		return (0);
+		return 0;
 	case TCSBRKP:		/* support for POSIX tcsendbreak() */
 		retval = tty_check_change(tty);
 		if (retval)
-			return (retval);
+			return retval;
 		tty_wait_until_sent(tty, 0);
 		mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
-		return (0);
+		return 0;
 	case TIOCGSOFTCAR:
-		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
+		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
 	case TIOCSSOFTCAR:
 		if (get_user(templ, (unsigned long __user *) argp))
 			return -EFAULT;
 		arg = templ;
 		tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
-		return (0);
+		return 0;
 	case TIOCGSERIAL:
 		return mxser_get_serial_info(info, argp);
 	case TIOCSSERIAL:
@@ -1278,7 +1339,7 @@
 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
 		 * Caller should use TIOCGICOUNT to see which one it was
 		 */
-	case TIOCMIWAIT:{
+	case TIOCMIWAIT: {
 			DECLARE_WAITQUEUE(wait, current);
 			int ret;
 			spin_lock_irqsave(&info->slock, flags);
@@ -1292,7 +1353,14 @@
 				spin_unlock_irqrestore(&info->slock, flags);
 
 				set_current_state(TASK_INTERRUPTIBLE);
-				if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+				if (((arg & TIOCM_RNG) &&
+						(cnow.rng != cprev.rng)) ||
+						((arg & TIOCM_DSR) &&
+						(cnow.dsr != cprev.dsr)) ||
+						((arg & TIOCM_CD) &&
+						(cnow.dcd != cprev.dcd)) ||
+						((arg & TIOCM_CTS) &&
+						(cnow.cts != cprev.cts))) {
 					ret = 0;
 					break;
 				}
@@ -1338,21 +1406,18 @@
 		put_user(cnow.dsr, &p_cuser->dsr);
 		put_user(cnow.rng, &p_cuser->rng);
 		put_user(cnow.dcd, &p_cuser->dcd);
-
-/* */
 		return 0;
 	case MOXA_HighSpeedOn:
-		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *) argp);
-
-	case MOXA_SDS_RSTICOUNTER:{
+		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+	case MOXA_SDS_RSTICOUNTER: {
 			info->mon_data.rxcnt = 0;
 			info->mon_data.txcnt = 0;
 			return 0;
 		}
-// (above) added by James.
+/* (above) added by James. */
 	case MOXA_ASPP_SETBAUD:{
 			long baud;
-			if (get_user(baud, (long __user *) argp))
+			if (get_user(baud, (long __user *)argp))
 				return -EFAULT;
 			mxser_set_baud(info, baud);
 			return 0;
@@ -1377,9 +1442,10 @@
 
 			return 0;
 		}
-	case MOXA_ASPP_MON:{
+	case MOXA_ASPP_MON: {
 			int mcr, status;
-//      info->mon_data.ser_param = tty->termios->c_cflag;
+
+			/* info->mon_data.ser_param = tty->termios->c_cflag; */
 
 			status = mxser_get_msr(info->base, 1, info->port, info);
 			mxser_check_modem_status(info, status);
@@ -1400,25 +1466,25 @@
 			else
 				info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
 
-
-			if (copy_to_user(argp, &info->mon_data, sizeof(struct mxser_mon)))
+			if (copy_to_user(argp, &info->mon_data,
+					sizeof(struct mxser_mon)))
 				return -EFAULT;
 
 			return 0;
-
 		}
 
-	case MOXA_ASPP_LSTATUS:{
-			if (copy_to_user(argp, &info->err_shadow, sizeof(unsigned char)))
+	case MOXA_ASPP_LSTATUS: {
+			if (copy_to_user(argp, &info->err_shadow,
+					sizeof(unsigned char)))
 				return -EFAULT;
 
 			info->err_shadow = 0;
 			return 0;
-
 		}
-	case MOXA_SET_BAUD_METHOD:{
+	case MOXA_SET_BAUD_METHOD: {
 			int method;
-			if (get_user(method, (int __user *) argp))
+
+			if (get_user(method, (int __user *)argp))
 				return -EFAULT;
 			mxser_set_baud_method[info->port] = method;
 			if (copy_to_user(argp, &method, sizeof(int)))
@@ -1442,7 +1508,8 @@
 
 	switch (cmd) {
 	case MOXA_GET_CONF:
-		if (copy_to_user(argp, mxsercfg, sizeof(struct mxser_hwconf) * 4))
+		if (copy_to_user(argp, mxsercfg,
+				sizeof(struct mxser_hwconf) * 4))
 			return -EFAULT;
 		return 0;
 	case MOXA_GET_MAJOR:
@@ -1461,11 +1528,11 @@
 			if (mxvar_table[i].base)
 				result |= (1 << i);
 		}
-		return put_user(result, (unsigned long __user *) argp);
+		return put_user(result, (unsigned long __user *)argp);
 	case MOXA_GETDATACOUNT:
 		if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
 			return -EFAULT;
-		return (0);
+		return 0;
 	case MOXA_GETMSTATUS:
 		for (i = 0; i < MXSER_PORTS; i++) {
 			GMStatus[i].ri = 0;
@@ -1498,22 +1565,26 @@
 			else
 				GMStatus[i].cts = 0;
 		}
-		if (copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS))
+		if (copy_to_user(argp, GMStatus,
+				sizeof(struct mxser_mstatus) * MXSER_PORTS))
 			return -EFAULT;
 		return 0;
-	case MOXA_ASPP_MON_EXT:{
+	case MOXA_ASPP_MON_EXT: {
 			int status;
 			int opmode, p;
 			int shiftbit;
 			unsigned cflag, iflag;
 
 			for (i = 0; i < MXSER_PORTS; i++) {
-
 				if (!mxvar_table[i].base)
 					continue;
 
-				status = mxser_get_msr(mxvar_table[i].base, 0, i, &(mxvar_table[i]));
-//                      mxser_check_modem_status(&mxvar_table[i], status);
+				status = mxser_get_msr(mxvar_table[i].base, 0,
+							i, &(mxvar_table[i]));
+				/*
+				mxser_check_modem_status(&mxvar_table[i],
+								status);
+				*/
 				if (status & UART_MSR_TERI)
 					mxvar_table[i].icount.rng++;
 				if (status & UART_MSR_DDSR)
@@ -1578,75 +1649,76 @@
 	return 0;
 }
 
-
 static void mxser_stoprx(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
-	//unsigned long flags;
-
+	struct mxser_struct *info = tty->driver_data;
+	/* unsigned long flags; */
 
 	info->ldisc_stop_rx = 1;
 	if (I_IXOFF(tty)) {
-
-		//MX_LOCK(&info->slock);
-		// following add by Victor Yu. 09-02-2002
+		/* MX_LOCK(&info->slock); */
+		/* following add by Victor Yu. 09-02-2002 */
 		if (info->IsMoxaMustChipFlag) {
 			info->IER &= ~MOXA_MUST_RECV_ISR;
 			outb(info->IER, info->base + UART_IER);
 		} else {
-			// above add by Victor Yu. 09-02-2002
-
+			/* above add by Victor Yu. 09-02-2002 */
 			info->x_char = STOP_CHAR(tty);
-			//      outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
+			/* mask by Victor Yu. 09-02-2002 */
+			/* outb(info->IER, 0); */
 			outb(0, info->base + UART_IER);
 			info->IER |= UART_IER_THRI;
-			outb(info->IER, info->base + UART_IER);	/* force Tx interrupt */
-		}		// add by Victor Yu. 09-02-2002
-		//MX_UNLOCK(&info->slock);
+			/* force Tx interrupt */
+			outb(info->IER, info->base + UART_IER);
+		}		/* add by Victor Yu. 09-02-2002 */
+		/* MX_UNLOCK(&info->slock); */
 	}
 
 	if (info->tty->termios->c_cflag & CRTSCTS) {
-		//MX_LOCK(&info->slock);
+		/* MX_LOCK(&info->slock); */
 		info->MCR &= ~UART_MCR_RTS;
 		outb(info->MCR, info->base + UART_MCR);
-		//MX_UNLOCK(&info->slock);
+		/* MX_UNLOCK(&info->slock); */
 	}
 }
 
 static void mxser_startrx(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
-	//unsigned long flags;
+	struct mxser_struct *info = tty->driver_data;
+	/* unsigned long flags; */
 
 	info->ldisc_stop_rx = 0;
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
 			info->x_char = 0;
 		else {
-			//MX_LOCK(&info->slock);
+			/* MX_LOCK(&info->slock); */
 
-			// following add by Victor Yu. 09-02-2002
+			/* following add by Victor Yu. 09-02-2002 */
 			if (info->IsMoxaMustChipFlag) {
 				info->IER |= MOXA_MUST_RECV_ISR;
 				outb(info->IER, info->base + UART_IER);
 			} else {
-				// above add by Victor Yu. 09-02-2002
+				/* above add by Victor Yu. 09-02-2002 */
 
 				info->x_char = START_CHAR(tty);
-				//          outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
-				outb(0, info->base + UART_IER);	// add by Victor Yu. 09-02-2002
-				info->IER |= UART_IER_THRI;	/* force Tx interrupt */
+				/* mask by Victor Yu. 09-02-2002 */
+				/* outb(info->IER, 0); */
+				/* add by Victor Yu. 09-02-2002 */
+				outb(0, info->base + UART_IER);
+				/* force Tx interrupt */
+				info->IER |= UART_IER_THRI;
 				outb(info->IER, info->base + UART_IER);
-			}	// add by Victor Yu. 09-02-2002
-			//MX_UNLOCK(&info->slock);
+			}	/* add by Victor Yu. 09-02-2002 */
+			/* MX_UNLOCK(&info->slock); */
 		}
 	}
 
 	if (info->tty->termios->c_cflag & CRTSCTS) {
-		//MX_LOCK(&info->slock);
+		/* MX_LOCK(&info->slock); */
 		info->MCR |= UART_MCR_RTS;
 		outb(info->MCR, info->base + UART_MCR);
-		//MX_UNLOCK(&info->slock);
+		/* MX_UNLOCK(&info->slock); */
 	}
 }
 
@@ -1656,48 +1728,53 @@
  */
 static void mxser_throttle(struct tty_struct *tty)
 {
-	//struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
-	//unsigned long flags;
-	//MX_LOCK(&info->slock);
+	/* struct mxser_struct *info = tty->driver_data; */
+	/* unsigned long flags; */
+
+	/* MX_LOCK(&info->slock); */
 	mxser_stoprx(tty);
-	//MX_UNLOCK(&info->slock);
+	/* MX_UNLOCK(&info->slock); */
 }
 
 static void mxser_unthrottle(struct tty_struct *tty)
 {
-	//struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
-	//unsigned long flags;
-	//MX_LOCK(&info->slock);
+	/* struct mxser_struct *info = tty->driver_data; */
+	/* unsigned long flags; */
+
+	/* MX_LOCK(&info->slock); */
 	mxser_startrx(tty);
-	//MX_UNLOCK(&info->slock);
+	/* MX_UNLOCK(&info->slock); */
 }
 
 static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
-	if ((tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+	if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+			(RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
 
 		mxser_change_speed(info, old_termios);
 
-		if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+		if ((old_termios->c_cflag & CRTSCTS) &&
+				!(tty->termios->c_cflag & CRTSCTS)) {
 			tty->hw_stopped = 0;
 			mxser_start(tty);
 		}
 	}
 
 /* Handle sw stopped */
-	if ((old_termios->c_iflag & IXON) && !(tty->termios->c_iflag & IXON)) {
+	if ((old_termios->c_iflag & IXON) &&
+			!(tty->termios->c_iflag & IXON)) {
 		tty->stopped = 0;
 
-		// following add by Victor Yu. 09-02-2002
+		/* following add by Victor Yu. 09-02-2002 */
 		if (info->IsMoxaMustChipFlag) {
 			spin_lock_irqsave(&info->slock, flags);
 			DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
 			spin_unlock_irqrestore(&info->slock, flags);
 		}
-		// above add by Victor Yu. 09-02-2002
+		/* above add by Victor Yu. 09-02-2002 */
 
 		mxser_start(tty);
 	}
@@ -1711,7 +1788,7 @@
  */
 static void mxser_stop(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->slock, flags);
@@ -1724,7 +1801,7 @@
 
 static void mxser_start(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->slock, flags);
@@ -1740,7 +1817,7 @@
  */
 static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long orig_jiffies, char_time;
 	int lsr;
 
@@ -1777,7 +1854,8 @@
 	if (!timeout || timeout > 2 * info->timeout)
 		timeout = 2 * info->timeout;
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-	printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+		timeout, char_time);
 	printk("jiff=%lu...", jiffies);
 #endif
 	while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) {
@@ -1803,7 +1881,7 @@
  */
 void mxser_hangup(struct tty_struct *tty)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 
 	mxser_flush_buffer(tty);
 	mxser_shutdown(info);
@@ -1815,24 +1893,26 @@
 }
 
 
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
 /*
  * mxser_rs_break() --- routine which turns the break handling on or off
  */
 static void mxser_rs_break(struct tty_struct *tty, int break_state)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->slock, flags);
 	if (break_state == -1)
-		outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+		outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+			info->base + UART_LCR);
 	else
-		outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+		outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+			info->base + UART_LCR);
 	spin_unlock_irqrestore(&info->slock, flags);
 }
 
-// (above) added by James.
+/* (above) added by James. */
 
 
 /*
@@ -1848,7 +1928,7 @@
 	int handled = IRQ_NONE;
 
 	port = NULL;
-	//spin_lock(&gm_lock);
+	/* spin_lock(&gm_lock); */
 
 	for (i = 0; i < MXSER_BOARDS; i++) {
 		if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
@@ -1857,29 +1937,25 @@
 		}
 	}
 
-	if (i == MXSER_BOARDS) {
+	if (i == MXSER_BOARDS)
 		goto irq_stop;
-	}
-	if (port == 0) {
+	if (port == 0)
 		goto irq_stop;
-	}
 	max = mxser_numports[mxsercfg[i].board_type - 1];
 	while (1) {
 		irqbits = inb(port->vector) & port->vectormask;
-		if (irqbits == port->vectormask) {
+		if (irqbits == port->vectormask)
 			break;
-		}
 
 		handled = IRQ_HANDLED;
 		for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
-			if (irqbits == port->vectormask) {
+			if (irqbits == port->vectormask)
 				break;
-			}
 			if (bits & irqbits)
 				continue;
 			info = port + i;
 
-			// following add by Victor Yu. 09-13-2002
+			/* following add by Victor Yu. 09-13-2002 */
 			iir = inb(info->base + UART_IIR);
 			if (iir & UART_IIR_NO_INT)
 				continue;
@@ -1890,9 +1966,9 @@
 				inb(info->base + UART_MSR);
 				continue;
 			}
-			// above add by Victor Yu. 09-13-2002
+			/* above add by Victor Yu. 09-13-2002 */
 			/*
-			   if ( info->tty->flip.count < TTY_FLIPBUF_SIZE/4 ){
+			   if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) {
 			   info->IER |= MOXA_MUST_RECV_ISR;
 			   outb(info->IER, info->base + UART_IER);
 			   }
@@ -1908,18 +1984,15 @@
 			   status = inb(info->base + UART_LSR) & info->read_status_mask;
 			 */
 
-			// following add by Victor Yu. 09-02-2002
+			/* following add by Victor Yu. 09-02-2002 */
 			status = inb(info->base + UART_LSR);
 
-			if (status & UART_LSR_PE) {
+			if (status & UART_LSR_PE)
 				info->err_shadow |= NPPI_NOTIFY_PARITY;
-			}
-			if (status & UART_LSR_FE) {
+			if (status & UART_LSR_FE)
 				info->err_shadow |= NPPI_NOTIFY_FRAMING;
-			}
-			if (status & UART_LSR_OE) {
+			if (status & UART_LSR_OE)
 				info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN;
-			}
 			if (status & UART_LSR_BI)
 				info->err_shadow |= NPPI_NOTIFY_BREAK;
 
@@ -1930,11 +2003,14 @@
 				   continue;
 				   }
 				 */
-				if (iir == MOXA_MUST_IIR_GDA || iir == MOXA_MUST_IIR_RDA || iir == MOXA_MUST_IIR_RTO || iir == MOXA_MUST_IIR_LSR)
+				if (iir == MOXA_MUST_IIR_GDA ||
+						iir == MOXA_MUST_IIR_RDA ||
+						iir == MOXA_MUST_IIR_RTO ||
+						iir == MOXA_MUST_IIR_LSR)
 					mxser_receive_chars(info, &status);
 
 			} else {
-				// above add by Victor Yu. 09-02-2002
+				/* above add by Victor Yu. 09-02-2002 */
 
 				status &= info->read_status_mask;
 				if (status & UART_LSR_DR)
@@ -1944,13 +2020,13 @@
 			if (msr & UART_MSR_ANY_DELTA) {
 				mxser_check_modem_status(info, msr);
 			}
-			// following add by Victor Yu. 09-13-2002
+			/* following add by Victor Yu. 09-13-2002 */
 			if (info->IsMoxaMustChipFlag) {
 				if ((iir == 0x02) && (status & UART_LSR_THRE)) {
 					mxser_transmit_chars(info);
 				}
 			} else {
-				// above add by Victor Yu. 09-13-2002
+				/* above add by Victor Yu. 09-13-2002 */
 
 				if (status & UART_LSR_THRE) {
 /* 8-2-99 by William
@@ -1966,7 +2042,7 @@
 	}
 
       irq_stop:
-	//spin_unlock(&gm_lock);
+	/* spin_unlock(&gm_lock); */
 	return handled;
 }
 
@@ -1984,56 +2060,58 @@
 
 	recv_room = tty->receive_room;
 	if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
-		//mxser_throttle(tty);
+		/* mxser_throttle(tty); */
 		mxser_stoprx(tty);
-		//return;
+		/* return; */
 	}
 
-	// following add by Victor Yu. 09-02-2002
+	/* following add by Victor Yu. 09-02-2002 */
 	if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
 
 		if (*status & UART_LSR_SPECIAL) {
 			goto intr_old;
 		}
-		// following add by Victor Yu. 02-11-2004
-		if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID && (*status & MOXA_MUST_LSR_RERR))
+		/* following add by Victor Yu. 02-11-2004 */
+		if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID &&
+				(*status & MOXA_MUST_LSR_RERR))
 			goto intr_old;
-		// above add by Victor Yu. 02-14-2004
+		/* above add by Victor Yu. 02-14-2004 */
 		if (*status & MOXA_MUST_LSR_RERR)
 			goto intr_old;
 
 		gdl = inb(info->base + MOXA_MUST_GDL_REGISTER);
 
-		if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)	// add by Victor Yu. 02-11-2004
+		/* add by Victor Yu. 02-11-2004 */
+		if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)
 			gdl &= MOXA_MUST_GDL_MASK;
 		if (gdl >= recv_room) {
 			if (!info->ldisc_stop_rx) {
-				//mxser_throttle(tty);
+				/* mxser_throttle(tty); */
 				mxser_stoprx(tty);
 			}
-			//return;
+			/* return; */
 		}
 		while (gdl--) {
 			ch = inb(info->base + UART_RX);
 			tty_insert_flip_char(tty, ch, 0);
 			cnt++;
 			/*
-			   if((cnt>=HI_WATER) && (info->stop_rx==0)){
+			   if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
 			   mxser_stoprx(tty);
-			   info->stop_rx=1;
+			   info->stop_rx = 1;
 			   break;
 			   } */
 		}
 		goto end_intr;
 	}
-intr_old:
-	// above add by Victor Yu. 09-02-2002
+ intr_old:
+	/* above add by Victor Yu. 09-02-2002 */
 
 	do {
 		if (max-- < 0)
 			break;
 		/*
-		   if((cnt>=HI_WATER) && (info->stop_rx==0)){
+		   if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
 		   mxser_stoprx(tty);
 		   info->stop_rx=1;
 		   break;
@@ -2041,11 +2119,11 @@
 		 */
 
 		ch = inb(info->base + UART_RX);
-		// following add by Victor Yu. 09-02-2002
+		/* following add by Victor Yu. 09-02-2002 */
 		if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ )
 			outb(0x23, info->base + UART_FCR);
 		*status &= info->read_status_mask;
-		// above add by Victor Yu. 09-02-2002
+		/* above add by Victor Yu. 09-02-2002 */
 		if (*status & info->ignore_status_mask) {
 			if (++ignored > 100)
 				break;
@@ -2080,7 +2158,7 @@
 			cnt++;
 			if (cnt >= recv_room) {
 				if (!info->ldisc_stop_rx) {
-					//mxser_throttle(tty);
+					/* mxser_throttle(tty); */
 					mxser_stoprx(tty);
 				}
 				break;
@@ -2088,21 +2166,20 @@
 
 		}
 
-		// following add by Victor Yu. 09-02-2002
+		/* following add by Victor Yu. 09-02-2002 */
 		if (info->IsMoxaMustChipFlag)
 			break;
-		// above add by Victor Yu. 09-02-2002
+		/* above add by Victor Yu. 09-02-2002 */
 
 		/* mask by Victor Yu. 09-02-2002
 		 *status = inb(info->base + UART_LSR) & info->read_status_mask;
 		 */
-		// following add by Victor Yu. 09-02-2002
+		/* following add by Victor Yu. 09-02-2002 */
 		*status = inb(info->base + UART_LSR);
-		// above add by Victor Yu. 09-02-2002
+		/* above add by Victor Yu. 09-02-2002 */
 	} while (*status & UART_LSR_DR);
 
-end_intr:		// add by Victor Yu. 09-02-2002
-
+end_intr:		/* add by Victor Yu. 09-02-2002 */
 	mxvar_log.rxcnt[info->port] += cnt;
 	info->mon_data.rxcnt += cnt;
 	info->mon_data.up_rxcnt += cnt;
@@ -2137,7 +2214,10 @@
 		return;
 	}
 
-	if ((info->xmit_cnt <= 0) || info->tty->stopped || (info->tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag))) {
+	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+			(info->tty->hw_stopped &&
+			(info->type != PORT_16550A) &&
+			(!info->IsMoxaMustChipFlag))) {
 		info->IER &= ~UART_IER_THRI;
 		outb(info->IER, info->base + UART_IER);
 		spin_unlock_irqrestore(&info->slock, flags);
@@ -2147,17 +2227,18 @@
 	cnt = info->xmit_cnt;
 	count = info->xmit_fifo_size;
 	do {
-		outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
+		outb(info->xmit_buf[info->xmit_tail++],
+			info->base + UART_TX);
 		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
 		if (--info->xmit_cnt <= 0)
 			break;
 	} while (--count > 0);
 	mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
 
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
 	info->mon_data.txcnt += (cnt - info->xmit_cnt);
 	info->mon_data.up_txcnt += (cnt - info->xmit_cnt);
-// (above) added by James.
+/* (above) added by James. */
 
 /* added by casper 1/11/2000 */
 	info->icount.tx += (cnt - info->xmit_cnt);
@@ -2188,7 +2269,6 @@
 	info->mon_data.modem_status = status;
 	wake_up_interruptible(&info->delta_msr_wait);
 
-
 	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
@@ -2200,7 +2280,8 @@
 			if (status & UART_MSR_CTS) {
 				info->tty->hw_stopped = 0;
 
-				if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+				if ((info->type != PORT_16550A) &&
+						(!info->IsMoxaMustChipFlag)) {
 					info->IER |= UART_IER_THRI;
 					outb(info->IER, info->base + UART_IER);
 				}
@@ -2209,7 +2290,8 @@
 		} else {
 			if (!(status & UART_MSR_CTS)) {
 				info->tty->hw_stopped = 1;
-				if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+				if ((info->type != PORT_16550A) &&
+						(!info->IsMoxaMustChipFlag)) {
 					info->IER &= ~UART_IER_THRI;
 					outb(info->IER, info->base + UART_IER);
 				}
@@ -2231,7 +2313,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
 		info->flags |= ASYNC_NORMAL_ACTIVE;
-		return (0);
+		return 0;
 	}
 
 	if (tty->termios->c_cflag & CLOCAL)
@@ -2254,7 +2336,8 @@
 	info->blocked_open++;
 	while (1) {
 		spin_lock_irqsave(&info->slock, flags);
-		outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
+		outb(inb(info->base + UART_MCR) |
+			UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
 		spin_unlock_irqrestore(&info->slock, flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
@@ -2264,7 +2347,9 @@
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+		if (!(info->flags & ASYNC_CLOSING) &&
+				(do_clocal ||
+				(inb(info->base + UART_MSR) & UART_MSR_DCD)))
 			break;
 		if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
@@ -2278,27 +2363,26 @@
 		info->count++;
 	info->blocked_open--;
 	if (retval)
-		return (retval);
+		return retval;
 	info->flags |= ASYNC_NORMAL_ACTIVE;
-	return (0);
+	return 0;
 }
 
 static int mxser_startup(struct mxser_struct *info)
 {
-
 	unsigned long page;
 	unsigned long flags;
 
 	page = __get_free_page(GFP_KERNEL);
 	if (!page)
-		return (-ENOMEM);
+		return -ENOMEM;
 
 	spin_lock_irqsave(&info->slock, flags);
 
 	if (info->flags & ASYNC_INITIALIZED) {
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
-		return (0);
+		return 0;
 	}
 
 	if (!info->base || !info->type) {
@@ -2306,7 +2390,7 @@
 			set_bit(TTY_IO_ERROR, &info->tty->flags);
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
-		return (0);
+		return 0;
 	}
 	if (info->xmit_buf)
 		free_page(page);
@@ -2318,9 +2402,12 @@
 	 * (they will be reenabled in mxser_change_speed())
 	 */
 	if (info->IsMoxaMustChipFlag)
-		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+		outb((UART_FCR_CLEAR_RCVR |
+			UART_FCR_CLEAR_XMIT |
+			MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
 	else
-		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+			info->base + UART_FCR);
 
 	/*
 	 * At this point there's no way the LSR could still be 0xFF;
@@ -2332,9 +2419,9 @@
 		if (capable(CAP_SYS_ADMIN)) {
 			if (info->tty)
 				set_bit(TTY_IO_ERROR, &info->tty->flags);
-			return (0);
+			return 0;
 		} else
-			return (-ENODEV);
+			return -ENODEV;
 	}
 
 	/*
@@ -2356,12 +2443,12 @@
 	 * Finally, enable interrupts
 	 */
 	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-//      info->IER = UART_IER_RLSI | UART_IER_RDI;
+	/* info->IER = UART_IER_RLSI | UART_IER_RDI; */
 
-	// following add by Victor Yu. 08-30-2002
+	/* following add by Victor Yu. 08-30-2002 */
 	if (info->IsMoxaMustChipFlag)
 		info->IER |= MOXA_MUST_IER_EGDAI;
-	// above add by Victor Yu. 08-30-2002
+	/* above add by Victor Yu. 08-30-2002 */
 	outb(info->IER, info->base + UART_IER);	/* enable interrupts */
 
 	/*
@@ -2383,7 +2470,7 @@
 	mxser_change_speed(info, NULL);
 
 	info->flags |= ASYNC_INITIALIZED;
-	return (0);
+	return 0;
 }
 
 /*
@@ -2421,12 +2508,15 @@
 	outb(info->MCR, info->base + UART_MCR);
 
 	/* clear Rx/Tx FIFO's */
-	// following add by Victor Yu. 08-30-2002
+	/* following add by Victor Yu. 08-30-2002 */
 	if (info->IsMoxaMustChipFlag)
-		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+		outb((UART_FCR_CLEAR_RCVR |
+			UART_FCR_CLEAR_XMIT |
+			MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
 	else
-		// above add by Victor Yu. 08-30-2002
-		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+		/* above add by Victor Yu. 08-30-2002 */
+		outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+			info->base + UART_FCR);
 
 	/* read data port to reset things */
 	(void) inb(info->base + UART_RX);
@@ -2436,11 +2526,10 @@
 
 	info->flags &= ~ASYNC_INITIALIZED;
 
-	// following add by Victor Yu. 09-23-2002
-	if (info->IsMoxaMustChipFlag) {
+	/* following add by Victor Yu. 09-23-2002 */
+	if (info->IsMoxaMustChipFlag)
 		SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
-	}
-	// above add by Victor Yu. 09-23-2002
+	/* above add by Victor Yu. 09-23-2002 */
 
 	spin_unlock_irqrestore(&info->slock, flags);
 }
@@ -2457,14 +2546,12 @@
 	long baud;
 	unsigned long flags;
 
-
 	if (!info->tty || !info->tty->termios)
 		return ret;
 	cflag = info->tty->termios->c_cflag;
 	if (!(info->base))
 		return ret;
 
-
 #ifndef B921600
 #define B921600 (B460800 +1)
 #endif
@@ -2559,9 +2646,8 @@
 		cval |= 0x04;
 	if (cflag & PARENB)
 		cval |= UART_LCR_PARITY;
-	if (!(cflag & PARODD)) {
+	if (!(cflag & PARODD))
 		cval |= UART_LCR_EPAR;
-	}
 	if (cflag & CMSPAR)
 		cval |= UART_LCR_SPAR;
 
@@ -2574,13 +2660,12 @@
 			fcr = 0;
 	} else {
 		fcr = UART_FCR_ENABLE_FIFO;
-		// following add by Victor Yu. 08-30-2002
+		/* following add by Victor Yu. 08-30-2002 */
 		if (info->IsMoxaMustChipFlag) {
 			fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
 			SET_MOXA_MUST_FIFO_VALUE(info);
 		} else {
-			// above add by Victor Yu. 08-30-2002
-
+			/* above add by Victor Yu. 08-30-2002 */
 			switch (info->rx_trigger) {
 			case 1:
 				fcr |= UART_FCR_TRIGGER_1;
@@ -2606,22 +2691,24 @@
 		info->IER |= UART_IER_MSI;
 		if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
 			info->MCR |= UART_MCR_AFE;
-			//status = mxser_get_msr(info->base, 0, info->port);
-/*	save_flags(flags);
+			/* status = mxser_get_msr(info->base, 0, info->port); */
+/*
+	save_flags(flags);
 	cli();
 	status = inb(baseaddr + UART_MSR);
-	restore_flags(flags);*/
-			//mxser_check_modem_status(info, status);
+	restore_flags(flags);
+*/
+			/* mxser_check_modem_status(info, status); */
 		} else {
-			//status = mxser_get_msr(info->base, 0, info->port);
-
-			//MX_LOCK(&info->slock);
+			/* status = mxser_get_msr(info->base, 0, info->port); */
+			/* MX_LOCK(&info->slock); */
 			status = inb(info->base + UART_MSR);
-			//MX_UNLOCK(&info->slock);
+			/* MX_UNLOCK(&info->slock); */
 			if (info->tty->hw_stopped) {
 				if (status & UART_MSR_CTS) {
 					info->tty->hw_stopped = 0;
-					if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+					if ((info->type != PORT_16550A) &&
+							(!info->IsMoxaMustChipFlag)) {
 						info->IER |= UART_IER_THRI;
 						outb(info->IER, info->base + UART_IER);
 					}
@@ -2630,7 +2717,8 @@
 			} else {
 				if (!(status & UART_MSR_CTS)) {
 					info->tty->hw_stopped = 1;
-					if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+					if ((info->type != PORT_16550A) &&
+							(!info->IsMoxaMustChipFlag)) {
 						info->IER &= ~UART_IER_THRI;
 						outb(info->IER, info->base + UART_IER);
 					}
@@ -2668,11 +2756,17 @@
 		 * overruns too.  (For real raw support).
 		 */
 		if (I_IGNPAR(info->tty)) {
-			info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
-			info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+			info->ignore_status_mask |=
+						UART_LSR_OE |
+						UART_LSR_PE |
+						UART_LSR_FE;
+			info->read_status_mask |=
+						UART_LSR_OE |
+						UART_LSR_PE |
+						UART_LSR_FE;
 		}
 	}
-	// following add by Victor Yu. 09-02-2002
+	/* following add by Victor Yu. 09-02-2002 */
 	if (info->IsMoxaMustChipFlag) {
 		spin_lock_irqsave(&info->slock, flags);
 		SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
@@ -2698,7 +2792,7 @@
 		 */
 		spin_unlock_irqrestore(&info->slock, flags);
 	}
-	// above add by Victor Yu. 09-02-2002
+	/* above add by Victor Yu. 09-02-2002 */
 
 
 	outb(fcr, info->base + UART_FCR);	/* set fcr */
@@ -2729,10 +2823,8 @@
 		quot = (2 * info->baud_base / 269);
 	} else if (newspd) {
 		quot = info->baud_base / newspd;
-
 		if (quot == 0)
 			quot = 1;
-
 	} else {
 		quot = 0;
 	}
@@ -2765,8 +2857,6 @@
 	return ret;
 }
 
-
-
 /*
  * ------------------------------------------------------------
  * friends of mxser_ioctl()
@@ -2777,7 +2867,7 @@
 	struct serial_struct tmp;
 
 	if (!retinfo)
-		return (-EFAULT);
+		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.type = info->type;
 	tmp.line = info->port;
@@ -2791,7 +2881,7 @@
 	tmp.hub6 = 0;
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
-	return (0);
+	return 0;
 }
 
 static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
@@ -2801,29 +2891,37 @@
 	int retval = 0;
 
 	if (!new_info || !info->base)
-		return (-EFAULT);
+		return -EFAULT;
 	if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
 		return -EFAULT;
 
-	if ((new_serial.irq != info->irq) || (new_serial.port != info->base) || (new_serial.custom_divisor != info->custom_divisor) || (new_serial.baud_base != info->baud_base))
-		return (-EPERM);
+	if ((new_serial.irq != info->irq) ||
+			(new_serial.port != info->base) ||
+			(new_serial.custom_divisor != info->custom_divisor) ||
+			(new_serial.baud_base != info->baud_base))
+		return -EPERM;
 
 	flags = info->flags & ASYNC_SPD_MASK;
 
 	if (!capable(CAP_SYS_ADMIN)) {
-		if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
-			return (-EPERM);
-		info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK));
+		if ((new_serial.baud_base != info->baud_base) ||
+				(new_serial.close_delay != info->close_delay) ||
+				((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+				(new_serial.flags & ASYNC_USR_MASK));
 	} else {
 		/*
 		 * OK, past this point, all the error checking has been done.
 		 * At this point, we start making changes.....
 		 */
-		info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS));
+		info->flags = ((info->flags & ~ASYNC_FLAGS) |
+				(new_serial.flags & ASYNC_FLAGS));
 		info->close_delay = new_serial.close_delay * HZ / 100;
 		info->closing_wait = new_serial.closing_wait * HZ / 100;
-		info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-		info->tty->low_latency = 0;	//(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+		info->tty->low_latency =
+				(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+		info->tty->low_latency = 0;	/* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
 	}
 
 	/* added by casper, 3/17/2000, for mouse */
@@ -2831,7 +2929,6 @@
 
 	process_txrx_fifo(info);
 
-	/* */
 	if (info->flags & ASYNC_INITIALIZED) {
 		if (flags != (info->flags & ASYNC_SPD_MASK)) {
 			mxser_change_speed(info, NULL);
@@ -2839,7 +2936,7 @@
 	} else {
 		retval = mxser_startup(info);
 	}
-	return (retval);
+	return retval;
 }
 
 /*
@@ -2876,25 +2973,27 @@
 		return;
 	set_current_state(TASK_INTERRUPTIBLE);
 	spin_lock_irqsave(&info->slock, flags);
-	outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+	outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+		info->base + UART_LCR);
 	spin_unlock_irqrestore(&info->slock, flags);
 	schedule_timeout(duration);
 	spin_lock_irqsave(&info->slock, flags);
-	outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+	outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+		info->base + UART_LCR);
 	spin_unlock_irqrestore(&info->slock, flags);
 }
 
 static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned char control, status;
 	unsigned long flags;
 
 
 	if (tty->index == MXSER_PORTS)
-		return (-ENOIOCTLCMD);
+		return -ENOIOCTLCMD;
 	if (tty->flags & (1 << TTY_IO_ERROR))
-		return (-EIO);
+		return -EIO;
 
 	control = info->MCR;
 
@@ -2904,12 +3003,16 @@
 		mxser_check_modem_status(info, status);
 	spin_unlock_irqrestore(&info->slock, flags);
 	return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
-	    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+		    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+		    ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+		    ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+		    ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+		    ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
 }
 
 static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
 {
-	struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+	struct mxser_struct *info = tty->driver_data;
 	unsigned long flags;
 
 
@@ -2968,38 +3071,36 @@
 		hwconf->board_type = MXSER_BOARD_CI104J;
 		hwconf->ports = 4;
 	} else
-		return (0);
+		return 0;
 
 	irq = 0;
 	if (hwconf->ports == 2) {
 		irq = regs[9] & 0xF000;
 		irq = irq | (irq >> 4);
 		if (irq != (regs[9] & 0xFF00))
-			return (MXSER_ERR_IRQ_CONFLIT);
+			return MXSER_ERR_IRQ_CONFLIT;
 	} else if (hwconf->ports == 4) {
 		irq = regs[9] & 0xF000;
 		irq = irq | (irq >> 4);
 		irq = irq | (irq >> 8);
 		if (irq != regs[9])
-			return (MXSER_ERR_IRQ_CONFLIT);
+			return MXSER_ERR_IRQ_CONFLIT;
 	} else if (hwconf->ports == 8) {
 		irq = regs[9] & 0xF000;
 		irq = irq | (irq >> 4);
 		irq = irq | (irq >> 8);
 		if ((irq != regs[9]) || (irq != regs[10]))
-			return (MXSER_ERR_IRQ_CONFLIT);
+			return MXSER_ERR_IRQ_CONFLIT;
 	}
 
-	if (!irq) {
-		return (MXSER_ERR_IRQ);
-	}
-	hwconf->irq = ((int) (irq & 0xF000) >> 12);
+	if (!irq)
+		return MXSER_ERR_IRQ;
+	hwconf->irq = ((int)(irq & 0xF000) >> 12);
 	for (i = 0; i < 8; i++)
 		hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
-	if ((regs[12] & 0x80) == 0) {
-		return (MXSER_ERR_VECTOR);
-	}
-	hwconf->vector = (int) regs[11];	/* interrupt vector */
+	if ((regs[12] & 0x80) == 0)
+		return MXSER_ERR_VECTOR;
+	hwconf->vector = (int)regs[11];	/* interrupt vector */
 	if (id == 1)
 		hwconf->vector_mask = 0x00FF;
 	else
@@ -3007,10 +3108,10 @@
 	for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
 		if (regs[12] & bits) {
 			hwconf->baud_base[i] = 921600;
-			hwconf->MaxCanSetBaudRate[i] = 921600;	// add by Victor Yu. 09-04-2002
+			hwconf->MaxCanSetBaudRate[i] = 921600;	/* add by Victor Yu. 09-04-2002 */
 		} else {
 			hwconf->baud_base[i] = 115200;
-			hwconf->MaxCanSetBaudRate[i] = 115200;	// add by Victor Yu. 09-04-2002
+			hwconf->MaxCanSetBaudRate[i] = 115200;	/* add by Victor Yu. 09-04-2002 */
 		}
 	}
 	scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -3030,7 +3131,7 @@
 		hwconf->ports = 4;
 	request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)");
 	request_region(hwconf->vector, 1, "mxser(vector)");
-	return (hwconf->ports);
+	return hwconf->ports;
 }
 
 #define CHIP_SK 	0x01	/* Serial Data Clock  in Eprom */
@@ -3053,7 +3154,7 @@
 
 	id = mxser_program_mode(port);
 	if (id < 0)
-		return (id);
+		return id;
 	for (i = 0; i < 14; i++) {
 		k = (i & 0x3F) | 0x180;
 		for (j = 0x100; j > 0; j >>= 1) {
@@ -3066,7 +3167,7 @@
 				outb(CHIP_CS | CHIP_SK, port);	/* A? bit of read */
 			}
 		}
-		(void) inb(port);
+		(void)inb(port);
 		value = 0;
 		for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
 			outb(CHIP_CS, port);
@@ -3078,28 +3179,33 @@
 		outb(0, port);
 	}
 	mxser_normal_mode(port);
-	return (id);
+	return id;
 }
 
 static int mxser_program_mode(int port)
 {
 	int id, i, j, n;
-	//unsigned long flags;
+	/* unsigned long flags; */
 
 	spin_lock(&gm_lock);
 	outb(0, port);
 	outb(0, port);
 	outb(0, port);
-	(void) inb(port);
-	(void) inb(port);
+	(void)inb(port);
+	(void)inb(port);
 	outb(0, port);
-	(void) inb(port);
-	//restore_flags(flags);
+	(void)inb(port);
+	/* restore_flags(flags); */
 	spin_unlock(&gm_lock);
 
 	id = inb(port + 1) & 0x1F;
-	if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID) && (id != CI104J_ASIC_ID))
-		return (-1);
+	if ((id != C168_ASIC_ID) &&
+			(id != C104_ASIC_ID) &&
+			(id != C102_ASIC_ID) &&
+			(id != CI132_ASIC_ID) &&
+			(id != CI134_ASIC_ID) &&
+			(id != CI104J_ASIC_ID))
+		return -1;
 	for (i = 0, j = 0; i < 4; i++) {
 		n = inb(port + 2);
 		if (n == 'M') {
@@ -3112,7 +3218,7 @@
 	}
 	if (j != 2)
 		id = -2;
-	return (id);
+	return id;
 }
 
 static void mxser_normal_mode(int port)
@@ -3130,7 +3236,7 @@
 		if ((n & 0x61) == 0x60)
 			break;
 		if ((n & 1) == 1)
-			(void) inb(port);
+			(void)inb(port);
 	}
 	outb(0x00, port + 4);
 }
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index c48de09..203dc2b 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -951,7 +951,8 @@
    {
 queue_the_message:
 
-      pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
+      pMsg = kmalloc(sizeof(struct r3964_message),
+		     error_code?GFP_ATOMIC:GFP_KERNEL);
       TRACE_M("add_msg - kmalloc %p",pMsg);
       if(pMsg==NULL) {
          return;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0c141c2..17bc8ab 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1582,7 +1582,7 @@
 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
 		return;
 
-	if (!tty || !info->tx_buf)
+	if (!info->tx_buf)
 		return;
 
 	spin_lock_irqsave(&info->lock,flags);
@@ -1649,7 +1649,7 @@
 			__FILE__,__LINE__,info->device_name,count);
 	
 	if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
-	    !tty || !info->tx_buf)
+		!info->tx_buf)
 		goto cleanup;
 
 	if (info->params.mode == MGSL_MODE_HDLC) {
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index eec1fea..0bd0904 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -546,7 +546,7 @@
 	 ** run out of space it will be set to the offset of the
 	 ** next byte to copy from the packet data area. The packet
 	 ** length field is decremented by the number of bytes that
-	 ** we succesfully removed from the packet. When this reaches
+	 ** we successfully removed from the packet. When this reaches
 	 ** zero, we reset the offset pointer to be zero, and free
 	 ** the packet from the front of the queue.
 	 */
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 7edc6a4..0708c51 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -324,35 +324,15 @@
 			  CHANNEL_t * cp, unsigned int ChanStatus)
 {
 	unsigned int CharNStat;
-	int ToRecv, wRecv, space = 0, count;
-	unsigned char *cbuf, *chead;
-	char *fbuf, *fhead;
-	struct tty_ldisc *ld;
-
-	ld = tty_ldisc_ref(tty);
+	int ToRecv, wRecv, space;
+	unsigned char *cbuf;
 
 	ToRecv = sGetRxCnt(cp);
-	space = tty->receive_room;
-	if (space > 2 * TTY_FLIPBUF_SIZE)
-		space = 2 * TTY_FLIPBUF_SIZE;
-	count = 0;
 #ifdef ROCKET_DEBUG_INTR
-	printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space);
+	printk(KERN_INFO "rp_do_receive(%d)...", ToRecv);
 #endif
-
-	/*
-	 * determine how many we can actually read in.  If we can't
-	 * read any in then we have a software overrun condition.
-	 */
-	if (ToRecv > space)
-		ToRecv = space;
-
-	ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv);
-	if (ToRecv <= 0)
-		goto done;
-
-	cbuf = chead;
-	fbuf = fhead;
+	if (ToRecv == 0)
+		return;
 
 	/*
 	 * if status indicates there are errored characters in the
@@ -380,6 +360,8 @@
 		       info->read_status_mask);
 #endif
 		while (ToRecv) {
+			char flag;
+
 			CharNStat = sInW(sGetTxRxDataIO(cp));
 #ifdef ROCKET_DEBUG_RECEIVE
 			printk(KERN_INFO "%x...", CharNStat);
@@ -392,17 +374,16 @@
 			}
 			CharNStat &= info->read_status_mask;
 			if (CharNStat & STMBREAKH)
-				*fbuf++ = TTY_BREAK;
+				flag = TTY_BREAK;
 			else if (CharNStat & STMPARITYH)
-				*fbuf++ = TTY_PARITY;
+				flag = TTY_PARITY;
 			else if (CharNStat & STMFRAMEH)
-				*fbuf++ = TTY_FRAME;
+				flag = TTY_FRAME;
 			else if (CharNStat & STMRCVROVRH)
-				*fbuf++ = TTY_OVERRUN;
+				flag = TTY_OVERRUN;
 			else
-				*fbuf++ = TTY_NORMAL;
-			*cbuf++ = CharNStat & 0xff;
-			count++;
+				flag = TTY_NORMAL;
+			tty_insert_flip_char(tty, CharNStat & 0xff, flag);
 			ToRecv--;
 		}
 
@@ -422,20 +403,23 @@
 		 * characters at time by doing repeated word IO
 		 * transfer.
 		 */
+		space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
+		if (space < ToRecv) {
+#ifdef ROCKET_DEBUG_RECEIVE
+			printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
+#endif
+			if (space <= 0)
+				return;
+			ToRecv = space;
+		}
 		wRecv = ToRecv >> 1;
 		if (wRecv)
 			sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
 		if (ToRecv & 1)
 			cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
-		memset(fbuf, TTY_NORMAL, ToRecv);
-		cbuf += ToRecv;
-		fbuf += ToRecv;
-		count += ToRecv;
 	}
 	/*  Push the data up to the tty layer */
-	ld->receive_buf(tty, chead, fhead, count);
-done:
-	tty_ldisc_deref(ld);
+	tty_flip_buffer_push(tty);
 }
 
 /*
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 5343e9f..1b53302 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -1683,7 +1683,7 @@
 
 	bp = port_Board(port);
 
-	if (!tty || !port->xmit_buf || !tmp_buf) {
+	if (!port->xmit_buf || !tmp_buf) {
 		func_exit();
 		return 0;
 	}
@@ -1733,7 +1733,7 @@
 		return;
 	}
 	dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
-	if (!tty || !port->xmit_buf) {
+	if (!port->xmit_buf) {
 		func_exit();
 		return;
 	}
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index b4d1f4e..4e35d41 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -101,6 +101,7 @@
 
 static struct pci_device_id pci_table[] = {
 	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
 	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
 	{PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,}, /* terminate list */
@@ -870,7 +871,7 @@
 		goto cleanup;
 	DBGINFO(("%s write count=%d\n", info->device_name, count));
 
-	if (!tty || !info->tx_buf)
+	if (!info->tx_buf)
 		goto cleanup;
 
 	if (count > info->max_frame_size) {
@@ -924,7 +925,7 @@
 	if (sanity_check(info, tty->name, "put_char"))
 		return;
 	DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
-	if (!tty || !info->tx_buf)
+	if (!info->tx_buf)
 		return;
 	spin_lock_irqsave(&info->lock,flags);
 	if (!info->tx_active && (info->tx_count < info->max_frame_size))
@@ -2515,7 +2516,8 @@
 	DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
 	spin_lock_irqsave(&info->lock,flags);
 	info->idle_mode = idle_mode;
-	tx_set_idle(info);
+	if (info->params.mode != MGSL_MODE_ASYNC)
+		tx_set_idle(info);
 	spin_unlock_irqrestore(&info->lock,flags);
 	return 0;
 }
@@ -3076,7 +3078,7 @@
 
 static int alloc_tmp_rbuf(struct slgt_info *info)
 {
-	info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+	info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL);
 	if (info->tmp_rbuf == NULL)
 		return -ENOMEM;
 	return 0;
@@ -3276,6 +3278,9 @@
 	case SYNCLINK_GT_DEVICE_ID:
 		devstr = "GT";
 		break;
+	case SYNCLINK_GT2_DEVICE_ID:
+		devstr = "GT2";
+		break;
 	case SYNCLINK_GT4_DEVICE_ID:
 		devstr = "GT4";
 		break;
@@ -3353,7 +3358,9 @@
 	int i;
 	int port_count = 1;
 
-	if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+	if (pdev->device == SYNCLINK_GT2_DEVICE_ID)
+		port_count = 2;
+	else if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
 		port_count = 4;
 
 	/* allocate device instances for all ports */
@@ -3940,8 +3947,6 @@
 
 	msc_set_vcr(info);
 
-	tx_set_idle(info);
-
 	/* SCR (serial control)
 	 *
 	 * 15  1=tx req on FIFO half empty
@@ -4012,7 +4017,7 @@
 	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
 	}
 
-	switch (info->params.crc_type)
+	switch (info->params.crc_type & HDLC_CRC_MASK)
 	{
 	case HDLC_CRC_16_CCITT: val |= BIT9; break;
 	case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4073,7 +4078,7 @@
 	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
 	}
 
-	switch (info->params.crc_type)
+	switch (info->params.crc_type & HDLC_CRC_MASK)
 	{
 	case HDLC_CRC_16_CCITT: val |= BIT9; break;
 	case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4175,17 +4180,38 @@
  */
 static void tx_set_idle(struct slgt_info *info)
 {
-	unsigned char val = 0xff;
+	unsigned char val;
+	unsigned short tcr;
 
-	switch(info->idle_mode)
-	{
-	case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
-	case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
-	case HDLC_TXIDLE_ZEROS:          val = 0x00; break;
-	case HDLC_TXIDLE_ONES:           val = 0xff; break;
-	case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
-	case HDLC_TXIDLE_SPACE:          val = 0x00; break;
-	case HDLC_TXIDLE_MARK:           val = 0xff; break;
+	/* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits
+	 * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits
+	 */
+	tcr = rd_reg16(info, TCR);
+	if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) {
+		/* disable preamble, set idle size to 16 bits */
+		tcr = (tcr & ~(BIT6 + BIT5)) | BIT4;
+		/* MSB of 16 bit idle specified in tx preamble register (TPR) */
+		wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff));
+	} else if (!(tcr & BIT6)) {
+		/* preamble is disabled, set idle size to 8 bits */
+		tcr &= ~(BIT5 + BIT4);
+	}
+	wr_reg16(info, TCR, tcr);
+
+	if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) {
+		/* LSB of custom tx idle specified in tx idle register */
+		val = (unsigned char)(info->idle_mode & 0xff);
+	} else {
+		/* standard 8 bit idle patterns */
+		switch(info->idle_mode)
+		{
+		case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
+		case HDLC_TXIDLE_ALT_ZEROS_ONES:
+		case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+		case HDLC_TXIDLE_ZEROS:
+		case HDLC_TXIDLE_SPACE:          val = 0x00; break;
+		default:                         val = 0xff;
+		}
 	}
 
 	wr_reg8(info, TIR, val);
@@ -4313,6 +4339,12 @@
 	unsigned long flags;
 	struct tty_struct *tty = info->tty;
 	unsigned char addr_field = 0xff;
+	unsigned int crc_size = 0;
+
+	switch (info->params.crc_type & HDLC_CRC_MASK) {
+	case HDLC_CRC_16_CCITT: crc_size = 2; break;
+	case HDLC_CRC_32_CCITT: crc_size = 4; break;
+	}
 
 check_again:
 
@@ -4357,7 +4389,7 @@
 	status = desc_status(info->rbufs[end]);
 
 	/* ignore CRC bit if not using CRC (bit is undefined) */
-	if (info->params.crc_type == HDLC_CRC_NONE)
+	if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE)
 		status &= ~BIT1;
 
 	if (framesize == 0 ||
@@ -4366,34 +4398,34 @@
 		goto check_again;
 	}
 
-	if (framesize < 2 || status & (BIT1+BIT0)) {
-		if (framesize < 2 || (status & BIT0))
-			info->icount.rxshort++;
-		else
-			info->icount.rxcrc++;
+	if (framesize < (2 + crc_size) || status & BIT0) {
+		info->icount.rxshort++;
 		framesize = 0;
+	} else if (status & BIT1) {
+		info->icount.rxcrc++;
+		if (!(info->params.crc_type & HDLC_CRC_RETURN_EX))
+			framesize = 0;
+	}
 
 #ifdef CONFIG_HDLC
-		{
-			struct net_device_stats *stats = hdlc_stats(info->netdev);
-			stats->rx_errors++;
-			stats->rx_frame_errors++;
-		}
-#endif
-	} else {
-		/* adjust frame size for CRC, if any */
-		if (info->params.crc_type == HDLC_CRC_16_CCITT)
-			framesize -= 2;
-		else if (info->params.crc_type == HDLC_CRC_32_CCITT)
-			framesize -= 4;
+	if (framesize == 0) {
+		struct net_device_stats *stats = hdlc_stats(info->netdev);
+		stats->rx_errors++;
+		stats->rx_frame_errors++;
 	}
+#endif
 
 	DBGBH(("%s rx frame status=%04X size=%d\n",
 		info->device_name, status, framesize));
 	DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
 
 	if (framesize) {
-		if (framesize > info->max_frame_size)
+		if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
+			framesize -= crc_size;
+			crc_size = 0;
+		}
+
+		if (framesize > info->max_frame_size + crc_size)
 			info->icount.rxlong++;
 		else {
 			/* copy dma buffer(s) to contiguous temp buffer */
@@ -4413,6 +4445,11 @@
 					i = 0;
 			}
 
+			if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
+				*p = (status & BIT1) ? RX_CRC_ERROR : RX_OK;
+				framesize++;
+			}
+
 #ifdef CONFIG_HDLC
 			if (info->netcount)
 				hdlcdev_rx(info,info->tmp_rbuf, framesize);
@@ -4671,13 +4708,13 @@
 static int adapter_test(struct slgt_info *info)
 {
 	DBGINFO(("testing %s\n", info->device_name));
-	if ((info->init_error = register_test(info)) < 0) {
+	if (register_test(info) < 0) {
 		printk("register test failure %s addr=%08X\n",
 			info->device_name, info->phys_reg_addr);
-	} else if ((info->init_error = irq_test(info)) < 0) {
+	} else if (irq_test(info) < 0) {
 		printk("IRQ test failure %s IRQ=%d\n",
 			info->device_name, info->irq_level);
-	} else if ((info->init_error = loopback_test(info)) < 0) {
+	} else if (loopback_test(info) < 0) {
 		printk("loopback test failure %s\n", info->device_name);
 	}
 	return info->init_error;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 8587401..21bf15a 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -988,7 +988,7 @@
 	if (sanity_check(info, tty->name, "write"))
 		goto cleanup;
 
-	if (!tty || !info->tx_buf)
+	if (!info->tx_buf)
 		goto cleanup;
 
 	if (info->params.mode == MGSL_MODE_HDLC) {
@@ -1067,7 +1067,7 @@
 	if (sanity_check(info, tty->name, "put_char"))
 		return;
 
-	if (!tty || !info->tx_buf)
+	if (!info->tx_buf)
 		return;
 
 	spin_lock_irqsave(&info->lock,flags);
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index f58ad7f..ef68d15 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -343,7 +343,7 @@
 
 	val = (unsigned char)tmp;
 	spin_lock_irqsave(&event_lock, flags);
-	SET_PORT_BITS(TLCLK_REG1, 0xef, val << 1);
+	SET_PORT_BITS(TLCLK_REG1, 0xdf, val << 1);
 	spin_unlock_irqrestore(&event_lock, flags);
 
 	return strnlen(buf, count);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 6c94879..714d95f 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -98,7 +98,22 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+#define MAX_NR_CON_DRIVER 16
 
+#define CON_DRIVER_FLAG_MODULE 1
+#define CON_DRIVER_FLAG_INIT 2
+
+struct con_driver {
+	const struct consw *con;
+	const char *desc;
+	struct class_device *class_dev;
+	int node;
+	int first;
+	int last;
+	int flag;
+};
+
+static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
 const struct consw *conswitchp;
 
 /* A bitmap for codes <32. A bit of 1 indicates that the code
@@ -2557,7 +2572,7 @@
 {
 	const char *display_desc = NULL;
 	struct vc_data *vc;
-	unsigned int currcons = 0;
+	unsigned int currcons = 0, i;
 
 	acquire_console_sem();
 
@@ -2569,6 +2584,22 @@
 		return 0;
 	}
 
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		struct con_driver *con_driver = &registered_con_driver[i];
+
+		if (con_driver->con == NULL) {
+			con_driver->con = conswitchp;
+			con_driver->desc = display_desc;
+			con_driver->flag = CON_DRIVER_FLAG_INIT;
+			con_driver->first = 0;
+			con_driver->last = MAX_NR_CONSOLES - 1;
+			break;
+		}
+	}
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		con_driver_map[i] = conswitchp;
+
 	init_timer(&console_timer);
 	console_timer.function = blank_screen_t;
 	if (blankinterval) {
@@ -2656,38 +2687,53 @@
 }
 
 #ifndef VT_SINGLE_DRIVER
+#include <linux/device.h>
 
-/*
- *	If we support more console drivers, this function is used
- *	when a driver wants to take over some existing consoles
- *	and become default driver for newly opened ones.
- */
+static struct class *vtconsole_class;
 
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
+static int bind_con_driver(const struct consw *csw, int first, int last,
+			   int deflt)
 {
-	int i, j = -1;
-	const char *desc;
-	struct module *owner;
+	struct module *owner = csw->owner;
+	const char *desc = NULL;
+	struct con_driver *con_driver;
+	int i, j = -1, k = -1, retval = -ENODEV;
 
-	owner = csw->owner;
 	if (!try_module_get(owner))
 		return -ENODEV;
 
 	acquire_console_sem();
 
-	desc = csw->con_startup();
-	if (!desc) {
-		release_console_sem();
-		module_put(owner);
-		return -ENODEV;
+	/* check if driver is registered */
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		con_driver = &registered_con_driver[i];
+
+		if (con_driver->con == csw) {
+			desc = con_driver->desc;
+			retval = 0;
+			break;
+		}
 	}
+
+	if (retval)
+		goto err;
+
+	if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
+		csw->con_startup();
+		con_driver->flag |= CON_DRIVER_FLAG_INIT;
+	}
+
 	if (deflt) {
 		if (conswitchp)
 			module_put(conswitchp->owner);
+
 		__module_get(owner);
 		conswitchp = csw;
 	}
 
+	first = max(first, con_driver->first);
+	last = min(last, con_driver->last);
+
 	for (i = first; i <= last; i++) {
 		int old_was_color;
 		struct vc_data *vc = vc_cons[i].d;
@@ -2701,15 +2747,17 @@
 			continue;
 
 		j = i;
-		if (CON_IS_VISIBLE(vc))
+
+		if (CON_IS_VISIBLE(vc)) {
+			k = i;
 			save_screen(vc);
+		}
+
 		old_was_color = vc->vc_can_do_color;
 		vc->vc_sw->con_deinit(vc);
 		vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-		vc->vc_visible_origin = vc->vc_origin;
-		vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
-		vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
 		visual_init(vc, i, 0);
+		set_origin(vc);
 		update_attr(vc);
 
 		/* If the console changed between mono <-> color, then
@@ -2718,37 +2766,507 @@
 		 */
 		if (old_was_color != vc->vc_can_do_color)
 			clear_buffer_attributes(vc);
-
-		if (CON_IS_VISIBLE(vc))
-			update_screen(vc);
 	}
+
 	printk("Console: switching ");
 	if (!deflt)
 		printk("consoles %d-%d ", first+1, last+1);
-	if (j >= 0)
+	if (j >= 0) {
+		struct vc_data *vc = vc_cons[j].d;
+
 		printk("to %s %s %dx%d\n",
-		       vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
-		       desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
-	else
+		       vc->vc_can_do_color ? "colour" : "mono",
+		       desc, vc->vc_cols, vc->vc_rows);
+
+		if (k >= 0) {
+			vc = vc_cons[k].d;
+			update_screen(vc);
+		}
+	} else
 		printk("to %s\n", desc);
 
+	retval = 0;
+err:
 	release_console_sem();
-
 	module_put(owner);
-	return 0;
+	return retval;
+};
+
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int con_is_graphics(const struct consw *csw, int first, int last)
+{
+	int i, retval = 0;
+
+	for (i = first; i <= last; i++) {
+		struct vc_data *vc = vc_cons[i].d;
+
+		if (vc && vc->vc_mode == KD_GRAPHICS) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
 }
 
-void give_up_console(const struct consw *csw)
+static int unbind_con_driver(const struct consw *csw, int first, int last,
+			     int deflt)
 {
-	int i;
+	struct module *owner = csw->owner;
+	const struct consw *defcsw = NULL;
+	struct con_driver *con_driver = NULL, *con_back = NULL;
+	int i, retval = -ENODEV;
 
-	for(i = 0; i < MAX_NR_CONSOLES; i++)
+	if (!try_module_get(owner))
+		return -ENODEV;
+
+	acquire_console_sem();
+
+	/* check if driver is registered and if it is unbindable */
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		con_driver = &registered_con_driver[i];
+
+		if (con_driver->con == csw &&
+		    con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+			retval = 0;
+			break;
+		}
+	}
+
+	if (retval) {
+		release_console_sem();
+		goto err;
+	}
+
+	retval = -ENODEV;
+
+	/* check if backup driver exists */
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		con_back = &registered_con_driver[i];
+
+		if (con_back->con &&
+		    !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+			defcsw = con_back->con;
+			retval = 0;
+			break;
+		}
+	}
+
+	if (retval) {
+		release_console_sem();
+		goto err;
+	}
+
+	if (!con_is_bound(csw)) {
+		release_console_sem();
+		goto err;
+	}
+
+	first = max(first, con_driver->first);
+	last = min(last, con_driver->last);
+
+	for (i = first; i <= last; i++) {
 		if (con_driver_map[i] == csw) {
 			module_put(csw->owner);
 			con_driver_map[i] = NULL;
 		}
+	}
+
+	if (!con_is_bound(defcsw)) {
+		const struct consw *defconsw = conswitchp;
+
+		defcsw->con_startup();
+		con_back->flag |= CON_DRIVER_FLAG_INIT;
+		/*
+		 * vgacon may change the default driver to point
+		 * to dummycon, we restore it here...
+		 */
+		conswitchp = defconsw;
+	}
+
+	if (!con_is_bound(csw))
+		con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
+
+	release_console_sem();
+	/* ignore return value, binding should not fail */
+	bind_con_driver(defcsw, first, last, deflt);
+err:
+	module_put(owner);
+	return retval;
+
 }
 
+static int vt_bind(struct con_driver *con)
+{
+	const struct consw *defcsw = NULL, *csw = NULL;
+	int i, more = 1, first = -1, last = -1, deflt = 0;
+
+ 	if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+	    con_is_graphics(con->con, con->first, con->last))
+		goto err;
+
+	csw = con->con;
+
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		struct con_driver *con = &registered_con_driver[i];
+
+		if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
+			defcsw = con->con;
+			break;
+		}
+	}
+
+	if (!defcsw)
+		goto err;
+
+	while (more) {
+		more = 0;
+
+		for (i = con->first; i <= con->last; i++) {
+			if (con_driver_map[i] == defcsw) {
+				if (first == -1)
+					first = i;
+				last = i;
+				more = 1;
+			} else if (first != -1)
+				break;
+		}
+
+		if (first == 0 && last == MAX_NR_CONSOLES -1)
+			deflt = 1;
+
+		if (first != -1)
+			bind_con_driver(csw, first, last, deflt);
+
+		first = -1;
+		last = -1;
+		deflt = 0;
+	}
+
+err:
+	return 0;
+}
+
+static int vt_unbind(struct con_driver *con)
+{
+	const struct consw *csw = NULL;
+	int i, more = 1, first = -1, last = -1, deflt = 0;
+
+ 	if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+	    con_is_graphics(con->con, con->first, con->last))
+		goto err;
+
+	csw = con->con;
+
+	while (more) {
+		more = 0;
+
+		for (i = con->first; i <= con->last; i++) {
+			if (con_driver_map[i] == csw) {
+				if (first == -1)
+					first = i;
+				last = i;
+				more = 1;
+			} else if (first != -1)
+				break;
+		}
+
+		if (first == 0 && last == MAX_NR_CONSOLES -1)
+			deflt = 1;
+
+		if (first != -1)
+			unbind_con_driver(csw, first, last, deflt);
+
+		first = -1;
+		last = -1;
+		deflt = 0;
+	}
+
+err:
+	return 0;
+}
+#else
+static inline int vt_bind(struct con_driver *con)
+{
+	return 0;
+}
+static inline int vt_unbind(struct con_driver *con)
+{
+	return 0;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static ssize_t store_bind(struct class_device *class_device,
+			  const char *buf, size_t count)
+{
+	struct con_driver *con = class_get_devdata(class_device);
+	int bind = simple_strtoul(buf, NULL, 0);
+
+	if (bind)
+		vt_bind(con);
+	else
+		vt_unbind(con);
+
+	return count;
+}
+
+static ssize_t show_bind(struct class_device *class_device, char *buf)
+{
+	struct con_driver *con = class_get_devdata(class_device);
+	int bind = con_is_bound(con->con);
+
+	return snprintf(buf, PAGE_SIZE, "%i\n", bind);
+}
+
+static ssize_t show_name(struct class_device *class_device, char *buf)
+{
+	struct con_driver *con = class_get_devdata(class_device);
+
+	return snprintf(buf, PAGE_SIZE, "%s %s\n",
+			(con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
+			 con->desc);
+
+}
+
+static struct class_device_attribute class_device_attrs[] = {
+	__ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
+	__ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static int vtconsole_init_class_device(struct con_driver *con)
+{
+	int i;
+
+	class_set_devdata(con->class_dev, con);
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_create_file(con->class_dev,
+					 &class_device_attrs[i]);
+
+	return 0;
+}
+
+static void vtconsole_deinit_class_device(struct con_driver *con)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_remove_file(con->class_dev,
+					 &class_device_attrs[i]);
+}
+
+/**
+ * con_is_bound - checks if driver is bound to the console
+ * @csw: console driver
+ *
+ * RETURNS: zero if unbound, nonzero if bound
+ *
+ * Drivers can call this and if zero, they should release
+ * all resources allocated on con_startup()
+ */
+int con_is_bound(const struct consw *csw)
+{
+	int i, bound = 0;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (con_driver_map[i] == csw) {
+			bound = 1;
+			break;
+		}
+	}
+
+	return bound;
+}
+EXPORT_SYMBOL(con_is_bound);
+
+/**
+ * register_con_driver - register console driver to console layer
+ * @csw: console driver
+ * @first: the first console to take over, minimum value is 0
+ * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
+ *
+ * DESCRIPTION: This function registers a console driver which can later
+ * bind to a range of consoles specified by @first and @last. It will
+ * also initialize the console driver by calling con_startup().
+ */
+int register_con_driver(const struct consw *csw, int first, int last)
+{
+	struct module *owner = csw->owner;
+	struct con_driver *con_driver;
+	const char *desc;
+	int i, retval = 0;
+
+	if (!try_module_get(owner))
+		return -ENODEV;
+
+	acquire_console_sem();
+
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		con_driver = &registered_con_driver[i];
+
+		/* already registered */
+		if (con_driver->con == csw)
+			retval = -EINVAL;
+	}
+
+	if (retval)
+		goto err;
+
+	desc = csw->con_startup();
+
+	if (!desc)
+		goto err;
+
+	retval = -EINVAL;
+
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		con_driver = &registered_con_driver[i];
+
+		if (con_driver->con == NULL) {
+			con_driver->con = csw;
+			con_driver->desc = desc;
+			con_driver->node = i;
+			con_driver->flag = CON_DRIVER_FLAG_MODULE |
+			                   CON_DRIVER_FLAG_INIT;
+			con_driver->first = first;
+			con_driver->last = last;
+			retval = 0;
+			break;
+		}
+	}
+
+	if (retval)
+		goto err;
+
+	con_driver->class_dev = class_device_create(vtconsole_class, NULL,
+						    MKDEV(0, con_driver->node),
+						    NULL, "vtcon%i",
+						    con_driver->node);
+
+	if (IS_ERR(con_driver->class_dev)) {
+		printk(KERN_WARNING "Unable to create class_device for %s; "
+		       "errno = %ld\n", con_driver->desc,
+		       PTR_ERR(con_driver->class_dev));
+		con_driver->class_dev = NULL;
+	} else {
+		vtconsole_init_class_device(con_driver);
+	}
+err:
+	release_console_sem();
+	module_put(owner);
+	return retval;
+}
+EXPORT_SYMBOL(register_con_driver);
+
+/**
+ * unregister_con_driver - unregister console driver from console layer
+ * @csw: console driver
+ *
+ * DESCRIPTION: All drivers that registers to the console layer must
+ * call this function upon exit, or if the console driver is in a state
+ * where it won't be able to handle console services, such as the
+ * framebuffer console without loaded framebuffer drivers.
+ *
+ * The driver must unbind first prior to unregistration.
+ */
+int unregister_con_driver(const struct consw *csw)
+{
+	int i, retval = -ENODEV;
+
+	acquire_console_sem();
+
+	/* cannot unregister a bound driver */
+	if (con_is_bound(csw))
+		goto err;
+
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		struct con_driver *con_driver = &registered_con_driver[i];
+
+		if (con_driver->con == csw &&
+		    con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+			vtconsole_deinit_class_device(con_driver);
+			class_device_destroy(vtconsole_class,
+					     MKDEV(0, con_driver->node));
+			con_driver->con = NULL;
+			con_driver->desc = NULL;
+			con_driver->class_dev = NULL;
+			con_driver->node = 0;
+			con_driver->flag = 0;
+			con_driver->first = 0;
+			con_driver->last = 0;
+			retval = 0;
+			break;
+		}
+	}
+err:
+	release_console_sem();
+	return retval;
+}
+EXPORT_SYMBOL(unregister_con_driver);
+
+/*
+ *	If we support more console drivers, this function is used
+ *	when a driver wants to take over some existing consoles
+ *	and become default driver for newly opened ones.
+ *
+ *      take_over_console is basically a register followed by unbind
+ */
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
+{
+	int err;
+
+	err = register_con_driver(csw, first, last);
+
+	if (!err)
+		bind_con_driver(csw, first, last, deflt);
+
+	return err;
+}
+
+/*
+ * give_up_console is a wrapper to unregister_con_driver. It will only
+ * work if driver is fully unbound.
+ */
+void give_up_console(const struct consw *csw)
+{
+	unregister_con_driver(csw);
+}
+
+static int __init vtconsole_class_init(void)
+{
+	int i;
+
+	vtconsole_class = class_create(THIS_MODULE, "vtconsole");
+	if (IS_ERR(vtconsole_class)) {
+		printk(KERN_WARNING "Unable to create vt console class; "
+		       "errno = %ld\n", PTR_ERR(vtconsole_class));
+		vtconsole_class = NULL;
+	}
+
+	/* Add system drivers to sysfs */
+	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+		struct con_driver *con = &registered_con_driver[i];
+
+		if (con->con && !con->class_dev) {
+			con->class_dev =
+				class_device_create(vtconsole_class, NULL,
+						    MKDEV(0, con->node), NULL,
+						    "vtcon%i", con->node);
+
+			if (IS_ERR(con->class_dev)) {
+				printk(KERN_WARNING "Unable to create "
+				       "class_device for %s; errno = %ld\n",
+				       con->desc, PTR_ERR(con->class_dev));
+				con->class_dev = NULL;
+			} else {
+				vtconsole_init_class_device(con);
+			}
+		}
+	}
+
+	return 0;
+}
+postcore_initcall(vtconsole_class_init);
+
 #endif
 
 /*
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
new file mode 100644
index 0000000..a522254
--- /dev/null
+++ b/drivers/clocksource/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_X86_CYCLONE_TIMER)	+= cyclone.o
+obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
+obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
new file mode 100644
index 0000000..7ad3be8
--- /dev/null
+++ b/drivers/clocksource/acpi_pm.c
@@ -0,0 +1,177 @@
+/*
+ * linux/drivers/clocksource/acpi_pm.c
+ *
+ * This file contains the ACPI PM based clocksource.
+ *
+ * This code was largely moved from the i386 timer_pm.c file
+ * which was (C) Dominik Brodowski <linux@brodo.de> 2003
+ * and contained the following comments:
+ *
+ * Driver to use the Power Management Timer (PMTMR) available in some
+ * southbridges as primary timing source for the Linux kernel.
+ *
+ * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
+ * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
+ *
+ * This file is licensed under the GPL v2.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/* Number of PMTMR ticks expected during calibration run */
+#define PMTMR_TICKS_PER_SEC 3579545
+
+/*
+ * The I/O port the PMTMR resides at.
+ * The location is detected during setup_arch(),
+ * in arch/i386/acpi/boot.c
+ */
+u32 pmtmr_ioport __read_mostly;
+
+#define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */
+
+static inline u32 read_pmtmr(void)
+{
+	/* mask the output to 24 bits */
+	return inl(pmtmr_ioport) & ACPI_PM_MASK;
+}
+
+static cycle_t acpi_pm_read_verified(void)
+{
+	u32 v1 = 0, v2 = 0, v3 = 0;
+
+	/*
+	 * It has been reported that because of various broken
+	 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock
+	 * source is not latched, you must read it multiple
+	 * times to ensure a safe value is read:
+	 */
+	do {
+		v1 = read_pmtmr();
+		v2 = read_pmtmr();
+		v3 = read_pmtmr();
+	} while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+			|| (v3 > v1 && v3 < v2));
+
+	return (cycle_t)v2;
+}
+
+static cycle_t acpi_pm_read(void)
+{
+	return (cycle_t)read_pmtmr();
+}
+
+static struct clocksource clocksource_acpi_pm = {
+	.name		= "acpi_pm",
+	.rating		= 200,
+	.read		= acpi_pm_read,
+	.mask		= (cycle_t)ACPI_PM_MASK,
+	.mult		= 0, /*to be caluclated*/
+	.shift		= 22,
+	.is_continuous	= 1,
+};
+
+
+#ifdef CONFIG_PCI
+static int acpi_pm_good;
+static int __init acpi_pm_good_setup(char *__str)
+{
+       acpi_pm_good = 1;
+       return 1;
+}
+__setup("acpi_pm_good", acpi_pm_good_setup);
+
+static inline void acpi_pm_need_workaround(void)
+{
+	clocksource_acpi_pm.read = acpi_pm_read_verified;
+	clocksource_acpi_pm.rating = 110;
+}
+
+/*
+ * PIIX4 Errata:
+ *
+ * The power management timer may return improper results when read.
+ * Although the timer value settles properly after incrementing,
+ * while incrementing there is a 3 ns window every 69.8 ns where the
+ * timer value is indeterminate (a 4.2% chance that the data will be
+ * incorrect when read). As a result, the ACPI free running count up
+ * timer specification is violated due to erroneous reads.
+ */
+static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
+{
+	u8 rev;
+
+	if (acpi_pm_good)
+		return;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+	/* the bug has been fixed in PIIX4M */
+	if (rev < 3) {
+		printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
+		       " Due to workarounds for a bug,\n"
+		       "* this clock source is slow. Consider trying"
+		       " other clock sources\n");
+
+		acpi_pm_need_workaround();
+	}
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+			acpi_pm_check_blacklist);
+
+static void __devinit acpi_pm_check_graylist(struct pci_dev *dev)
+{
+	if (acpi_pm_good)
+		return;
+
+	printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to"
+	       " workarounds for a bug,\n"
+	       "* this clock source is slow. If you are sure your timer"
+	       " does not have\n"
+	       "* this bug, please use \"acpi_pm_good\" to disable the"
+	       " workaround\n");
+
+	acpi_pm_need_workaround();
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
+			acpi_pm_check_graylist);
+#endif
+
+
+static int __init init_acpi_pm_clocksource(void)
+{
+	u32 value1, value2;
+	unsigned int i;
+
+	if (!pmtmr_ioport)
+		return -ENODEV;
+
+	clocksource_acpi_pm.mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC,
+						clocksource_acpi_pm.shift);
+
+	/* "verify" this timing source: */
+	value1 = read_pmtmr();
+	for (i = 0; i < 10000; i++) {
+		value2 = read_pmtmr();
+		if (value2 == value1)
+			continue;
+		if (value2 > value1)
+			goto pm_good;
+		if ((value2 < value1) && ((value2) < 0xFFF))
+			goto pm_good;
+		printk(KERN_INFO "PM-Timer had inconsistent results:"
+			" 0x%#x, 0x%#x - aborting.\n", value1, value2);
+		return -EINVAL;
+	}
+	printk(KERN_INFO "PM-Timer had no reasonable result:"
+			" 0x%#x - aborting.\n", value1);
+	return -ENODEV;
+
+pm_good:
+	return clocksource_register(&clocksource_acpi_pm);
+}
+
+module_init(init_acpi_pm_clocksource);
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
new file mode 100644
index 0000000..bf4d3d5
--- /dev/null
+++ b/drivers/clocksource/cyclone.c
@@ -0,0 +1,119 @@
+#include <linux/clocksource.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/timex.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include "mach_timer.h"
+
+#define CYCLONE_CBAR_ADDR	0xFEB00CD0	/* base address ptr */
+#define CYCLONE_PMCC_OFFSET	0x51A0		/* offset to control register */
+#define CYCLONE_MPCS_OFFSET	0x51A8		/* offset to select register */
+#define CYCLONE_MPMC_OFFSET	0x51D0		/* offset to count register */
+#define CYCLONE_TIMER_FREQ	99780000	/* 100Mhz, but not really */
+#define CYCLONE_TIMER_MASK	CLOCKSOURCE_MASK(32) /* 32 bit mask */
+
+int use_cyclone = 0;
+static void __iomem *cyclone_ptr;
+
+static cycle_t read_cyclone(void)
+{
+	return (cycle_t)readl(cyclone_ptr);
+}
+
+static struct clocksource clocksource_cyclone = {
+	.name		= "cyclone",
+	.rating		= 250,
+	.read		= read_cyclone,
+	.mask		= CYCLONE_TIMER_MASK,
+	.mult		= 10,
+	.shift		= 0,
+	.is_continuous	= 1,
+};
+
+static int __init init_cyclone_clocksource(void)
+{
+	unsigned long base;	/* saved value from CBAR */
+	unsigned long offset;
+	u32 __iomem* volatile cyclone_timer;	/* Cyclone MPMC0 register */
+	u32 __iomem* reg;
+	int i;
+
+	/* make sure we're on a summit box: */
+	if (!use_cyclone)
+		return -ENODEV;
+
+	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+	/* find base address: */
+	offset = CYCLONE_CBAR_ADDR;
+	reg = ioremap_nocache(offset, sizeof(reg));
+	if (!reg) {
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		return -ENODEV;
+	}
+	/* even on 64bit systems, this is only 32bits: */
+	base = readl(reg);
+	if (!base) {
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		return -ENODEV;
+	}
+	iounmap(reg);
+
+	/* setup PMCC: */
+	offset = base + CYCLONE_PMCC_OFFSET;
+	reg = ioremap_nocache(offset, sizeof(reg));
+	if (!reg) {
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		return -ENODEV;
+	}
+	writel(0x00000001,reg);
+	iounmap(reg);
+
+	/* setup MPCS: */
+	offset = base + CYCLONE_MPCS_OFFSET;
+	reg = ioremap_nocache(offset, sizeof(reg));
+	if (!reg) {
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		return -ENODEV;
+	}
+	writel(0x00000001,reg);
+	iounmap(reg);
+
+	/* map in cyclone_timer: */
+	offset = base + CYCLONE_MPMC_OFFSET;
+	cyclone_timer = ioremap_nocache(offset, sizeof(u64));
+	if (!cyclone_timer) {
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		return -ENODEV;
+	}
+
+	/* quick test to make sure its ticking: */
+	for (i = 0; i < 3; i++){
+		u32 old = readl(cyclone_timer);
+		int stall = 100;
+
+		while (stall--)
+			barrier();
+
+		if (readl(cyclone_timer) == old) {
+			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			iounmap(cyclone_timer);
+			cyclone_timer = NULL;
+			return -ENODEV;
+		}
+	}
+	cyclone_ptr = cyclone_timer;
+
+	/* sort out mult/shift values: */
+	clocksource_cyclone.shift = 22;
+	clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
+						clocksource_cyclone.shift);
+
+	return clocksource_register(&clocksource_cyclone);
+}
+
+module_init(init_cyclone_clocksource);
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
new file mode 100644
index 0000000..d418b82
--- /dev/null
+++ b/drivers/clocksource/scx200_hrt.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2006 Jim Cromie
+ *
+ * This is a clocksource driver for the Geode SCx200's 1 or 27 MHz
+ * high-resolution timer.  The Geode SC-1100 (at least) has a buggy
+ * time stamp counter (TSC), which loses time unless 'idle=poll' is
+ * given as a boot-arg. In its absence, the Generic Timekeeping code
+ * will detect and de-rate the bad TSC, allowing this timer to take
+ * over timekeeping duties.
+ *
+ * Based on work by John Stultz, and Ted Phelps (in a 2.6.12-rc6 patch)
+ *
+ * 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/clocksource.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200_hrt"
+
+static int mhz27;
+module_param(mhz27, int, 0);	/* load time only */
+MODULE_PARM_DESC(mhz27, "count at 27.0 MHz (default is 1.0 MHz)");
+
+static int ppm;
+module_param(ppm, int, 0);	/* load time only */
+MODULE_PARM_DESC(ppm, "+-adjust to actual XO freq (ppm)");
+
+/* HiRes Timer configuration register address */
+#define SCx200_TMCNFG_OFFSET (SCx200_TIMER_OFFSET + 5)
+
+/* and config settings */
+#define HR_TMEN (1 << 0)	/* timer interrupt enable */
+#define HR_TMCLKSEL (1 << 1)	/* 1|0 counts at 27|1 MHz */
+#define HR_TM27MPD (1 << 2)	/* 1 turns off input clock (power-down) */
+
+/* The base timer frequency, * 27 if selected */
+#define HRT_FREQ   1000000
+
+static cycle_t read_hrt(void)
+{
+	/* Read the timer value */
+	return (cycle_t) inl(scx200_cb_base + SCx200_TIMER_OFFSET);
+}
+
+#define HRT_SHIFT_1	22
+#define HRT_SHIFT_27	26
+
+static struct clocksource cs_hrt = {
+	.name		= "scx200_hrt",
+	.rating		= 250,
+	.read		= read_hrt,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.is_continuous	= 1,
+	/* mult, shift are set based on mhz27 flag */
+};
+
+static int __init init_hrt_clocksource(void)
+{
+	/* Make sure scx200 has initializedd the configuration block */
+	if (!scx200_cb_present())
+		return -ENODEV;
+
+	/* Reserve the timer's ISA io-region for ourselves */
+	if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET,
+			    SCx200_TIMER_SIZE,
+			    "NatSemi SCx200 High-Resolution Timer")) {
+		printk(KERN_WARNING NAME ": unable to lock timer region\n");
+		return -ENODEV;
+	}
+
+	/* write timer config */
+	outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0,
+	     scx200_cb_base + SCx200_TMCNFG_OFFSET);
+
+	if (mhz27) {
+		cs_hrt.shift = HRT_SHIFT_27;
+		cs_hrt.mult = clocksource_hz2mult((HRT_FREQ + ppm) * 27,
+						  cs_hrt.shift);
+	} else {
+		cs_hrt.shift = HRT_SHIFT_1;
+		cs_hrt.mult = clocksource_hz2mult(HRT_FREQ + ppm,
+						  cs_hrt.shift);
+	}
+	printk(KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n",
+		mhz27 ? "27":"1", ppm);
+
+	return clocksource_register(&cs_hrt);
+}
+
+module_init(init_hrt_clocksource);
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("clocksource on SCx200 HiRes Timer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 5158a9d..17ee684 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -60,15 +60,14 @@
 #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
 
 struct aes_ctx {
-	uint32_t e_data[AES_EXTENDED_KEY_SIZE];
-	uint32_t d_data[AES_EXTENDED_KEY_SIZE];
 	struct {
 		struct cword encrypt;
 		struct cword decrypt;
 	} cword;
-	uint32_t *E;
-	uint32_t *D;
+	u32 *D;
 	int key_length;
+	u32 E[AES_EXTENDED_KEY_SIZE];
+	u32 d_data[AES_EXTENDED_KEY_SIZE];
 };
 
 /* ====== Key management routines ====== */
@@ -282,19 +281,20 @@
 	return 0;
 }
 
-static inline struct aes_ctx *aes_ctx(void *ctx)
+static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
 {
+	unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
 	unsigned long align = PADLOCK_ALIGNMENT;
 
 	if (align <= crypto_tfm_ctx_alignment())
 		align = 1;
-	return (struct aes_ctx *)ALIGN((unsigned long)ctx, align);
+	return (struct aes_ctx *)ALIGN(addr, align);
 }
 
-static int
-aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags)
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+		       unsigned int key_len, u32 *flags)
 {
-	struct aes_ctx *ctx = aes_ctx(ctx_arg);
+	struct aes_ctx *ctx = aes_ctx(tfm);
 	const __le32 *key = (const __le32 *)in_key;
 	uint32_t i, t, u, v, w;
 	uint32_t P[AES_EXTENDED_KEY_SIZE];
@@ -312,8 +312,7 @@
 	 * itself we must supply the plain key for both encryption
 	 * and decryption.
 	 */
-	ctx->E = ctx->e_data;
-	ctx->D = ctx->e_data;
+	ctx->D = ctx->E;
 
 	E_KEY[0] = le32_to_cpu(key[0]);
 	E_KEY[1] = le32_to_cpu(key[1]);
@@ -414,24 +413,22 @@
 	return iv;
 }
 
-static void
-aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct aes_ctx *ctx = aes_ctx(ctx_arg);
+	struct aes_ctx *ctx = aes_ctx(tfm);
 	padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1);
 }
 
-static void
-aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
-	struct aes_ctx *ctx = aes_ctx(ctx_arg);
+	struct aes_ctx *ctx = aes_ctx(tfm);
 	padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
 }
 
 static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
-	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	struct aes_ctx *ctx = aes_ctx(desc->tfm);
 	padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt,
 			   nbytes / AES_BLOCK_SIZE);
 	return nbytes & ~(AES_BLOCK_SIZE - 1);
@@ -440,7 +437,7 @@
 static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
-	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	struct aes_ctx *ctx = aes_ctx(desc->tfm);
 	padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt,
 			   nbytes / AES_BLOCK_SIZE);
 	return nbytes & ~(AES_BLOCK_SIZE - 1);
@@ -449,7 +446,7 @@
 static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
-	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	struct aes_ctx *ctx = aes_ctx(desc->tfm);
 	u8 *iv;
 
 	iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info,
@@ -462,7 +459,7 @@
 static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
-	struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+	struct aes_ctx *ctx = aes_ctx(desc->tfm);
 	padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt,
 			   nbytes / AES_BLOCK_SIZE);
 	return nbytes & ~(AES_BLOCK_SIZE - 1);
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 0fdf7fb..2801d14 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -824,10 +824,9 @@
 {
 	/* it's currently unsafe to unload this module */
 	/* if forced, worst case is that rmmod hangs */
-	if (THIS_MODULE != NULL)
-		THIS_MODULE->unsafe = 1;
+	__unsafe(THIS_MODULE);
 
-	return pci_module_init(&ioat_pci_drv);
+	pci_module_init(&ioat_pci_drv);
 }
 
 module_init(ioat_init_module);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1e371a5..731c3d5 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -6,8 +6,7 @@
 menu "Firmware Drivers"
 
 config EDD
-	tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
+	tristate "BIOS Enhanced Disk Drive calls determine boot disk"
 	depends on !IA64
 	help
 	  Say Y or M here if you want to enable BIOS Enhanced Disk Drive
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 948bd7e..b9e3886 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -255,10 +255,15 @@
 /**
  *	dmi_check_system - check system DMI data
  *	@list: array of dmi_system_id structures to match against
+ *		All non-null elements of the list must match
+ *		their slot's (field index's) data (i.e., each
+ *		list string must be a substring of the specified
+ *		DMI slot's string data) to be considered a
+ *		successful match.
  *
  *	Walk the blacklist table running matching functions until someone
  *	returns non zero or we hit the end. Callback function is called for
- *	each successfull match. Returns the number of matches.
+ *	each successful match. Returns the number of matches.
  */
 int dmi_check_system(struct dmi_system_id *list)
 {
@@ -287,7 +292,7 @@
 
 /**
  *	dmi_get_system_info - return DMI data value
- *	@field: data index (see enum dmi_filed)
+ *	@field: data index (see enum dmi_field)
  *
  *	Returns one DMI data value, can be used to perform
  *	complex DMI data checks.
@@ -301,13 +306,13 @@
 /**
  *	dmi_find_device - find onboard device by type/name
  *	@type: device type or %DMI_DEV_TYPE_ANY to match all device types
- *	@desc: device name string or %NULL to match all
+ *	@name: device name string or %NULL to match all
  *	@from: previous device found in search, or %NULL for new search.
  *
  *	Iterates through the list of known onboard devices. If a device is
  *	found with a matching @vendor and @device, a pointer to its device
  *	structure is returned.  Otherwise, %NULL is returned.
- *	A new search is initiated by passing %NULL to the @from argument.
+ *	A new search is initiated by passing %NULL as the @from argument.
  *	If @from is not %NULL, searches continue from next device.
  */
 struct dmi_device * dmi_find_device(int type, const char *name,
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 65b2709..facc1cc 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -341,7 +341,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
 				size_t count, int nr)
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 94be3d7..a6ce7ab 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -358,7 +358,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
 	size_t count, int nr)
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index f72120d..b4ccdfc 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -253,7 +253,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
 	size_t count, int nr)
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index e229daf..e6c1b63 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -421,7 +421,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan clock divider.  This follows the principle
-   of least suprise; the user doesn't expect the fan minimum to change just
+   of least surprise; the user doesn't expect the fan minimum to change just
    because the divider changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
 		size_t count, int nr)
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 6f3fda7..063f71c 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -380,7 +380,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
 	size_t count, int nr)
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 7732aec..825e8f7 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -207,7 +207,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan clock divider.  This follows the principle
-   of least suprise; the user doesn't expect the fan minimum to change just
+   of least surprise; the user doesn't expect the fan minimum to change just
    because the divider changed. */
 static ssize_t set_fan_div(struct device *dev, const char *buf,
 		size_t count, int nr)
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 71fb7f1..79368d5 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -781,7 +781,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t
 store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index e4c7003..7be469e 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -630,7 +630,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t
 store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 4ef884c..e407c74 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -463,7 +463,7 @@
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
-   least suprise; the user doesn't expect the fan minimum to change just
+   least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t
 store_fan_div(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 6de3cd3..99fa424 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -395,7 +395,8 @@
 			 * we cannot reliably check if drive can auto-close
 			 */
 			if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
-				log = 0;
+				break;
+			log = 1;
 			break;
 		case UNIT_ATTENTION:
 			/*
@@ -417,6 +418,11 @@
 			      struct request *failed_command,
 			      struct request_sense *sense)
 {
+	unsigned long sector;
+	unsigned long bio_sectors;
+	unsigned long valid;
+	struct cdrom_info *info = drive->driver_data;
+
 	if (!cdrom_log_sense(drive, failed_command, sense))
 		return;
 
@@ -429,6 +435,37 @@
 		if (sense->sense_key == 0x05 && sense->asc == 0x24)
 			return;
 
+ 	if (sense->error_code == 0x70) {	/* Current Error */
+ 		switch(sense->sense_key) {
+		case MEDIUM_ERROR:
+		case VOLUME_OVERFLOW:
+		case ILLEGAL_REQUEST:
+			if (!sense->valid)
+				break;
+			if (failed_command == NULL ||
+					!blk_fs_request(failed_command))
+				break;
+			sector = (sense->information[0] << 24) |
+				 (sense->information[1] << 16) |
+				 (sense->information[2] <<  8) |
+				 (sense->information[3]);
+
+			bio_sectors = bio_sectors(failed_command->bio);
+			if (bio_sectors < 4)
+				bio_sectors = 4;
+			if (drive->queue->hardsect_size == 2048)
+				sector <<= 2;	/* Device sector size is 2K */
+			sector &= ~(bio_sectors -1);
+			valid = (sector - failed_command->sector) << 9;
+
+			if (valid < 0)
+				valid = 0;
+			if (sector < get_capacity(info->disk) &&
+				drive->probed_capacity - sector < 4 * 75) {
+				set_capacity(info->disk, sector);
+			}
+ 		}
+ 	}
 #if VERBOSE_IDE_CD_ERRORS
 	{
 		int i;
@@ -609,17 +646,23 @@
 				sense = failed->sense;
 				failed->sense_len = rq->sense_len;
 			}
-
+			cdrom_analyze_sense_data(drive, failed, sense);
 			/*
 			 * now end failed request
 			 */
-			spin_lock_irqsave(&ide_lock, flags);
-			end_that_request_chunk(failed, 0, failed->data_len);
-			end_that_request_last(failed, 0);
-			spin_unlock_irqrestore(&ide_lock, flags);
-		}
-
-		cdrom_analyze_sense_data(drive, failed, sense);
+			if (blk_fs_request(failed)) {
+				if (ide_end_dequeued_request(drive, failed, 0,
+						failed->hard_nr_sectors))
+					BUG();
+			} else {
+				spin_lock_irqsave(&ide_lock, flags);
+				end_that_request_chunk(failed, 0,
+							failed->data_len);
+				end_that_request_last(failed, 0);
+				spin_unlock_irqrestore(&ide_lock, flags);
+			}
+		} else
+			cdrom_analyze_sense_data(drive, NULL, sense);
 	}
 
 	if (!rq->current_nr_sectors && blk_fs_request(rq))
@@ -633,6 +676,13 @@
 	ide_end_request(drive, uptodate, nsectors);
 }
 
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
+{
+	if (stat & 0x80)
+		return;
+	ide_dump_status(drive, msg, stat);
+}
+
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
@@ -761,16 +811,16 @@
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
-			ide_dump_status (drive, "command error", stat);
+			ide_dump_status_no_sense (drive, "command error", stat);
 			do_end_request = 1;
 		} else if (sense_key == MEDIUM_ERROR) {
 			/* No point in re-trying a zillion times on a bad 
 			 * sector...  If we got here the error is not correctable */
-			ide_dump_status (drive, "media error (bad sector)", stat);
+			ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
 			do_end_request = 1;
 		} else if (sense_key == BLANK_CHECK) {
 			/* Disk appears blank ?? */
-			ide_dump_status (drive, "media error (blank)", stat);
+			ide_dump_status_no_sense (drive, "media error (blank)", stat);
 			do_end_request = 1;
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
@@ -782,13 +832,27 @@
 			do_end_request = 1;
 		}
 
-		if (do_end_request)
-			cdrom_end_request(drive, 0);
+		/* End a request through request sense analysis when we have
+		   sense data. We need this in order to perform end of media
+		   processing */
 
-		/* If we got a CHECK_CONDITION status,
-		   queue a request sense command. */
-		if ((stat & ERR_STAT) != 0)
-			cdrom_queue_request_sense(drive, NULL, NULL);
+		if (do_end_request) {
+			if (stat & ERR_STAT) {
+				unsigned long flags;
+				spin_lock_irqsave(&ide_lock, flags);
+				blkdev_dequeue_request(rq);
+				HWGROUP(drive)->rq = NULL;
+				spin_unlock_irqrestore(&ide_lock, flags);
+
+				cdrom_queue_request_sense(drive, rq->sense, rq);
+			} else
+				cdrom_end_request(drive, 0);
+		} else {
+			/* If we got a CHECK_CONDITION status,
+			   queue a request sense command. */
+			if (stat & ERR_STAT)
+				cdrom_queue_request_sense(drive, NULL, NULL);
+		}
 	} else {
 		blk_dump_rq_flags(rq, "ide-cd: bad rq");
 		cdrom_end_request(drive, 0);
@@ -1491,8 +1555,7 @@
 }
 
 
-static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
 {
 	struct request_sense sense;
 	int retries = 10;
@@ -2220,6 +2283,9 @@
 		toc->capacity = 0x1fffff;
 
 	set_capacity(info->disk, toc->capacity * sectors_per_frame);
+	/* Save a private copy of te TOC capacity for error handling */
+	drive->probed_capacity = toc->capacity * sectors_per_frame;
+
 	blk_queue_hardsect_size(drive->queue,
 				sectors_per_frame << SECTOR_BITS);
 
@@ -2342,6 +2408,7 @@
 	if (!stat && (last_written > toc->capacity)) {
 		toc->capacity = last_written;
 		set_capacity(info->disk, toc->capacity * sectors_per_frame);
+		drive->probed_capacity = toc->capacity * sectors_per_frame;
 	}
 
 	/* Remember that we've read this stuff. */
@@ -2698,14 +2765,11 @@
 	 * any other way to detect this...
 	 */
 	if (sense.sense_key == NOT_READY) {
-		if (sense.asc == 0x3a) {
-			if (sense.ascq == 1)
-				return CDS_NO_DISC;
-			else if (sense.ascq == 0 || sense.ascq == 2)
-				return CDS_TRAY_OPEN;
-		}
+		if (sense.asc == 0x3a && sense.ascq == 1)
+			return CDS_NO_DISC;
+		else
+			return CDS_TRAY_OPEN;
 	}
-
 	return CDS_DRIVE_NOT_READY;
 }
 
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index a5017de..f033d73 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -37,7 +37,7 @@
  * Version 1.15		convert all calls to ide_raw_taskfile
  *				since args will return register content.
  * Version 1.16		added suspend-resume-checkpower
- * Version 1.17		do flush on standy, do flush on ATA < ATA6
+ * Version 1.17		do flush on standby, do flush on ATA < ATA6
  *			fix wcache setup.
  */
 
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index a1179e9..4656587 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -1284,7 +1284,7 @@
 
 	debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
 			rq->rq_status,
-			rq->rq_disk ? rq->rq_disk->disk_name ? "?",
+			rq->rq_disk ? rq->rq_disk->disk_name : "?",
 			rq->flags, rq->errors);
 	debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
 			"current_nr_sectors: %d\n", (long)rq->sector,
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 4f2f138..935cb25 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -223,6 +223,63 @@
 }
 
 /**
+ *	ide_end_dequeued_request	-	complete an IDE I/O
+ *	@drive: IDE device for the I/O
+ *	@uptodate:
+ *	@nr_sectors: number of sectors completed
+ *
+ *	Complete an I/O that is no longer on the request queue. This
+ *	typically occurs when we pull the request and issue a REQUEST_SENSE.
+ *	We must still finish the old request but we must not tamper with the
+ *	queue in the meantime.
+ *
+ *	NOTE: This path does not handle barrier, but barrier is not supported
+ *	on ide-cd anyway.
+ */
+
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+			     int uptodate, int nr_sectors)
+{
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	BUG_ON(!(rq->flags & REQ_STARTED));
+
+	/*
+	 * if failfast is set on a request, override number of sectors and
+	 * complete the whole request right now
+	 */
+	if (blk_noretry_request(rq) && end_io_error(uptodate))
+		nr_sectors = rq->hard_nr_sectors;
+
+	if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+		rq->errors = -EIO;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+		add_disk_randomness(rq->rq_disk);
+		if (blk_rq_tagged(rq))
+			blk_queue_end_tag(drive->queue, rq);
+		end_that_request_last(rq, uptodate);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
+
+
+/**
  *	ide_complete_pm_request - end the current Power Management request
  *	@drive: target drive
  *	@rq: request
@@ -902,7 +959,7 @@
 			printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
 		SELECT_DRIVE(drive);
 		HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
-		rc = ide_wait_not_busy(HWIF(drive), 10000);
+		rc = ide_wait_not_busy(HWIF(drive), 100000);
 		if (rc)
 			printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
 	}
@@ -1608,7 +1665,7 @@
  *	Initialize a request before we fill it in and send it down to
  *	ide_do_drive_cmd. Commands must be set up by this function. Right
  *	now it doesn't do a lot, but if that changes abusers will have a
- *	nasty suprise.
+ *	nasty surprise.
  */
 
 void ide_init_drive_cmd (struct request *rq)
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 16a1431..7ddb118 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -485,7 +485,7 @@
 	unsigned long flags;
 	u8 err = 0;
 
-	local_irq_set(flags);
+	local_irq_save(flags);
 	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
 	if (stat & BUSY_STAT)
 		printk("Busy ");
@@ -567,7 +567,7 @@
 
 	status.all = stat;
 	error.all = 0;
-	local_irq_set(flags);
+	local_irq_save(flags);
 	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
 	if (status.b.bsy)
 		printk("Busy ");
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index f04791a..09f3a7d 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2646,21 +2646,23 @@
 	return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
 {
 	struct idetape_bh *bh = tape->bh;
 	int count;
+	int ret = 0;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
 			printk(KERN_ERR "ide-tape: bh == NULL in "
 				"idetape_copy_stage_from_user\n");
-			return;
+			return 1;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
-		copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
+		if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+			ret = 1;
 		n -= count;
 		atomic_add(count, &bh->b_count);
 		buf += count;
@@ -2671,23 +2673,26 @@
 		}
 	}
 	tape->bh = bh;
+	return ret;
 }
 
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
 {
 	struct idetape_bh *bh = tape->bh;
 	int count;
+	int ret = 0;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
 			printk(KERN_ERR "ide-tape: bh == NULL in "
 				"idetape_copy_stage_to_user\n");
-			return;
+			return 1;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = min(tape->b_count, n);
-		copy_to_user(buf, tape->b_data, count);
+		if  (copy_to_user(buf, tape->b_data, count))
+			ret = 1;
 		n -= count;
 		tape->b_data += count;
 		tape->b_count -= count;
@@ -2700,6 +2705,7 @@
 			}
 		}
 	}
+	return ret;
 }
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
@@ -3719,6 +3725,7 @@
 	struct ide_tape_obj *tape = ide_tape_f(file);
 	ide_drive_t *drive = tape->drive;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
+	ssize_t ret = 0;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
@@ -3737,7 +3744,8 @@
 		return (0);
 	if (tape->merge_stage_size) {
 		actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
-		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
+		if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+			ret = -EFAULT;
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
 		count -= actually_read;
@@ -3746,7 +3754,8 @@
 		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
+		if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+			ret = -EFAULT;
 		buf += bytes_read;
 		count -= bytes_read;
 		actually_read += bytes_read;
@@ -3756,7 +3765,8 @@
 		if (bytes_read <= 0)
 			goto finish;
 		temp = min((unsigned long)count, (unsigned long)bytes_read);
-		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
+		if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+			ret = -EFAULT;
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
 	}
@@ -3769,7 +3779,8 @@
 		idetape_space_over_filemarks(drive, MTFSF, 1);
 		return 0;
 	}
-	return actually_read;
+
+	return (ret) ? ret : actually_read;
 }
 
 static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
@@ -3777,7 +3788,8 @@
 {
 	struct ide_tape_obj *tape = ide_tape_f(file);
 	ide_drive_t *drive = tape->drive;
-	ssize_t retval, actually_written = 0;
+	ssize_t actually_written = 0;
+	ssize_t ret = 0;
 
 	/* The drive is write protected. */
 	if (tape->write_prot)
@@ -3813,7 +3825,7 @@
 		 *	some drives (Seagate STT3401A) will return an error.
 		 */
 		if (drive->dsc_overlap) {
-			retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+			ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
 			if (retval < 0) {
 				__idetape_kfree_stage(tape->merge_stage);
 				tape->merge_stage = NULL;
@@ -3834,12 +3846,14 @@
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
-		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
+		if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+				ret = -EFAULT;
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
 		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
+			ssize_t retval;
 			tape->merge_stage_size = 0;
 			retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 			if (retval <= 0)
@@ -3847,7 +3861,9 @@
 		}
 	}
 	while (count >= tape->stage_size) {
-		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
+		ssize_t retval;
+		if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+			ret = -EFAULT;
 		buf += tape->stage_size;
 		count -= tape->stage_size;
 		retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
@@ -3857,10 +3873,11 @@
 	}
 	if (count) {
 		actually_written += count;
-		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
+		if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+			ret = -EFAULT;
 		tape->merge_stage_size += count;
 	}
-	return (actually_written);
+	return (ret) ? ret : actually_written;
 }
 
 static int idetape_write_filemark (ide_drive_t *drive)
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
index 2fcfac6..c0864b1 100644
--- a/drivers/ide/ide-timing.h
+++ b/drivers/ide/ide-timing.h
@@ -220,6 +220,12 @@
 		return -EINVAL;
 
 /*
+ * Copy the timing from the table.
+ */
+
+	*t = *s;
+
+/*
  * If the drive is an EIDE drive, it can tell us it needs extended
  * PIO/MWDMA cycle timing.
  */
@@ -247,7 +253,7 @@
  * Convert the timing to bus clock counts.
  */
 
-	ide_timing_quantize(s, t, T, UT);
+	ide_timing_quantize(t, t, T, UT);
 
 /*
  * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 7ce5bf7..22d1754 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -370,7 +370,6 @@
 	if (!(speed)) {
 		/* restore original pci-config space */
 		pci_write_config_dword(dev, drive_pci, drive_conf);
-		hwif->tuneproc(drive, 5);
 		return 0;
 	}
 
@@ -415,8 +414,6 @@
 	if (drive->addressing == 1) {
 		struct request *rq	= HWGROUP(drive)->rq;
 		ide_hwif_t *hwif	= HWIF(drive);
-//		struct pci_dev *dev	= hwif->pci_dev;
-//		unsgned long high_16	= pci_resource_start(dev, 4);
 		unsigned long high_16   = hwif->dma_master;
 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
 		u32 word_count	= 0;
@@ -436,7 +433,6 @@
 {
 	if (drive->addressing == 1) {
 		ide_hwif_t *hwif	= HWIF(drive);
-//		unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
 		unsigned long high_16	= hwif->dma_master;
 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
 		u8 clock		= 0;
@@ -453,8 +449,6 @@
 static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-//	struct pci_dev *dev	= hwif->pci_dev;
-//	unsigned long high_16	= pci_resource_start(dev, 4);
 	unsigned long high_16	= hwif->dma_master;
 	u8 dma_stat		= hwif->INB(hwif->dma_status);
 	u8 sc1d			= hwif->INB((high_16 + 0x001d));
@@ -492,12 +486,7 @@
 
 static void pdc202xx_reset_host (ide_hwif_t *hwif)
 {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
 	unsigned long high_16	= hwif->dma_master;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
 
 	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
@@ -550,31 +539,6 @@
 #endif
 }
 
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-static int pdc202xx_tristate (ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
-	unsigned long high_16	= hwif->dma_master;
-	u8 sc1f			= hwif->INB(high_16|0x001f);
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	if (state) {
-		hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
-	} else {
-		hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
-	}
-	return 0;
-}
-
 static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name)
 {
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
@@ -624,10 +588,8 @@
 	hwif->tuneproc  = &config_chipset_for_pio;
 	hwif->quirkproc = &pdc202xx_quirkproc;
 
-	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
-		hwif->busproc   = &pdc202xx_tristate;
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
 		hwif->resetproc = &pdc202xx_reset;
-	}
 
 	hwif->speedproc = &pdc202xx_tune_chipset;
 
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index e9b83e1..7fac6f5 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -222,6 +222,8 @@
 	unsigned long flags;
 	u16 master_data;
 	u8 slave_data;
+	static DEFINE_SPINLOCK(tune_lock);
+
 				 /* ISP  RTC */
 	u8 timings[][2]	= { { 0, 0 },
 			    { 0, 0 },
@@ -230,7 +232,13 @@
 			    { 2, 3 }, };
 
 	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	spin_lock_irqsave(&ide_lock, flags);
+
+	/*
+	 * Master vs slave is synchronized above us but the slave register is
+	 * shared by the two hwifs so the corner case of two slave timeouts in
+	 * parallel must be locked.
+	 */
+	spin_lock_irqsave(&tune_lock, flags);
 	pci_read_config_word(dev, master_port, &master_data);
 	if (is_slave) {
 		master_data = master_data | 0x4000;
@@ -250,7 +258,7 @@
 	pci_write_config_word(dev, master_port, master_data);
 	if (is_slave)
 		pci_write_config_byte(dev, slave_port, slave_data);
-	spin_unlock_irqrestore(&ide_lock, flags);
+	spin_unlock_irqrestore(&tune_lock, flags);
 }
 
 /**
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 79b81be..1867375 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -4,7 +4,7 @@
 
 config IEEE1394
 	tristate "IEEE 1394 (FireWire) support"
-	depends on (PCI || BROKEN) && (BROKEN || !FRV)
+	depends on PCI || BROKEN
 	select NET
 	help
 	  IEEE 1394 describes a high performance serial bus, which is also
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 5bda159..2d5b57b 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1074,8 +1074,7 @@
 
 	/* Move list entry to beginnig of list so that oldest partial
 	 * datagrams percolate to the end of the list */
-	list_del(lh);
-	list_add(lh, pdgl);
+	list_move(lh, pdgl);
 
 	return 0;
 }
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 2d47b11..ad49c04 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -103,7 +103,7 @@
  * driver specific parts, enable the controller and make it available
  * to the general subsystem using hpsb_add_host().
  *
- * Return Value: a pointer to the &hpsb_host if succesful, %NULL if
+ * Return Value: a pointer to the &hpsb_host if successful, %NULL if
  * no memory was available.
  */
 static DEFINE_MUTEX(host_num_alloc);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index e7b55e8..0ecbf33 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -139,7 +139,7 @@
 
 /*
  * Hand over received selfid packet to the core.  Complement check (second
- * quadlet is complement of first) is expected to be done and succesful.
+ * quadlet is complement of first) is expected to be done and successful.
  */
 void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
 
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 948f1b8..50c71e1 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -8,6 +8,7 @@
  * directory of the kernel sources for details.
  */
 
+#include <linux/bitmap.h>
 #include <linux/kernel.h>
 #include <linux/config.h>
 #include <linux/list.h>
@@ -334,10 +335,12 @@
 static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
 
 
+/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
+ * here, therefore displayed values may be occasionally wrong. */
 static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct node_entry *ne = container_of(dev, struct node_entry, device);
-	return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);
+	return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
 }
 static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
 
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 20ce539..571ea68 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -132,8 +132,7 @@
 static void __queue_complete_req(struct pending_request *req)
 {
 	struct file_info *fi = req->file_info;
-	list_del(&req->list);
-	list_add_tail(&req->list, &fi->req_complete);
+	list_move_tail(&req->list, &fi->req_complete);
 
 	up(&fi->complete_sem);
 	wake_up_interruptible(&fi->poll_wait_complete);
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index ba2d650..69a53d4 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -41,4 +41,6 @@
 
 source "drivers/infiniband/ulp/srp/Kconfig"
 
+source "drivers/infiniband/ulp/iser/Kconfig"
+
 endmenu
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index eea2732..c7ff58c 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -3,3 +3,4 @@
 obj-$(CONFIG_IPATH_CORE)		+= hw/ipath/
 obj-$(CONFIG_INFINIBAND_IPOIB)		+= ulp/ipoib/
 obj-$(CONFIG_INFINIBAND_SRP)		+= ulp/srp/
+obj-$(CONFIG_INFINIBAND_ISER)		+= ulp/iser/
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index a76834e..863f64b 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -476,7 +476,7 @@
 	else {
 		ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
 		return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
-			ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0;
+			ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0;
 	}
 }
 
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index b38e02a..5ed4dab 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1775,11 +1775,9 @@
 void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr)
 {
 	mad_send_wr->timeout = 0;
-	if (mad_send_wr->refcount == 1) {
-		list_del(&mad_send_wr->agent_list);
-		list_add_tail(&mad_send_wr->agent_list,
+	if (mad_send_wr->refcount == 1)
+		list_move_tail(&mad_send_wr->agent_list,
 			      &mad_send_wr->mad_agent_priv->done_list);
-	}
 }
 
 static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
@@ -2098,8 +2096,7 @@
 		queued_send_wr = container_of(mad_list,
 					struct ib_mad_send_wr_private,
 					mad_list);
-		list_del(&mad_list->list);
-		list_add_tail(&mad_list->list, &send_queue->list);
+		list_move_tail(&mad_list->list, &send_queue->list);
 	}
 	spin_unlock_irqrestore(&send_queue->lock, flags);
 
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index d4704e0..ebcd5b1 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -665,8 +665,7 @@
 			goto out;
 
 		mad_send_wr->refcount++;
-		list_del(&mad_send_wr->agent_list);
-		list_add_tail(&mad_send_wr->agent_list,
+		list_move_tail(&mad_send_wr->agent_list,
 			      &mad_send_wr->mad_agent_priv->send_list);
 	}
 out:
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 76bf61e..a908a7b 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -1530,7 +1530,6 @@
 out_put:
 	put_qp_read(qp);
 
-out:
 	while (wr) {
 		if (is_ud && wr->wr.ud.ah)
 			put_ah_read(wr->wr.ud.ah);
@@ -1539,6 +1538,7 @@
 		wr = next;
 	}
 
+out:
 	kfree(user_wr);
 
 	return ret ? ret : in_len;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e57d3c5..e725ccc 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -188,7 +188,6 @@
 
 		idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
 		ib_destroy_ah(ah);
-		list_del(&uobj->list);
 		kfree(uobj);
 	}
 
@@ -200,7 +199,6 @@
 		idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
 		ib_uverbs_detach_umcast(qp, uqp);
 		ib_destroy_qp(qp);
-		list_del(&uobj->list);
 		ib_uverbs_release_uevent(file, &uqp->uevent);
 		kfree(uqp);
 	}
@@ -213,7 +211,6 @@
 
 		idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
 		ib_destroy_cq(cq);
-		list_del(&uobj->list);
 		ib_uverbs_release_ucq(file, ev_file, ucq);
 		kfree(ucq);
 	}
@@ -225,7 +222,6 @@
 
 		idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
 		ib_destroy_srq(srq);
-		list_del(&uobj->list);
 		ib_uverbs_release_uevent(file, uevent);
 		kfree(uevent);
 	}
@@ -243,7 +239,6 @@
 		memobj = container_of(uobj, struct ib_umem_object, uobject);
 		ib_umem_release_on_close(mrdev, &memobj->umem);
 
-		list_del(&uobj->list);
 		kfree(memobj);
 	}
 
@@ -252,7 +247,6 @@
 
 		idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
 		ib_dealloc_pd(pd);
-		list_del(&uobj->list);
 		kfree(uobj);
 	}
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 216471f..ab40488 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -864,8 +864,7 @@
 
 			if (mcast) {
 				/* Destroy the send only entry */
-				list_del(&mcast->list);
-				list_add_tail(&mcast->list, &remove_list);
+				list_move_tail(&mcast->list, &remove_list);
 
 				rb_replace_node(&mcast->rb_node,
 						&nmcast->rb_node,
@@ -890,8 +889,7 @@
 			rb_erase(&mcast->rb_node, &priv->multicast_tree);
 
 			/* Move to the remove list */
-			list_del(&mcast->list);
-			list_add_tail(&mcast->list, &remove_list);
+			list_move_tail(&mcast->list, &remove_list);
 		}
 	}
 
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
new file mode 100644
index 0000000..fead87d
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -0,0 +1,11 @@
+config INFINIBAND_ISER
+	tristate "ISCSI RDMA Protocol"
+	depends on INFINIBAND && SCSI
+	select SCSI_ISCSI_ATTRS
+	---help---
+	  Support for the ISCSI RDMA Protocol over InfiniBand.  This
+	  allows you to access storage devices that speak ISER/ISCSI
+	  over InfiniBand.
+
+	  The ISER protocol is defined by IETF.
+	  See <http://www.ietf.org/>.
diff --git a/drivers/infiniband/ulp/iser/Makefile b/drivers/infiniband/ulp/iser/Makefile
new file mode 100644
index 0000000..fe6cd15f
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_INFINIBAND_ISER)	+= ib_iser.o
+
+ib_iser-y			:= iser_verbs.o iser_initiator.o iser_memory.o \
+				   iscsi_iser.o
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
new file mode 100644
index 0000000..4c3f2de
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -0,0 +1,790 @@
+/*
+ * iSCSI Initiator over iSER Data-Path
+ *
+ * Copyright (C) 2004 Dmitry Yusupov
+ * Copyright (C) 2004 Alex Aizman
+ * Copyright (C) 2005 Mike Christie
+ * Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved.
+ * maintained by openib-general@openib.org
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *	- Redistributions of source code must retain the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer.
+ *
+ *	- Redistributions in binary form must reproduce the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer in the documentation and/or other materials
+ *	  provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Credits:
+ *	Christoph Hellwig
+ *	FUJITA Tomonori
+ *	Arne Redlich
+ *	Zhenyu Wang
+ * Modified by:
+ *      Erez Zilber
+ *
+ *
+ * $Id: iscsi_iser.c 6965 2006-05-07 11:36:20Z ogerlitz $
+ */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/hardirq.h>
+#include <linux/kfifo.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/cdev.h>
+#include <linux/in.h>
+#include <linux/net.h>
+#include <linux/scatterlist.h>
+#include <linux/delay.h>
+
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "iscsi_iser.h"
+
+static unsigned int iscsi_max_lun = 512;
+module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
+
+int iser_debug_level = 0;
+
+MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover "
+		   "v" DRV_VER " (" DRV_DATE ")");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz");
+
+module_param_named(debug_level, iser_debug_level, int, 0644);
+MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");
+
+struct iser_global ig;
+
+void
+iscsi_iser_recv(struct iscsi_conn *conn,
+		struct iscsi_hdr *hdr, char *rx_data, int rx_data_len)
+{
+	int rc = 0;
+	uint32_t ret_itt;
+	int datalen;
+	int ahslen;
+
+	/* verify PDU length */
+	datalen = ntoh24(hdr->dlength);
+	if (datalen != rx_data_len) {
+		printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n",
+		       datalen, rx_data_len);
+		rc = ISCSI_ERR_DATALEN;
+		goto error;
+	}
+
+	/* read AHS */
+	ahslen = hdr->hlength * 4;
+
+	/* verify itt (itt encoding: age+cid+itt) */
+	rc = iscsi_verify_itt(conn, hdr, &ret_itt);
+
+	if (!rc)
+		rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
+
+	if (rc && rc != ISCSI_ERR_NO_SCSI_CMD)
+		goto error;
+
+	return;
+error:
+	iscsi_conn_failure(conn, rc);
+}
+
+
+/**
+ * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+ *
+ **/
+static void
+iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+{
+	struct iscsi_iser_conn     *iser_conn  = ctask->conn->dd_data;
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+	struct scsi_cmnd  *sc = ctask->sc;
+
+	iser_ctask->command_sent = 0;
+	iser_ctask->iser_conn    = iser_conn;
+
+	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+		BUG_ON(ctask->total_length == 0);
+		/* bytes to be sent via RDMA operations */
+		iser_ctask->rdma_data_count = ctask->total_length -
+					 ctask->imm_count -
+					 ctask->unsol_count;
+
+		debug_scsi("cmd [itt %x total %d imm %d unsol_data %d "
+			   "rdma_data %d]\n",
+			   ctask->itt, ctask->total_length, ctask->imm_count,
+			   ctask->unsol_count, iser_ctask->rdma_data_count);
+	} else
+		/* bytes to be sent via RDMA operations */
+		iser_ctask->rdma_data_count = ctask->total_length;
+
+	iser_ctask_rdma_init(iser_ctask);
+}
+
+/**
+ * iscsi_mtask_xmit - xmit management(immediate) task
+ * @conn: iscsi connection
+ * @mtask: task management task
+ *
+ * Notes:
+ *	The function can return -EAGAIN in which case caller must
+ *	call it again later, or recover. '0' return code means successful
+ *	xmit.
+ *
+ **/
+static int
+iscsi_iser_mtask_xmit(struct iscsi_conn *conn,
+		      struct iscsi_mgmt_task *mtask)
+{
+	int error = 0;
+
+	debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+
+	error = iser_send_control(conn, mtask);
+
+	/* since iser xmits control with zero copy, mtasks can not be recycled
+	 * right after sending them.
+	 * The recycling scheme is based on whether a response is expected
+	 * - if yes, the mtask is recycled at iscsi_complete_pdu
+	 * - if no,  the mtask is recycled at iser_snd_completion
+	 */
+	if (error && error != -EAGAIN)
+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+
+	return error;
+}
+
+static int
+iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
+				 struct iscsi_cmd_task *ctask)
+{
+	struct iscsi_data  hdr;
+	int error = 0;
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+
+	/* Send data-out PDUs while there's still unsolicited data to send */
+	while (ctask->unsol_count > 0) {
+		iscsi_prep_unsolicit_data_pdu(ctask, &hdr,
+					      iser_ctask->rdma_data_count);
+
+		debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
+			   hdr.itt, ctask->data_count);
+
+		/* the buffer description has been passed with the command */
+		/* Send the command */
+		error = iser_send_data_out(conn, ctask, &hdr);
+		if (error) {
+			ctask->unsol_datasn--;
+			goto iscsi_iser_ctask_xmit_unsol_data_exit;
+		}
+		ctask->unsol_count -= ctask->data_count;
+		debug_scsi("Need to send %d more as data-out PDUs\n",
+			   ctask->unsol_count);
+	}
+
+iscsi_iser_ctask_xmit_unsol_data_exit:
+	return error;
+}
+
+static int
+iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
+		      struct iscsi_cmd_task *ctask)
+{
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+	int error = 0;
+
+	debug_scsi("ctask deq [cid %d itt 0x%x]\n",
+		   conn->id, ctask->itt);
+
+	/*
+	 * serialize with TMF AbortTask
+	 */
+	if (ctask->mtask)
+		return error;
+
+	/* Send the cmd PDU */
+	if (!iser_ctask->command_sent) {
+		error = iser_send_command(conn, ctask);
+		if (error)
+			goto iscsi_iser_ctask_xmit_exit;
+		iser_ctask->command_sent = 1;
+	}
+
+	/* Send unsolicited data-out PDU(s) if necessary */
+	if (ctask->unsol_count)
+		error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask);
+
+ iscsi_iser_ctask_xmit_exit:
+	if (error && error != -EAGAIN)
+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+	return error;
+}
+
+static void
+iscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+{
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+
+	if (iser_ctask->status == ISER_TASK_STATUS_STARTED) {
+		iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
+		iser_ctask_rdma_finalize(iser_ctask);
+	}
+}
+
+static struct iser_conn *
+iscsi_iser_ib_conn_lookup(__u64 ep_handle)
+{
+	struct iser_conn *ib_conn;
+	struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle;
+
+	mutex_lock(&ig.connlist_mutex);
+	list_for_each_entry(ib_conn, &ig.connlist, conn_list) {
+		if (ib_conn == uib_conn) {
+			mutex_unlock(&ig.connlist_mutex);
+			return ib_conn;
+		}
+	}
+	mutex_unlock(&ig.connlist_mutex);
+	iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle);
+	return NULL;
+}
+
+static struct iscsi_cls_conn *
+iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
+{
+	struct iscsi_conn *conn;
+	struct iscsi_cls_conn *cls_conn;
+	struct iscsi_iser_conn *iser_conn;
+
+	cls_conn = iscsi_conn_setup(cls_session, conn_idx);
+	if (!cls_conn)
+		return NULL;
+	conn = cls_conn->dd_data;
+
+	/*
+	 * due to issues with the login code re iser sematics
+	 * this not set in iscsi_conn_setup - FIXME
+	 */
+	conn->max_recv_dlength = 128;
+
+	iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL);
+	if (!iser_conn)
+		goto conn_alloc_fail;
+
+	/* currently this is the only field which need to be initiated */
+	rwlock_init(&iser_conn->lock);
+
+	conn->dd_data = iser_conn;
+	iser_conn->iscsi_conn = conn;
+
+	return cls_conn;
+
+conn_alloc_fail:
+	iscsi_conn_teardown(cls_conn);
+	return NULL;
+}
+
+static void
+iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+	iscsi_conn_teardown(cls_conn);
+	kfree(iser_conn);
+}
+
+static int
+iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
+		     struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
+		     int is_leading)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct iscsi_iser_conn *iser_conn;
+	struct iser_conn *ib_conn;
+	int error;
+
+	error = iscsi_conn_bind(cls_session, cls_conn, is_leading);
+	if (error)
+		return error;
+
+	/* the transport ep handle comes from user space so it must be
+	 * verified against the global ib connections list */
+	ib_conn = iscsi_iser_ib_conn_lookup(transport_eph);
+	if (!ib_conn) {
+		iser_err("can't bind eph %llx\n",
+			 (unsigned long long)transport_eph);
+		return -EINVAL;
+	}
+	/* binds the iSER connection retrieved from the previously
+	 * connected ep_handle to the iSCSI layer connection. exchanges
+	 * connection pointers */
+	iser_err("binding iscsi conn %p to iser_conn %p\n",conn,ib_conn);
+	iser_conn = conn->dd_data;
+	ib_conn->iser_conn = iser_conn;
+	iser_conn->ib_conn  = ib_conn;
+
+	conn->recv_lock = &iser_conn->lock;
+
+	return 0;
+}
+
+static int
+iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	int err;
+
+	err = iscsi_conn_start(cls_conn);
+	if (err)
+		return err;
+
+	return iser_conn_set_full_featured_mode(conn);
+}
+
+static void
+iscsi_iser_conn_terminate(struct iscsi_conn *conn)
+{
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+	struct iser_conn *ib_conn = iser_conn->ib_conn;
+
+	BUG_ON(!ib_conn);
+	/* starts conn teardown process, waits until all previously   *
+	 * posted buffers get flushed, deallocates all conn resources */
+	iser_conn_terminate(ib_conn);
+	iser_conn->ib_conn = NULL;
+	conn->recv_lock = NULL;
+}
+
+
+static struct iscsi_transport iscsi_iser_transport;
+
+static struct iscsi_cls_session *
+iscsi_iser_session_create(struct iscsi_transport *iscsit,
+			 struct scsi_transport_template *scsit,
+			  uint32_t initial_cmdsn, uint32_t *hostno)
+{
+	struct iscsi_cls_session *cls_session;
+	struct iscsi_session *session;
+	int i;
+	uint32_t hn;
+	struct iscsi_cmd_task  *ctask;
+	struct iscsi_mgmt_task *mtask;
+	struct iscsi_iser_cmd_task *iser_ctask;
+	struct iser_desc *desc;
+
+	cls_session = iscsi_session_setup(iscsit, scsit,
+					  sizeof(struct iscsi_iser_cmd_task),
+					  sizeof(struct iser_desc),
+					  initial_cmdsn, &hn);
+	if (!cls_session)
+	return NULL;
+
+	*hostno = hn;
+	session = class_to_transport_session(cls_session);
+
+	/* libiscsi setup itts, data and pool so just set desc fields */
+	for (i = 0; i < session->cmds_max; i++) {
+		ctask      = session->cmds[i];
+		iser_ctask = ctask->dd_data;
+		ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
+	}
+
+	for (i = 0; i < session->mgmtpool_max; i++) {
+		mtask      = session->mgmt_cmds[i];
+		desc       = mtask->dd_data;
+		mtask->hdr = &desc->iscsi_header;
+		desc->data = mtask->data;
+	}
+
+	return cls_session;
+}
+
+static int
+iscsi_iser_conn_set_param(struct iscsi_cls_conn *cls_conn,
+			  enum iscsi_param param, uint32_t value)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct iscsi_session *session = conn->session;
+
+	spin_lock_bh(&session->lock);
+	if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
+	    conn->stop_stage != STOP_CONN_RECOVER) {
+		printk(KERN_ERR "iscsi_iser: can not change parameter [%d]\n",
+		       param);
+		spin_unlock_bh(&session->lock);
+		return 0;
+	}
+	spin_unlock_bh(&session->lock);
+
+	switch (param) {
+	case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		/* TBD */
+		break;
+	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		conn->max_xmit_dlength =  value;
+		break;
+	case ISCSI_PARAM_HDRDGST_EN:
+		if (value) {
+			printk(KERN_ERR "DataDigest wasn't negotiated to None");
+			return -EPROTO;
+		}
+		break;
+	case ISCSI_PARAM_DATADGST_EN:
+		if (value) {
+			printk(KERN_ERR "DataDigest wasn't negotiated to None");
+			return -EPROTO;
+		}
+		break;
+	case ISCSI_PARAM_INITIAL_R2T_EN:
+		session->initial_r2t_en = value;
+		break;
+	case ISCSI_PARAM_IMM_DATA_EN:
+		session->imm_data_en = value;
+		break;
+	case ISCSI_PARAM_FIRST_BURST:
+		session->first_burst = value;
+		break;
+	case ISCSI_PARAM_MAX_BURST:
+		session->max_burst = value;
+		break;
+	case ISCSI_PARAM_PDU_INORDER_EN:
+		session->pdu_inorder_en = value;
+		break;
+	case ISCSI_PARAM_DATASEQ_INORDER_EN:
+		session->dataseq_inorder_en = value;
+		break;
+	case ISCSI_PARAM_ERL:
+		session->erl = value;
+		break;
+	case ISCSI_PARAM_IFMARKER_EN:
+		if (value) {
+			printk(KERN_ERR "IFMarker wasn't negotiated to No");
+			return -EPROTO;
+		}
+		break;
+	case ISCSI_PARAM_OFMARKER_EN:
+		if (value) {
+			printk(KERN_ERR "OFMarker wasn't negotiated to No");
+			return -EPROTO;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int
+iscsi_iser_session_get_param(struct iscsi_cls_session *cls_session,
+			     enum iscsi_param param, uint32_t *value)
+{
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+
+	switch (param) {
+	case ISCSI_PARAM_INITIAL_R2T_EN:
+		*value = session->initial_r2t_en;
+		break;
+	case ISCSI_PARAM_MAX_R2T:
+		*value = session->max_r2t;
+		break;
+	case ISCSI_PARAM_IMM_DATA_EN:
+		*value = session->imm_data_en;
+		break;
+	case ISCSI_PARAM_FIRST_BURST:
+		*value = session->first_burst;
+		break;
+	case ISCSI_PARAM_MAX_BURST:
+		*value = session->max_burst;
+		break;
+	case ISCSI_PARAM_PDU_INORDER_EN:
+		*value = session->pdu_inorder_en;
+		break;
+	case ISCSI_PARAM_DATASEQ_INORDER_EN:
+		*value = session->dataseq_inorder_en;
+		break;
+	case ISCSI_PARAM_ERL:
+		*value = session->erl;
+		break;
+	case ISCSI_PARAM_IFMARKER_EN:
+		*value = 0;
+		break;
+	case ISCSI_PARAM_OFMARKER_EN:
+		*value = 0;
+		break;
+	default:
+		return ISCSI_ERR_PARAM_NOT_FOUND;
+	}
+
+	return 0;
+}
+
+static int
+iscsi_iser_conn_get_param(struct iscsi_cls_conn *cls_conn,
+			  enum iscsi_param param, uint32_t *value)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+
+	switch(param) {
+	case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		*value = conn->max_recv_dlength;
+		break;
+	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		*value = conn->max_xmit_dlength;
+		break;
+	case ISCSI_PARAM_HDRDGST_EN:
+		*value = 0;
+		break;
+	case ISCSI_PARAM_DATADGST_EN:
+		*value = 0;
+		break;
+	/*case ISCSI_PARAM_TARGET_RECV_DLENGTH:
+		*value = conn->target_recv_dlength;
+		break;
+	case ISCSI_PARAM_INITIATOR_RECV_DLENGTH:
+		*value = conn->initiator_recv_dlength;
+		break;*/
+	default:
+		return ISCSI_ERR_PARAM_NOT_FOUND;
+	}
+
+	return 0;
+}
+
+
+static void
+iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+
+	stats->txdata_octets = conn->txdata_octets;
+	stats->rxdata_octets = conn->rxdata_octets;
+	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
+	stats->dataout_pdus = conn->dataout_pdus_cnt;
+	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
+	stats->datain_pdus = conn->datain_pdus_cnt; /* always 0 */
+	stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */
+	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
+	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
+	stats->custom_length = 3;
+	strcpy(stats->custom[0].desc, "qp_tx_queue_full");
+	stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */
+	strcpy(stats->custom[1].desc, "fmr_map_not_avail");
+	stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */;
+	strcpy(stats->custom[2].desc, "eh_abort_cnt");
+	stats->custom[2].value = conn->eh_abort_cnt;
+}
+
+static int
+iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking,
+		      __u64 *ep_handle)
+{
+	int err;
+	struct iser_conn *ib_conn;
+
+	err = iser_conn_init(&ib_conn);
+	if (err)
+		goto out;
+
+	err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, non_blocking);
+	if (!err)
+		*ep_handle = (__u64)(unsigned long)ib_conn;
+
+out:
+	return err;
+}
+
+static int
+iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms)
+{
+	struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
+	int rc;
+
+	if (!ib_conn)
+		return -EINVAL;
+
+	rc = wait_event_interruptible_timeout(ib_conn->wait,
+			     ib_conn->state == ISER_CONN_UP,
+			     msecs_to_jiffies(timeout_ms));
+
+	/* if conn establishment failed, return error code to iscsi */
+	if (!rc &&
+	    (ib_conn->state == ISER_CONN_TERMINATING ||
+	     ib_conn->state == ISER_CONN_DOWN))
+		rc = -1;
+
+	iser_err("ib conn %p rc = %d\n", ib_conn, rc);
+
+	if (rc > 0)
+		return 1; /* success, this is the equivalent of POLLOUT */
+	else if (!rc)
+		return 0; /* timeout */
+	else
+		return rc; /* signal */
+}
+
+static void
+iscsi_iser_ep_disconnect(__u64 ep_handle)
+{
+	struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
+
+	if (!ib_conn)
+		return;
+
+	iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
+
+	iser_conn_terminate(ib_conn);
+}
+
+static struct scsi_host_template iscsi_iser_sht = {
+	.name                   = "iSCSI Initiator over iSER, v." DRV_VER,
+	.queuecommand           = iscsi_queuecommand,
+	.can_queue		= ISCSI_XMIT_CMDS_MAX - 1,
+	.sg_tablesize           = ISCSI_ISER_SG_TABLESIZE,
+	.cmd_per_lun            = ISCSI_MAX_CMD_PER_LUN,
+	.eh_abort_handler       = iscsi_eh_abort,
+	.eh_host_reset_handler	= iscsi_eh_host_reset,
+	.use_clustering         = DISABLE_CLUSTERING,
+	.proc_name              = "iscsi_iser",
+	.this_id                = -1,
+};
+
+static struct iscsi_transport iscsi_iser_transport = {
+	.owner                  = THIS_MODULE,
+	.name                   = "iser",
+	.caps                   = CAP_RECOVERY_L0 | CAP_MULTI_R2T,
+	.param_mask		= ISCSI_MAX_RECV_DLENGTH |
+				  ISCSI_MAX_XMIT_DLENGTH |
+				  ISCSI_HDRDGST_EN |
+				  ISCSI_DATADGST_EN |
+				  ISCSI_INITIAL_R2T_EN |
+				  ISCSI_MAX_R2T |
+				  ISCSI_IMM_DATA_EN |
+				  ISCSI_FIRST_BURST |
+				  ISCSI_MAX_BURST |
+				  ISCSI_PDU_INORDER_EN |
+				  ISCSI_DATASEQ_INORDER_EN,
+	.host_template          = &iscsi_iser_sht,
+	.conndata_size		= sizeof(struct iscsi_conn),
+	.max_lun                = ISCSI_ISER_MAX_LUN,
+	.max_cmd_len            = ISCSI_ISER_MAX_CMD_LEN,
+	/* session management */
+	.create_session         = iscsi_iser_session_create,
+	.destroy_session        = iscsi_session_teardown,
+	/* connection management */
+	.create_conn            = iscsi_iser_conn_create,
+	.bind_conn              = iscsi_iser_conn_bind,
+	.destroy_conn           = iscsi_iser_conn_destroy,
+	.set_param              = iscsi_iser_conn_set_param,
+	.get_conn_param		= iscsi_iser_conn_get_param,
+	.get_session_param	= iscsi_iser_session_get_param,
+	.start_conn             = iscsi_iser_conn_start,
+	.stop_conn              = iscsi_conn_stop,
+	/* these are called as part of conn recovery */
+	.suspend_conn_recv	= NULL, /* FIXME is/how this relvant to iser? */
+	.terminate_conn		= iscsi_iser_conn_terminate,
+	/* IO */
+	.send_pdu		= iscsi_conn_send_pdu,
+	.get_stats		= iscsi_iser_conn_get_stats,
+	.init_cmd_task		= iscsi_iser_cmd_init,
+	.xmit_cmd_task		= iscsi_iser_ctask_xmit,
+	.xmit_mgmt_task		= iscsi_iser_mtask_xmit,
+	.cleanup_cmd_task	= iscsi_iser_cleanup_ctask,
+	/* recovery */
+	.session_recovery_timedout = iscsi_session_recovery_timedout,
+
+	.ep_connect             = iscsi_iser_ep_connect,
+	.ep_poll                = iscsi_iser_ep_poll,
+	.ep_disconnect          = iscsi_iser_ep_disconnect
+};
+
+static int __init iser_init(void)
+{
+	int err;
+
+	iser_dbg("Starting iSER datamover...\n");
+
+	if (iscsi_max_lun < 1) {
+		printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
+		return -EINVAL;
+	}
+
+	iscsi_iser_transport.max_lun = iscsi_max_lun;
+
+	memset(&ig, 0, sizeof(struct iser_global));
+
+	ig.desc_cache = kmem_cache_create("iser_descriptors",
+					  sizeof (struct iser_desc),
+					  0, SLAB_HWCACHE_ALIGN,
+					  NULL, NULL);
+	if (ig.desc_cache == NULL)
+		return -ENOMEM;
+
+	/* device init is called only after the first addr resolution */
+	mutex_init(&ig.device_list_mutex);
+	INIT_LIST_HEAD(&ig.device_list);
+	mutex_init(&ig.connlist_mutex);
+	INIT_LIST_HEAD(&ig.connlist);
+
+	if (!iscsi_register_transport(&iscsi_iser_transport)) {
+		iser_err("iscsi_register_transport failed\n");
+		err = -EINVAL;
+		goto register_transport_failure;
+	}
+
+	return 0;
+
+register_transport_failure:
+	kmem_cache_destroy(ig.desc_cache);
+
+	return err;
+}
+
+static void __exit iser_exit(void)
+{
+	iser_dbg("Removing iSER datamover...\n");
+	iscsi_unregister_transport(&iscsi_iser_transport);
+	kmem_cache_destroy(ig.desc_cache);
+}
+
+module_init(iser_init);
+module_exit(iser_exit);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
new file mode 100644
index 0000000..3350ba6
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -0,0 +1,354 @@
+/*
+ * iSER transport for the Open iSCSI Initiator & iSER transport internals
+ *
+ * Copyright (C) 2004 Dmitry Yusupov
+ * Copyright (C) 2004 Alex Aizman
+ * Copyright (C) 2005 Mike Christie
+ * based on code maintained by open-iscsi@googlegroups.com
+ *
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *	- Redistributions of source code must retain the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer.
+ *
+ *	- Redistributions in binary form must reproduce the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer in the documentation and/or other materials
+ *	  provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iscsi_iser.h 7051 2006-05-10 12:29:11Z ogerlitz $
+ */
+#ifndef __ISCSI_ISER_H__
+#define __ISCSI_ISER_H__
+
+#include <linux/types.h>
+#include <linux/net.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mempool.h>
+#include <linux/uio.h>
+
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_fmr_pool.h>
+#include <rdma/rdma_cm.h>
+
+#define DRV_NAME	"iser"
+#define PFX		DRV_NAME ": "
+#define DRV_VER		"0.1"
+#define DRV_DATE	"May 7th, 2006"
+
+#define iser_dbg(fmt, arg...)				\
+	do {						\
+		if (iser_debug_level > 0)		\
+			printk(KERN_DEBUG PFX "%s:" fmt,\
+				__func__ , ## arg);	\
+	} while (0)
+
+#define iser_err(fmt, arg...)				\
+	do {						\
+		printk(KERN_ERR PFX "%s:" fmt,          \
+		       __func__ , ## arg);		\
+	} while (0)
+
+					/* support upto 512KB in one RDMA */
+#define ISCSI_ISER_SG_TABLESIZE         (0x80000 >> PAGE_SHIFT)
+#define ISCSI_ISER_MAX_LUN		256
+#define ISCSI_ISER_MAX_CMD_LEN		16
+
+/* QP settings */
+/* Maximal bounds on received asynchronous PDUs */
+#define ISER_MAX_RX_MISC_PDUS		4 /* NOOP_IN(2) , ASYNC_EVENT(2)   */
+
+#define ISER_MAX_TX_MISC_PDUS		6 /* NOOP_OUT(2), TEXT(1),         *
+					   * SCSI_TMFUNC(2), LOGOUT(1) */
+
+#define ISER_QP_MAX_RECV_DTOS		(ISCSI_XMIT_CMDS_MAX + \
+					ISER_MAX_RX_MISC_PDUS    +  \
+					ISER_MAX_TX_MISC_PDUS)
+
+/* the max TX (send) WR supported by the iSER QP is defined by                 *
+ * max_send_wr = T * (1 + D) + C ; D is how many inflight dataouts we expect   *
+ * to have at max for SCSI command. The tx posting & completion handling code  *
+ * supports -EAGAIN scheme where tx is suspended till the QP has room for more *
+ * send WR. D=8 comes from 64K/8K                                              */
+
+#define ISER_INFLIGHT_DATAOUTS		8
+
+#define ISER_QP_MAX_REQ_DTOS		(ISCSI_XMIT_CMDS_MAX *    \
+					(1 + ISER_INFLIGHT_DATAOUTS) + \
+					ISER_MAX_TX_MISC_PDUS        + \
+					ISER_MAX_RX_MISC_PDUS)
+
+#define ISER_VER			0x10
+#define ISER_WSV			0x08
+#define ISER_RSV			0x04
+
+struct iser_hdr {
+	u8      flags;
+	u8      rsvd[3];
+	__be32  write_stag; /* write rkey */
+	__be64  write_va;
+	__be32  read_stag;  /* read rkey */
+	__be64  read_va;
+} __attribute__((packed));
+
+
+/* Length of an object name string */
+#define ISER_OBJECT_NAME_SIZE		    64
+
+enum iser_ib_conn_state {
+	ISER_CONN_INIT,		   /* descriptor allocd, no conn          */
+	ISER_CONN_PENDING,	   /* in the process of being established */
+	ISER_CONN_UP,		   /* up and running                      */
+	ISER_CONN_TERMINATING,	   /* in the process of being terminated  */
+	ISER_CONN_DOWN,		   /* shut down                           */
+	ISER_CONN_STATES_NUM
+};
+
+enum iser_task_status {
+	ISER_TASK_STATUS_INIT = 0,
+	ISER_TASK_STATUS_STARTED,
+	ISER_TASK_STATUS_COMPLETED
+};
+
+enum iser_data_dir {
+	ISER_DIR_IN = 0,	   /* to initiator */
+	ISER_DIR_OUT,		   /* from initiator */
+	ISER_DIRS_NUM
+};
+
+struct iser_data_buf {
+	void               *buf;      /* pointer to the sg list               */
+	unsigned int       size;      /* num entries of this sg               */
+	unsigned long      data_len;  /* total data len                       */
+	unsigned int       dma_nents; /* returned by dma_map_sg               */
+	char       	   *copy_buf; /* allocated copy buf for SGs unaligned *
+	                               * for rdma which are copied            */
+	struct scatterlist sg_single; /* SG-ified clone of a non SG SC or     *
+				       * unaligned SG                         */
+  };
+
+/* fwd declarations */
+struct iser_device;
+struct iscsi_iser_conn;
+struct iscsi_iser_cmd_task;
+
+struct iser_mem_reg {
+	u32  lkey;
+	u32  rkey;
+	u64  va;
+	u64  len;
+	void *mem_h;
+};
+
+struct iser_regd_buf {
+	struct iser_mem_reg     reg;        /* memory registration info        */
+	void                    *virt_addr;
+	struct iser_device      *device;    /* device->device for dma_unmap    */
+	dma_addr_t              dma_addr;   /* if non zero, addr for dma_unmap */
+	enum dma_data_direction direction;  /* direction for dma_unmap	       */
+	unsigned int            data_size;
+	atomic_t                ref_count;  /* refcount, freed when dec to 0   */
+};
+
+#define MAX_REGD_BUF_VECTOR_LEN	2
+
+struct iser_dto {
+	struct iscsi_iser_cmd_task *ctask;
+	struct iscsi_iser_conn     *conn;
+	int                        notify_enable;
+
+	/* vector of registered buffers */
+	unsigned int               regd_vector_len;
+	struct iser_regd_buf       *regd[MAX_REGD_BUF_VECTOR_LEN];
+
+	/* offset into the registered buffer may be specified */
+	unsigned int               offset[MAX_REGD_BUF_VECTOR_LEN];
+
+	/* a smaller size may be specified, if 0, then full size is used */
+	unsigned int               used_sz[MAX_REGD_BUF_VECTOR_LEN];
+};
+
+enum iser_desc_type {
+	ISCSI_RX,
+	ISCSI_TX_CONTROL ,
+	ISCSI_TX_SCSI_COMMAND,
+	ISCSI_TX_DATAOUT
+};
+
+struct iser_desc {
+	struct iser_hdr              iser_header;
+	struct iscsi_hdr             iscsi_header;
+	struct iser_regd_buf         hdr_regd_buf;
+	void                         *data;         /* used by RX & TX_CONTROL */
+	struct iser_regd_buf         data_regd_buf; /* used by RX & TX_CONTROL */
+	enum   iser_desc_type        type;
+	struct iser_dto              dto;
+};
+
+struct iser_device {
+	struct ib_device             *ib_device;
+	struct ib_pd	             *pd;
+	struct ib_cq	             *cq;
+	struct ib_mr	             *mr;
+	struct tasklet_struct	     cq_tasklet;
+	struct list_head             ig_list; /* entry in ig devices list */
+	int                          refcount;
+};
+
+struct iser_conn {
+	struct iscsi_iser_conn       *iser_conn; /* iser conn for upcalls  */
+	enum iser_ib_conn_state	     state;	    /* rdma connection state   */
+	spinlock_t		     lock;	    /* used for state changes  */
+	struct iser_device           *device;       /* device context          */
+	struct rdma_cm_id            *cma_id;       /* CMA ID		       */
+	struct ib_qp	             *qp;           /* QP 		       */
+	struct ib_fmr_pool           *fmr_pool;     /* pool of IB FMRs         */
+	int                          disc_evt_flag; /* disconn event delivered */
+	wait_queue_head_t	     wait;          /* waitq for conn/disconn  */
+	atomic_t                     post_recv_buf_count; /* posted rx count   */
+	atomic_t                     post_send_buf_count; /* posted tx count   */
+	struct work_struct           comperror_work; /* conn term sleepable ctx*/
+	char 			     name[ISER_OBJECT_NAME_SIZE];
+	struct iser_page_vec         *page_vec;     /* represents SG to fmr maps*
+						     * maps serialized as tx is*/
+	struct list_head	     conn_list;       /* entry in ig conn list */
+};
+
+struct iscsi_iser_conn {
+	struct iscsi_conn            *iscsi_conn;/* ptr to iscsi conn */
+	struct iser_conn             *ib_conn;   /* iSER IB conn      */
+
+	rwlock_t		     lock;
+};
+
+struct iscsi_iser_cmd_task {
+	struct iser_desc             desc;
+	struct iscsi_iser_conn	     *iser_conn;
+	int			     rdma_data_count;/* RDMA bytes           */
+	enum iser_task_status 	     status;
+	int                          command_sent;  /* set if command  sent  */
+	int                          dir[ISER_DIRS_NUM];      /* set if dir use*/
+	struct iser_regd_buf         rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */
+	struct iser_data_buf         data[ISER_DIRS_NUM];     /* orig. data des*/
+	struct iser_data_buf         data_copy[ISER_DIRS_NUM];/* contig. copy  */
+};
+
+struct iser_page_vec {
+	u64 *pages;
+	int length;
+	int offset;
+	int data_size;
+};
+
+struct iser_global {
+	struct mutex      device_list_mutex;/*                   */
+	struct list_head  device_list;	     /* all iSER devices */
+	struct mutex      connlist_mutex;
+	struct list_head  connlist;		/* all iSER IB connections */
+
+	kmem_cache_t *desc_cache;
+};
+
+extern struct iser_global ig;
+extern int iser_debug_level;
+
+/* allocate connection resources needed for rdma functionality */
+int iser_conn_set_full_featured_mode(struct iscsi_conn *conn);
+
+int iser_send_control(struct iscsi_conn      *conn,
+		      struct iscsi_mgmt_task *mtask);
+
+int iser_send_command(struct iscsi_conn      *conn,
+		      struct iscsi_cmd_task  *ctask);
+
+int iser_send_data_out(struct iscsi_conn     *conn,
+		       struct iscsi_cmd_task *ctask,
+		       struct iscsi_data          *hdr);
+
+void iscsi_iser_recv(struct iscsi_conn *conn,
+		     struct iscsi_hdr       *hdr,
+		     char                   *rx_data,
+		     int                    rx_data_len);
+
+int  iser_conn_init(struct iser_conn **ib_conn);
+
+void iser_conn_terminate(struct iser_conn *ib_conn);
+
+void iser_conn_release(struct iser_conn *ib_conn);
+
+void iser_rcv_completion(struct iser_desc *desc,
+			 unsigned long    dto_xfer_len);
+
+void iser_snd_completion(struct iser_desc *desc);
+
+void iser_ctask_rdma_init(struct iscsi_iser_cmd_task     *ctask);
+
+void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *ctask);
+
+void iser_dto_buffs_release(struct iser_dto *dto);
+
+int  iser_regd_buff_release(struct iser_regd_buf *regd_buf);
+
+void iser_reg_single(struct iser_device      *device,
+		     struct iser_regd_buf    *regd_buf,
+		     enum dma_data_direction direction);
+
+int  iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task    *ctask,
+				  enum iser_data_dir            cmd_dir);
+
+void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
+				     enum iser_data_dir         cmd_dir);
+
+int  iser_reg_rdma_mem(struct iscsi_iser_cmd_task *ctask,
+		       enum   iser_data_dir        cmd_dir);
+
+int  iser_connect(struct iser_conn   *ib_conn,
+		  struct sockaddr_in *src_addr,
+		  struct sockaddr_in *dst_addr,
+		  int                non_blocking);
+
+int  iser_reg_page_vec(struct iser_conn     *ib_conn,
+		       struct iser_page_vec *page_vec,
+		       struct iser_mem_reg  *mem_reg);
+
+void iser_unreg_mem(struct iser_mem_reg *mem_reg);
+
+int  iser_post_recv(struct iser_desc *rx_desc);
+int  iser_post_send(struct iser_desc *tx_desc);
+
+int iser_conn_state_comp(struct iser_conn *ib_conn,
+			 enum iser_ib_conn_state comp);
+#endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
new file mode 100644
index 0000000..ccf56f6
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *	- Redistributions of source code must retain the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer.
+ *
+ *	- Redistributions in binary form must reproduce the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer in the documentation and/or other materials
+ *	  provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iser_initiator.c 6964 2006-05-07 11:11:43Z ogerlitz $
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+#include <linux/kfifo.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+
+#include "iscsi_iser.h"
+
+/* Constant PDU lengths calculations */
+#define ISER_TOTAL_HEADERS_LEN  (sizeof (struct iser_hdr) + \
+				 sizeof (struct iscsi_hdr))
+
+/* iser_dto_add_regd_buff - increments the reference count for *
+ * the registered buffer & adds it to the DTO object           */
+static void iser_dto_add_regd_buff(struct iser_dto *dto,
+				   struct iser_regd_buf *regd_buf,
+				   unsigned long use_offset,
+				   unsigned long use_size)
+{
+	int add_idx;
+
+	atomic_inc(&regd_buf->ref_count);
+
+	add_idx = dto->regd_vector_len;
+	dto->regd[add_idx] = regd_buf;
+	dto->used_sz[add_idx] = use_size;
+	dto->offset[add_idx] = use_offset;
+
+	dto->regd_vector_len++;
+}
+
+static int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+				  struct iser_data_buf       *data,
+				  enum   iser_data_dir       iser_dir,
+				  enum   dma_data_direction  dma_dir)
+{
+	struct device *dma_device;
+
+	iser_ctask->dir[iser_dir] = 1;
+	dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+	data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
+	if (data->dma_nents == 0) {
+		iser_err("dma_map_sg failed!!!\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+{
+	struct device  *dma_device;
+	struct iser_data_buf *data;
+
+	dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+	if (iser_ctask->dir[ISER_DIR_IN]) {
+		data = &iser_ctask->data[ISER_DIR_IN];
+		dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
+	}
+
+	if (iser_ctask->dir[ISER_DIR_OUT]) {
+		data = &iser_ctask->data[ISER_DIR_OUT];
+		dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
+	}
+}
+
+/* Register user buffer memory and initialize passive rdma
+ *  dto descriptor. Total data size is stored in
+ *  iser_ctask->data[ISER_DIR_IN].data_len
+ */
+static int iser_prepare_read_cmd(struct iscsi_cmd_task *ctask,
+				 unsigned int edtl)
+
+{
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+	struct iser_regd_buf *regd_buf;
+	int err;
+	struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
+	struct iser_data_buf *buf_in = &iser_ctask->data[ISER_DIR_IN];
+
+	err = iser_dma_map_task_data(iser_ctask,
+				     buf_in,
+				     ISER_DIR_IN,
+				     DMA_FROM_DEVICE);
+	if (err)
+		return err;
+
+	if (edtl > iser_ctask->data[ISER_DIR_IN].data_len) {
+		iser_err("Total data length: %ld, less than EDTL: "
+			 "%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
+			 iser_ctask->data[ISER_DIR_IN].data_len, edtl,
+			 ctask->itt, iser_ctask->iser_conn);
+		return -EINVAL;
+	}
+
+	err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_IN);
+	if (err) {
+		iser_err("Failed to set up Data-IN RDMA\n");
+		return err;
+	}
+	regd_buf = &iser_ctask->rdma_regd[ISER_DIR_IN];
+
+	hdr->flags    |= ISER_RSV;
+	hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey);
+	hdr->read_va   = cpu_to_be64(regd_buf->reg.va);
+
+	iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n",
+		 ctask->itt, regd_buf->reg.rkey,
+		 (unsigned long long)regd_buf->reg.va);
+
+	return 0;
+}
+
+/* Register user buffer memory and initialize passive rdma
+ *  dto descriptor. Total data size is stored in
+ *  ctask->data[ISER_DIR_OUT].data_len
+ */
+static int
+iser_prepare_write_cmd(struct iscsi_cmd_task *ctask,
+		       unsigned int imm_sz,
+		       unsigned int unsol_sz,
+		       unsigned int edtl)
+{
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+	struct iser_regd_buf *regd_buf;
+	int err;
+	struct iser_dto *send_dto = &iser_ctask->desc.dto;
+	struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
+	struct iser_data_buf *buf_out = &iser_ctask->data[ISER_DIR_OUT];
+
+	err = iser_dma_map_task_data(iser_ctask,
+				     buf_out,
+				     ISER_DIR_OUT,
+				     DMA_TO_DEVICE);
+	if (err)
+		return err;
+
+	if (edtl > iser_ctask->data[ISER_DIR_OUT].data_len) {
+		iser_err("Total data length: %ld, less than EDTL: %d, "
+			 "in WRITE cmd BHS itt: %d, conn: 0x%p\n",
+			 iser_ctask->data[ISER_DIR_OUT].data_len,
+			 edtl, ctask->itt, ctask->conn);
+		return -EINVAL;
+	}
+
+	err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_OUT);
+	if (err != 0) {
+		iser_err("Failed to register write cmd RDMA mem\n");
+		return err;
+	}
+
+	regd_buf = &iser_ctask->rdma_regd[ISER_DIR_OUT];
+
+	if (unsol_sz < edtl) {
+		hdr->flags     |= ISER_WSV;
+		hdr->write_stag = cpu_to_be32(regd_buf->reg.rkey);
+		hdr->write_va   = cpu_to_be64(regd_buf->reg.va + unsol_sz);
+
+		iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X "
+			 "VA:%#llX + unsol:%d\n",
+			 ctask->itt, regd_buf->reg.rkey,
+			 (unsigned long long)regd_buf->reg.va, unsol_sz);
+	}
+
+	if (imm_sz > 0) {
+		iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",
+			 ctask->itt, imm_sz);
+		iser_dto_add_regd_buff(send_dto,
+				       regd_buf,
+				       0,
+				       imm_sz);
+	}
+
+	return 0;
+}
+
+/**
+ * iser_post_receive_control - allocates, initializes and posts receive DTO.
+ */
+static int iser_post_receive_control(struct iscsi_conn *conn)
+{
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+	struct iser_desc     *rx_desc;
+	struct iser_regd_buf *regd_hdr;
+	struct iser_regd_buf *regd_data;
+	struct iser_dto      *recv_dto = NULL;
+	struct iser_device  *device = iser_conn->ib_conn->device;
+	int rx_data_size, err = 0;
+
+	rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
+	if (rx_desc == NULL) {
+		iser_err("Failed to alloc desc for post recv\n");
+		return -ENOMEM;
+	}
+	rx_desc->type = ISCSI_RX;
+
+	/* for the login sequence we must support rx of upto 8K; login is done
+	 * after conn create/bind (connect) and conn stop/bind (reconnect),
+	 * what's common for both schemes is that the connection is not started
+	 */
+	if (conn->c_stage != ISCSI_CONN_STARTED)
+		rx_data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+	else /* FIXME till user space sets conn->max_recv_dlength correctly */
+		rx_data_size = 128;
+
+	rx_desc->data = kmalloc(rx_data_size, GFP_NOIO);
+	if (rx_desc->data == NULL) {
+		iser_err("Failed to alloc data buf for post recv\n");
+		err = -ENOMEM;
+		goto post_rx_kmalloc_failure;
+	}
+
+	recv_dto = &rx_desc->dto;
+	recv_dto->conn          = iser_conn;
+	recv_dto->regd_vector_len = 0;
+
+	regd_hdr = &rx_desc->hdr_regd_buf;
+	memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
+	regd_hdr->device  = device;
+	regd_hdr->virt_addr  = rx_desc; /* == &rx_desc->iser_header */
+	regd_hdr->data_size  = ISER_TOTAL_HEADERS_LEN;
+
+	iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE);
+
+	iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0);
+
+	regd_data = &rx_desc->data_regd_buf;
+	memset(regd_data, 0, sizeof(struct iser_regd_buf));
+	regd_data->device  = device;
+	regd_data->virt_addr  = rx_desc->data;
+	regd_data->data_size  = rx_data_size;
+
+	iser_reg_single(device, regd_data, DMA_FROM_DEVICE);
+
+	iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0);
+
+	err = iser_post_recv(rx_desc);
+	if (!err)
+		return 0;
+
+	/* iser_post_recv failed */
+	iser_dto_buffs_release(recv_dto);
+	kfree(rx_desc->data);
+post_rx_kmalloc_failure:
+	kmem_cache_free(ig.desc_cache, rx_desc);
+	return err;
+}
+
+/* creates a new tx descriptor and adds header regd buffer */
+static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn,
+				  struct iser_desc       *tx_desc)
+{
+	struct iser_regd_buf *regd_hdr = &tx_desc->hdr_regd_buf;
+	struct iser_dto      *send_dto = &tx_desc->dto;
+
+	memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
+	regd_hdr->device  = iser_conn->ib_conn->device;
+	regd_hdr->virt_addr  = tx_desc; /* == &tx_desc->iser_header */
+	regd_hdr->data_size  = ISER_TOTAL_HEADERS_LEN;
+
+	send_dto->conn          = iser_conn;
+	send_dto->notify_enable   = 1;
+	send_dto->regd_vector_len = 0;
+
+	memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
+	tx_desc->iser_header.flags = ISER_VER;
+
+	iser_dto_add_regd_buff(send_dto, regd_hdr, 0, 0);
+}
+
+/**
+ *  iser_conn_set_full_featured_mode - (iSER API)
+ */
+int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
+{
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+	int i;
+	/* no need to keep it in a var, we are after login so if this should
+	 * be negotiated, by now the result should be available here */
+	int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS;
+
+	iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num);
+
+	/* Check that there is no posted recv or send buffers left - */
+	/* they must be consumed during the login phase */
+	BUG_ON(atomic_read(&iser_conn->ib_conn->post_recv_buf_count) != 0);
+	BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
+
+	/* Initial post receive buffers */
+	for (i = 0; i < initial_post_recv_bufs_num; i++) {
+		if (iser_post_receive_control(conn) != 0) {
+			iser_err("Failed to post recv bufs at:%d conn:0x%p\n",
+				 i, conn);
+			return -ENOMEM;
+		}
+	}
+	iser_dbg("Posted %d post recv bufs, conn:0x%p\n", i, conn);
+	return 0;
+}
+
+static int
+iser_check_xmit(struct iscsi_conn *conn, void *task)
+{
+	int rc = 0;
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+	write_lock_bh(conn->recv_lock);
+	if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
+	    ISER_QP_MAX_REQ_DTOS) {
+		iser_dbg("%ld can't xmit task %p, suspending tx\n",jiffies,task);
+		set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+		rc = -EAGAIN;
+	}
+	write_unlock_bh(conn->recv_lock);
+	return rc;
+}
+
+
+/**
+ * iser_send_command - send command PDU
+ */
+int iser_send_command(struct iscsi_conn     *conn,
+		      struct iscsi_cmd_task *ctask)
+{
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+	struct iser_dto *send_dto = NULL;
+	unsigned long edtl;
+	int err = 0;
+	struct iser_data_buf *data_buf;
+
+	struct iscsi_cmd *hdr =  ctask->hdr;
+	struct scsi_cmnd *sc  =  ctask->sc;
+
+	if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
+		iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
+		return -EPERM;
+	}
+	if (iser_check_xmit(conn, ctask))
+		return -EAGAIN;
+
+	edtl = ntohl(hdr->data_length);
+
+	/* build the tx desc regd header and add it to the tx desc dto */
+	iser_ctask->desc.type = ISCSI_TX_SCSI_COMMAND;
+	send_dto = &iser_ctask->desc.dto;
+	send_dto->ctask = iser_ctask;
+	iser_create_send_desc(iser_conn, &iser_ctask->desc);
+
+	if (hdr->flags & ISCSI_FLAG_CMD_READ)
+		data_buf = &iser_ctask->data[ISER_DIR_IN];
+	else
+		data_buf = &iser_ctask->data[ISER_DIR_OUT];
+
+	if (sc->use_sg) { /* using a scatter list */
+		data_buf->buf  = sc->request_buffer;
+		data_buf->size = sc->use_sg;
+	} else if (sc->request_bufflen) {
+		/* using a single buffer - convert it into one entry SG */
+		sg_init_one(&data_buf->sg_single,
+			    sc->request_buffer, sc->request_bufflen);
+		data_buf->buf   = &data_buf->sg_single;
+		data_buf->size  = 1;
+	}
+
+	data_buf->data_len = sc->request_bufflen;
+
+	if (hdr->flags & ISCSI_FLAG_CMD_READ) {
+		err = iser_prepare_read_cmd(ctask, edtl);
+		if (err)
+			goto send_command_error;
+	}
+	if (hdr->flags & ISCSI_FLAG_CMD_WRITE) {
+		err = iser_prepare_write_cmd(ctask,
+					     ctask->imm_count,
+				             ctask->imm_count +
+					     ctask->unsol_count,
+					     edtl);
+		if (err)
+			goto send_command_error;
+	}
+
+	iser_reg_single(iser_conn->ib_conn->device,
+			send_dto->regd[0], DMA_TO_DEVICE);
+
+	if (iser_post_receive_control(conn) != 0) {
+		iser_err("post_recv failed!\n");
+		err = -ENOMEM;
+		goto send_command_error;
+	}
+
+	iser_ctask->status = ISER_TASK_STATUS_STARTED;
+
+	err = iser_post_send(&iser_ctask->desc);
+	if (!err)
+		return 0;
+
+send_command_error:
+	iser_dto_buffs_release(send_dto);
+	iser_err("conn %p failed ctask->itt %d err %d\n",conn, ctask->itt, err);
+	return err;
+}
+
+/**
+ * iser_send_data_out - send data out PDU
+ */
+int iser_send_data_out(struct iscsi_conn     *conn,
+		       struct iscsi_cmd_task *ctask,
+		       struct iscsi_data *hdr)
+{
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+	struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+	struct iser_desc *tx_desc = NULL;
+	struct iser_dto *send_dto = NULL;
+	unsigned long buf_offset;
+	unsigned long data_seg_len;
+	unsigned int itt;
+	int err = 0;
+
+	if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
+		iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
+		return -EPERM;
+	}
+
+	if (iser_check_xmit(conn, ctask))
+		return -EAGAIN;
+
+	itt = ntohl(hdr->itt);
+	data_seg_len = ntoh24(hdr->dlength);
+	buf_offset   = ntohl(hdr->offset);
+
+	iser_dbg("%s itt %d dseg_len %d offset %d\n",
+		 __func__,(int)itt,(int)data_seg_len,(int)buf_offset);
+
+	tx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
+	if (tx_desc == NULL) {
+		iser_err("Failed to alloc desc for post dataout\n");
+		return -ENOMEM;
+	}
+
+	tx_desc->type = ISCSI_TX_DATAOUT;
+	memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr));
+
+	/* build the tx desc regd header and add it to the tx desc dto */
+	send_dto = &tx_desc->dto;
+	send_dto->ctask = iser_ctask;
+	iser_create_send_desc(iser_conn, tx_desc);
+
+	iser_reg_single(iser_conn->ib_conn->device,
+			send_dto->regd[0], DMA_TO_DEVICE);
+
+	/* all data was registered for RDMA, we can use the lkey */
+	iser_dto_add_regd_buff(send_dto,
+			       &iser_ctask->rdma_regd[ISER_DIR_OUT],
+			       buf_offset,
+			       data_seg_len);
+
+	if (buf_offset + data_seg_len > iser_ctask->data[ISER_DIR_OUT].data_len) {
+		iser_err("Offset:%ld & DSL:%ld in Data-Out "
+			 "inconsistent with total len:%ld, itt:%d\n",
+			 buf_offset, data_seg_len,
+			 iser_ctask->data[ISER_DIR_OUT].data_len, itt);
+		err = -EINVAL;
+		goto send_data_out_error;
+	}
+	iser_dbg("data-out itt: %d, offset: %ld, sz: %ld\n",
+		 itt, buf_offset, data_seg_len);
+
+
+	err = iser_post_send(tx_desc);
+	if (!err)
+		return 0;
+
+send_data_out_error:
+	iser_dto_buffs_release(send_dto);
+	kmem_cache_free(ig.desc_cache, tx_desc);
+	iser_err("conn %p failed err %d\n",conn, err);
+	return err;
+}
+
+int iser_send_control(struct iscsi_conn *conn,
+		      struct iscsi_mgmt_task *mtask)
+{
+	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+	struct iser_desc *mdesc = mtask->dd_data;
+	struct iser_dto *send_dto = NULL;
+	unsigned int itt;
+	unsigned long data_seg_len;
+	int err = 0;
+	unsigned char opcode;
+	struct iser_regd_buf *regd_buf;
+	struct iser_device *device;
+
+	if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
+		iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
+		return -EPERM;
+	}
+
+	if (iser_check_xmit(conn,mtask))
+		return -EAGAIN;
+
+	/* build the tx desc regd header and add it to the tx desc dto */
+	mdesc->type = ISCSI_TX_CONTROL;
+	send_dto = &mdesc->dto;
+	send_dto->ctask = NULL;
+	iser_create_send_desc(iser_conn, mdesc);
+
+	device = iser_conn->ib_conn->device;
+
+	iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
+
+	itt = ntohl(mtask->hdr->itt);
+	opcode = mtask->hdr->opcode & ISCSI_OPCODE_MASK;
+	data_seg_len = ntoh24(mtask->hdr->dlength);
+
+	if (data_seg_len > 0) {
+		regd_buf = &mdesc->data_regd_buf;
+		memset(regd_buf, 0, sizeof(struct iser_regd_buf));
+		regd_buf->device = device;
+		regd_buf->virt_addr = mtask->data;
+		regd_buf->data_size = mtask->data_count;
+		iser_reg_single(device, regd_buf,
+				DMA_TO_DEVICE);
+		iser_dto_add_regd_buff(send_dto, regd_buf,
+				       0,
+				       data_seg_len);
+	}
+
+	if (iser_post_receive_control(conn) != 0) {
+		iser_err("post_rcv_buff failed!\n");
+		err = -ENOMEM;
+		goto send_control_error;
+	}
+
+	err = iser_post_send(mdesc);
+	if (!err)
+		return 0;
+
+send_control_error:
+	iser_dto_buffs_release(send_dto);
+	iser_err("conn %p failed err %d\n",conn, err);
+	return err;
+}
+
+/**
+ * iser_rcv_dto_completion - recv DTO completion
+ */
+void iser_rcv_completion(struct iser_desc *rx_desc,
+			 unsigned long dto_xfer_len)
+{
+	struct iser_dto        *dto = &rx_desc->dto;
+	struct iscsi_iser_conn *conn = dto->conn;
+	struct iscsi_session *session = conn->iscsi_conn->session;
+	struct iscsi_cmd_task *ctask;
+	struct iscsi_iser_cmd_task *iser_ctask;
+	struct iscsi_hdr *hdr;
+	char   *rx_data = NULL;
+	int     rx_data_len = 0;
+	unsigned int itt;
+	unsigned char opcode;
+
+	hdr = &rx_desc->iscsi_header;
+
+	iser_dbg("op 0x%x itt 0x%x\n", hdr->opcode,hdr->itt);
+
+	if (dto_xfer_len > ISER_TOTAL_HEADERS_LEN) { /* we have data */
+		rx_data_len = dto_xfer_len - ISER_TOTAL_HEADERS_LEN;
+		rx_data     = dto->regd[1]->virt_addr;
+		rx_data    += dto->offset[1];
+	}
+
+	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
+
+	if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
+	        itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */
+		if (!(itt < session->cmds_max))
+			iser_err("itt can't be matched to task!!!"
+				 "conn %p opcode %d cmds_max %d itt %d\n",
+				 conn->iscsi_conn,opcode,session->cmds_max,itt);
+		/* use the mapping given with the cmds array indexed by itt */
+		ctask = (struct iscsi_cmd_task *)session->cmds[itt];
+		iser_ctask = ctask->dd_data;
+		iser_dbg("itt %d ctask %p\n",itt,ctask);
+		iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
+		iser_ctask_rdma_finalize(iser_ctask);
+	}
+
+	iser_dto_buffs_release(dto);
+
+	iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len);
+
+	kfree(rx_desc->data);
+	kmem_cache_free(ig.desc_cache, rx_desc);
+
+	/* decrementing conn->post_recv_buf_count only --after-- freeing the   *
+	 * task eliminates the need to worry on tasks which are completed in   *
+	 * parallel to the execution of iser_conn_term. So the code that waits *
+	 * for the posted rx bufs refcount to become zero handles everything   */
+	atomic_dec(&conn->ib_conn->post_recv_buf_count);
+}
+
+void iser_snd_completion(struct iser_desc *tx_desc)
+{
+	struct iser_dto        *dto = &tx_desc->dto;
+	struct iscsi_iser_conn *iser_conn = dto->conn;
+	struct iscsi_conn      *conn = iser_conn->iscsi_conn;
+	struct iscsi_mgmt_task *mtask;
+
+	iser_dbg("Initiator, Data sent dto=0x%p\n", dto);
+
+	iser_dto_buffs_release(dto);
+
+	if (tx_desc->type == ISCSI_TX_DATAOUT)
+		kmem_cache_free(ig.desc_cache, tx_desc);
+
+	atomic_dec(&iser_conn->ib_conn->post_send_buf_count);
+
+	write_lock(conn->recv_lock);
+	if (conn->suspend_tx) {
+		iser_dbg("%ld resuming tx\n",jiffies);
+		clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+		scsi_queue_work(conn->session->host, &conn->xmitwork);
+	}
+	write_unlock(conn->recv_lock);
+
+	if (tx_desc->type == ISCSI_TX_CONTROL) {
+		/* this arithmetic is legal by libiscsi dd_data allocation */
+		mtask = (void *) ((long)(void *)tx_desc -
+				  sizeof(struct iscsi_mgmt_task));
+		if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+			struct iscsi_session *session = conn->session;
+
+			spin_lock(&conn->session->lock);
+			list_del(&mtask->running);
+			__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+				    sizeof(void*));
+			spin_unlock(&session->lock);
+		}
+	}
+}
+
+void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *iser_ctask)
+
+{
+	iser_ctask->status = ISER_TASK_STATUS_INIT;
+
+	iser_ctask->dir[ISER_DIR_IN] = 0;
+	iser_ctask->dir[ISER_DIR_OUT] = 0;
+
+	iser_ctask->data[ISER_DIR_IN].data_len  = 0;
+	iser_ctask->data[ISER_DIR_OUT].data_len = 0;
+
+	memset(&iser_ctask->rdma_regd[ISER_DIR_IN], 0,
+	       sizeof(struct iser_regd_buf));
+	memset(&iser_ctask->rdma_regd[ISER_DIR_OUT], 0,
+	       sizeof(struct iser_regd_buf));
+}
+
+void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
+{
+	int deferred;
+
+	/* if we were reading, copy back to unaligned sglist,
+	 * anyway dma_unmap and free the copy
+	 */
+	if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL)
+		iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN);
+	if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL)
+		iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT);
+
+	if (iser_ctask->dir[ISER_DIR_IN]) {
+		deferred = iser_regd_buff_release
+			(&iser_ctask->rdma_regd[ISER_DIR_IN]);
+		if (deferred) {
+			iser_err("References remain for BUF-IN rdma reg\n");
+			BUG();
+		}
+	}
+
+	if (iser_ctask->dir[ISER_DIR_OUT]) {
+		deferred = iser_regd_buff_release
+			(&iser_ctask->rdma_regd[ISER_DIR_OUT]);
+		if (deferred) {
+			iser_err("References remain for BUF-OUT rdma reg\n");
+			BUG();
+		}
+	}
+
+	iser_dma_unmap_task_data(iser_ctask);
+}
+
+void iser_dto_buffs_release(struct iser_dto *dto)
+{
+	int i;
+
+	for (i = 0; i < dto->regd_vector_len; i++)
+		iser_regd_buff_release(dto->regd[i]);
+}
+
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
new file mode 100644
index 0000000..31950a5
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *	- Redistributions of source code must retain the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer.
+ *
+ *	- Redistributions in binary form must reproduce the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer in the documentation and/or other materials
+ *	  provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iser_memory.c 6964 2006-05-07 11:11:43Z ogerlitz $
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include "iscsi_iser.h"
+
+#define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */
+/**
+ * Decrements the reference count for the
+ * registered buffer & releases it
+ *
+ * returns 0 if released, 1 if deferred
+ */
+int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
+{
+	struct device *dma_device;
+
+	if ((atomic_read(&regd_buf->ref_count) == 0) ||
+	    atomic_dec_and_test(&regd_buf->ref_count)) {
+		/* if we used the dma mr, unreg is just NOP */
+		if (regd_buf->reg.rkey != 0)
+			iser_unreg_mem(&regd_buf->reg);
+
+		if (regd_buf->dma_addr) {
+			dma_device = regd_buf->device->ib_device->dma_device;
+			dma_unmap_single(dma_device,
+					 regd_buf->dma_addr,
+					 regd_buf->data_size,
+					 regd_buf->direction);
+		}
+		/* else this regd buf is associated with task which we */
+		/* dma_unmap_single/sg later */
+		return 0;
+	} else {
+		iser_dbg("Release deferred, regd.buff: 0x%p\n", regd_buf);
+		return 1;
+	}
+}
+
+/**
+ * iser_reg_single - fills registered buffer descriptor with
+ *		     registration information
+ */
+void iser_reg_single(struct iser_device *device,
+		     struct iser_regd_buf *regd_buf,
+		     enum dma_data_direction direction)
+{
+	dma_addr_t dma_addr;
+
+	dma_addr  = dma_map_single(device->ib_device->dma_device,
+				   regd_buf->virt_addr,
+				   regd_buf->data_size, direction);
+	BUG_ON(dma_mapping_error(dma_addr));
+
+	regd_buf->reg.lkey = device->mr->lkey;
+	regd_buf->reg.rkey = 0; /* indicate there's no need to unreg */
+	regd_buf->reg.len  = regd_buf->data_size;
+	regd_buf->reg.va   = dma_addr;
+
+	regd_buf->dma_addr  = dma_addr;
+	regd_buf->direction = direction;
+}
+
+/**
+ * iser_start_rdma_unaligned_sg
+ */
+int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task  *iser_ctask,
+				 enum iser_data_dir cmd_dir)
+{
+	int dma_nents;
+	struct device *dma_device;
+	char *mem = NULL;
+	struct iser_data_buf *data = &iser_ctask->data[cmd_dir];
+	unsigned long  cmd_data_len = data->data_len;
+
+	if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
+		mem = (void *)__get_free_pages(GFP_NOIO,
+		      long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+	else
+		mem = kmalloc(cmd_data_len, GFP_NOIO);
+
+	if (mem == NULL) {
+		iser_err("Failed to allocate mem size %d %d for copying sglist\n",
+			 data->size,(int)cmd_data_len);
+		return -ENOMEM;
+	}
+
+	if (cmd_dir == ISER_DIR_OUT) {
+		/* copy the unaligned sg the buffer which is used for RDMA */
+		struct scatterlist *sg = (struct scatterlist *)data->buf;
+		int i;
+		char *p, *from;
+
+		for (p = mem, i = 0; i < data->size; i++) {
+			from = kmap_atomic(sg[i].page, KM_USER0);
+			memcpy(p,
+			       from + sg[i].offset,
+			       sg[i].length);
+			kunmap_atomic(from, KM_USER0);
+			p += sg[i].length;
+		}
+	}
+
+	sg_init_one(&iser_ctask->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
+	iser_ctask->data_copy[cmd_dir].buf  =
+		&iser_ctask->data_copy[cmd_dir].sg_single;
+	iser_ctask->data_copy[cmd_dir].size = 1;
+
+	iser_ctask->data_copy[cmd_dir].copy_buf  = mem;
+
+	dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+	if (cmd_dir == ISER_DIR_OUT)
+		dma_nents = dma_map_sg(dma_device,
+				       &iser_ctask->data_copy[cmd_dir].sg_single,
+				       1, DMA_TO_DEVICE);
+	else
+		dma_nents = dma_map_sg(dma_device,
+				       &iser_ctask->data_copy[cmd_dir].sg_single,
+				       1, DMA_FROM_DEVICE);
+
+	BUG_ON(dma_nents == 0);
+
+	iser_ctask->data_copy[cmd_dir].dma_nents = dma_nents;
+	return 0;
+}
+
+/**
+ * iser_finalize_rdma_unaligned_sg
+ */
+void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+				     enum iser_data_dir         cmd_dir)
+{
+	struct device *dma_device;
+	struct iser_data_buf *mem_copy;
+	unsigned long  cmd_data_len;
+
+	dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+	mem_copy   = &iser_ctask->data_copy[cmd_dir];
+
+	if (cmd_dir == ISER_DIR_OUT)
+		dma_unmap_sg(dma_device, &mem_copy->sg_single, 1,
+			     DMA_TO_DEVICE);
+	else
+		dma_unmap_sg(dma_device, &mem_copy->sg_single, 1,
+			     DMA_FROM_DEVICE);
+
+	if (cmd_dir == ISER_DIR_IN) {
+		char *mem;
+		struct scatterlist *sg;
+		unsigned char *p, *to;
+		unsigned int sg_size;
+		int i;
+
+		/* copy back read RDMA to unaligned sg */
+		mem	= mem_copy->copy_buf;
+
+		sg	= (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf;
+		sg_size = iser_ctask->data[ISER_DIR_IN].size;
+
+		for (p = mem, i = 0; i < sg_size; i++){
+			to = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
+			memcpy(to + sg[i].offset,
+			       p,
+			       sg[i].length);
+			kunmap_atomic(to, KM_SOFTIRQ0);
+			p += sg[i].length;
+		}
+	}
+
+	cmd_data_len = iser_ctask->data[cmd_dir].data_len;
+
+	if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
+		free_pages((unsigned long)mem_copy->copy_buf,
+			   long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+	else
+		kfree(mem_copy->copy_buf);
+
+	mem_copy->copy_buf = NULL;
+}
+
+/**
+ * iser_sg_to_page_vec - Translates scatterlist entries to physical addresses
+ * and returns the length of resulting physical address array (may be less than
+ * the original due to possible compaction).
+ *
+ * we build a "page vec" under the assumption that the SG meets the RDMA
+ * alignment requirements. Other then the first and last SG elements, all
+ * the "internal" elements can be compacted into a list whose elements are
+ * dma addresses of physical pages. The code supports also the weird case
+ * where --few fragments of the same page-- are present in the SG as
+ * consecutive elements. Also, it handles one entry SG.
+ */
+static int iser_sg_to_page_vec(struct iser_data_buf *data,
+			       struct iser_page_vec *page_vec)
+{
+	struct scatterlist *sg = (struct scatterlist *)data->buf;
+	dma_addr_t first_addr, last_addr, page;
+	int start_aligned, end_aligned;
+	unsigned int cur_page = 0;
+	unsigned long total_sz = 0;
+	int i;
+
+	/* compute the offset of first element */
+	page_vec->offset = (u64) sg[0].offset;
+
+	for (i = 0; i < data->dma_nents; i++) {
+		total_sz += sg_dma_len(&sg[i]);
+
+		first_addr = sg_dma_address(&sg[i]);
+		last_addr  = first_addr + sg_dma_len(&sg[i]);
+
+		start_aligned = !(first_addr & ~PAGE_MASK);
+		end_aligned   = !(last_addr  & ~PAGE_MASK);
+
+		/* continue to collect page fragments till aligned or SG ends */
+		while (!end_aligned && (i + 1 < data->dma_nents)) {
+			i++;
+			total_sz += sg_dma_len(&sg[i]);
+			last_addr = sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]);
+			end_aligned = !(last_addr  & ~PAGE_MASK);
+		}
+
+		first_addr = first_addr & PAGE_MASK;
+
+		for (page = first_addr; page < last_addr; page += PAGE_SIZE)
+			page_vec->pages[cur_page++] = page;
+
+	}
+	page_vec->data_size = total_sz;
+	iser_dbg("page_vec->data_size:%d cur_page %d\n", page_vec->data_size,cur_page);
+	return cur_page;
+}
+
+#define MASK_4K			((1UL << 12) - 1) /* 0xFFF */
+#define IS_4K_ALIGNED(addr)	((((unsigned long)addr) & MASK_4K) == 0)
+
+/**
+ * iser_data_buf_aligned_len - Tries to determine the maximal correctly aligned
+ * for RDMA sub-list of a scatter-gather list of memory buffers, and  returns
+ * the number of entries which are aligned correctly. Supports the case where
+ * consecutive SG elements are actually fragments of the same physcial page.
+ */
+static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data)
+{
+	struct scatterlist *sg;
+	dma_addr_t end_addr, next_addr;
+	int i, cnt;
+	unsigned int ret_len = 0;
+
+	sg = (struct scatterlist *)data->buf;
+
+	for (cnt = 0, i = 0; i < data->dma_nents; i++, cnt++) {
+		/* iser_dbg("Checking sg iobuf [%d]: phys=0x%08lX "
+		   "offset: %ld sz: %ld\n", i,
+		   (unsigned long)page_to_phys(sg[i].page),
+		   (unsigned long)sg[i].offset,
+		   (unsigned long)sg[i].length); */
+		end_addr = sg_dma_address(&sg[i]) +
+			   sg_dma_len(&sg[i]);
+		/* iser_dbg("Checking sg iobuf end address "
+		       "0x%08lX\n", end_addr); */
+		if (i + 1 < data->dma_nents) {
+			next_addr = sg_dma_address(&sg[i+1]);
+			/* are i, i+1 fragments of the same page? */
+			if (end_addr == next_addr)
+				continue;
+			else if (!IS_4K_ALIGNED(end_addr)) {
+				ret_len = cnt + 1;
+				break;
+			}
+		}
+	}
+	if (i == data->dma_nents)
+		ret_len = cnt;	/* loop ended */
+	iser_dbg("Found %d aligned entries out of %d in sg:0x%p\n",
+		 ret_len, data->dma_nents, data);
+	return ret_len;
+}
+
+static void iser_data_buf_dump(struct iser_data_buf *data)
+{
+	struct scatterlist *sg = (struct scatterlist *)data->buf;
+	int i;
+
+	for (i = 0; i < data->size; i++)
+		iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
+			 "off:%d sz:%d dma_len:%d\n",
+			 i, (unsigned long)sg_dma_address(&sg[i]),
+			 sg[i].page, sg[i].offset,
+			 sg[i].length,sg_dma_len(&sg[i]));
+}
+
+static void iser_dump_page_vec(struct iser_page_vec *page_vec)
+{
+	int i;
+
+	iser_err("page vec length %d data size %d\n",
+		 page_vec->length, page_vec->data_size);
+	for (i = 0; i < page_vec->length; i++)
+		iser_err("%d %lx\n",i,(unsigned long)page_vec->pages[i]);
+}
+
+static void iser_page_vec_build(struct iser_data_buf *data,
+				struct iser_page_vec *page_vec)
+{
+	int page_vec_len = 0;
+
+	page_vec->length = 0;
+	page_vec->offset = 0;
+
+	iser_dbg("Translating sg sz: %d\n", data->dma_nents);
+	page_vec_len = iser_sg_to_page_vec(data,page_vec);
+	iser_dbg("sg len %d page_vec_len %d\n", data->dma_nents,page_vec_len);
+
+	page_vec->length = page_vec_len;
+
+	if (page_vec_len * PAGE_SIZE < page_vec->data_size) {
+		iser_err("page_vec too short to hold this SG\n");
+		iser_data_buf_dump(data);
+		iser_dump_page_vec(page_vec);
+		BUG();
+	}
+}
+
+/**
+ * iser_reg_rdma_mem - Registers memory intended for RDMA,
+ * obtaining rkey and va
+ *
+ * returns 0 on success, errno code on failure
+ */
+int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
+		      enum   iser_data_dir        cmd_dir)
+{
+	struct iser_conn     *ib_conn = iser_ctask->iser_conn->ib_conn;
+	struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
+	struct iser_regd_buf *regd_buf;
+	int aligned_len;
+	int err;
+
+	regd_buf = &iser_ctask->rdma_regd[cmd_dir];
+
+	aligned_len = iser_data_buf_aligned_len(mem);
+	if (aligned_len != mem->size) {
+		iser_err("rdma alignment violation %d/%d aligned\n",
+			 aligned_len, mem->size);
+		iser_data_buf_dump(mem);
+		/* allocate copy buf, if we are writing, copy the */
+		/* unaligned scatterlist, dma map the copy        */
+		if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
+				return -ENOMEM;
+		mem = &iser_ctask->data_copy[cmd_dir];
+	}
+
+	iser_page_vec_build(mem, ib_conn->page_vec);
+	err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, &regd_buf->reg);
+	if (err)
+		return err;
+
+	/* take a reference on this regd buf such that it will not be released *
+	 * (eg in send dto completion) before we get the scsi response         */
+	atomic_inc(&regd_buf->ref_count);
+	return 0;
+}
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
new file mode 100644
index 0000000..ff117bb
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -0,0 +1,827 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *	- Redistributions of source code must retain the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer.
+ *
+ *	- Redistributions in binary form must reproduce the above
+ *	  copyright notice, this list of conditions and the following
+ *	  disclaimer in the documentation and/or other materials
+ *	  provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
+ */
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+#include "iscsi_iser.h"
+
+#define ISCSI_ISER_MAX_CONN	8
+#define ISER_MAX_CQ_LEN		((ISER_QP_MAX_RECV_DTOS + \
+				ISER_QP_MAX_REQ_DTOS) *   \
+				 ISCSI_ISER_MAX_CONN)
+
+static void iser_cq_tasklet_fn(unsigned long data);
+static void iser_cq_callback(struct ib_cq *cq, void *cq_context);
+static void iser_comp_error_worker(void *data);
+
+static void iser_cq_event_callback(struct ib_event *cause, void *context)
+{
+	iser_err("got cq event %d \n", cause->event);
+}
+
+static void iser_qp_event_callback(struct ib_event *cause, void *context)
+{
+	iser_err("got qp event %d\n",cause->event);
+}
+
+/**
+ * iser_create_device_ib_res - creates Protection Domain (PD), Completion
+ * Queue (CQ), DMA Memory Region (DMA MR) with the device associated with
+ * the adapator.
+ *
+ * returns 0 on success, -1 on failure
+ */
+static int iser_create_device_ib_res(struct iser_device *device)
+{
+	device->pd = ib_alloc_pd(device->ib_device);
+	if (IS_ERR(device->pd))
+		goto pd_err;
+
+	device->cq = ib_create_cq(device->ib_device,
+				  iser_cq_callback,
+				  iser_cq_event_callback,
+				  (void *)device,
+				  ISER_MAX_CQ_LEN);
+	if (IS_ERR(device->cq))
+		goto cq_err;
+
+	if (ib_req_notify_cq(device->cq, IB_CQ_NEXT_COMP))
+		goto cq_arm_err;
+
+	tasklet_init(&device->cq_tasklet,
+		     iser_cq_tasklet_fn,
+		     (unsigned long)device);
+
+	device->mr = ib_get_dma_mr(device->pd,
+				   IB_ACCESS_LOCAL_WRITE);
+	if (IS_ERR(device->mr))
+		goto dma_mr_err;
+
+	return 0;
+
+dma_mr_err:
+	tasklet_kill(&device->cq_tasklet);
+cq_arm_err:
+	ib_destroy_cq(device->cq);
+cq_err:
+	ib_dealloc_pd(device->pd);
+pd_err:
+	iser_err("failed to allocate an IB resource\n");
+	return -1;
+}
+
+/**
+ * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR,
+ * CQ and PD created with the device associated with the adapator.
+ */
+static void iser_free_device_ib_res(struct iser_device *device)
+{
+	BUG_ON(device->mr == NULL);
+
+	tasklet_kill(&device->cq_tasklet);
+
+	(void)ib_dereg_mr(device->mr);
+	(void)ib_destroy_cq(device->cq);
+	(void)ib_dealloc_pd(device->pd);
+
+	device->mr = NULL;
+	device->cq = NULL;
+	device->pd = NULL;
+}
+
+/**
+ * iser_create_ib_conn_res - Creates FMR pool and Queue-Pair (QP)
+ *
+ * returns 0 on success, -1 on failure
+ */
+static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
+{
+	struct iser_device	*device;
+	struct ib_qp_init_attr	init_attr;
+	int			ret;
+	struct ib_fmr_pool_param params;
+
+	BUG_ON(ib_conn->device == NULL);
+
+	device = ib_conn->device;
+
+	ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) +
+				    (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)),
+				    GFP_KERNEL);
+	if (!ib_conn->page_vec) {
+		ret = -ENOMEM;
+		goto alloc_err;
+	}
+	ib_conn->page_vec->pages = (u64 *) (ib_conn->page_vec + 1);
+
+	params.page_shift        = PAGE_SHIFT;
+	/* when the first/last SG element are not start/end *
+	 * page aligned, the map whould be of N+1 pages     */
+	params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1;
+	/* make the pool size twice the max number of SCSI commands *
+	 * the ML is expected to queue, watermark for unmap at 50%  */
+	params.pool_size	 = ISCSI_XMIT_CMDS_MAX * 2;
+	params.dirty_watermark	 = ISCSI_XMIT_CMDS_MAX;
+	params.cache		 = 0;
+	params.flush_function	 = NULL;
+	params.access		 = (IB_ACCESS_LOCAL_WRITE  |
+				    IB_ACCESS_REMOTE_WRITE |
+				    IB_ACCESS_REMOTE_READ);
+
+	ib_conn->fmr_pool = ib_create_fmr_pool(device->pd, &params);
+	if (IS_ERR(ib_conn->fmr_pool)) {
+		ret = PTR_ERR(ib_conn->fmr_pool);
+		goto fmr_pool_err;
+	}
+
+	memset(&init_attr, 0, sizeof init_attr);
+
+	init_attr.event_handler = iser_qp_event_callback;
+	init_attr.qp_context	= (void *)ib_conn;
+	init_attr.send_cq	= device->cq;
+	init_attr.recv_cq	= device->cq;
+	init_attr.cap.max_send_wr  = ISER_QP_MAX_REQ_DTOS;
+	init_attr.cap.max_recv_wr  = ISER_QP_MAX_RECV_DTOS;
+	init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN;
+	init_attr.cap.max_recv_sge = 2;
+	init_attr.sq_sig_type	= IB_SIGNAL_REQ_WR;
+	init_attr.qp_type	= IB_QPT_RC;
+
+	ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr);
+	if (ret)
+		goto qp_err;
+
+	ib_conn->qp = ib_conn->cma_id->qp;
+	iser_err("setting conn %p cma_id %p: fmr_pool %p qp %p\n",
+		 ib_conn, ib_conn->cma_id,
+		 ib_conn->fmr_pool, ib_conn->cma_id->qp);
+	return ret;
+
+qp_err:
+	(void)ib_destroy_fmr_pool(ib_conn->fmr_pool);
+fmr_pool_err:
+	kfree(ib_conn->page_vec);
+alloc_err:
+	iser_err("unable to alloc mem or create resource, err %d\n", ret);
+	return ret;
+}
+
+/**
+ * releases the FMR pool, QP and CMA ID objects, returns 0 on success,
+ * -1 on failure
+ */
+static int iser_free_ib_conn_res(struct iser_conn *ib_conn)
+{
+	BUG_ON(ib_conn == NULL);
+
+	iser_err("freeing conn %p cma_id %p fmr pool %p qp %p\n",
+		 ib_conn, ib_conn->cma_id,
+		 ib_conn->fmr_pool, ib_conn->qp);
+
+	/* qp is created only once both addr & route are resolved */
+	if (ib_conn->fmr_pool != NULL)
+		ib_destroy_fmr_pool(ib_conn->fmr_pool);
+
+	if (ib_conn->qp != NULL)
+		rdma_destroy_qp(ib_conn->cma_id);
+
+	if (ib_conn->cma_id != NULL)
+		rdma_destroy_id(ib_conn->cma_id);
+
+	ib_conn->fmr_pool = NULL;
+	ib_conn->qp	  = NULL;
+	ib_conn->cma_id   = NULL;
+	kfree(ib_conn->page_vec);
+
+	return 0;
+}
+
+/**
+ * based on the resolved device node GUID see if there already allocated
+ * device for this device. If there's no such, create one.
+ */
+static
+struct iser_device *iser_device_find_by_ib_device(struct rdma_cm_id *cma_id)
+{
+	struct list_head    *p_list;
+	struct iser_device  *device = NULL;
+
+	mutex_lock(&ig.device_list_mutex);
+
+	p_list = ig.device_list.next;
+	while (p_list != &ig.device_list) {
+		device = list_entry(p_list, struct iser_device, ig_list);
+		/* find if there's a match using the node GUID */
+		if (device->ib_device->node_guid == cma_id->device->node_guid)
+			break;
+	}
+
+	if (device == NULL) {
+		device = kzalloc(sizeof *device, GFP_KERNEL);
+		if (device == NULL)
+			goto out;
+		/* assign this device to the device */
+		device->ib_device = cma_id->device;
+		/* init the device and link it into ig device list */
+		if (iser_create_device_ib_res(device)) {
+			kfree(device);
+			device = NULL;
+			goto out;
+		}
+		list_add(&device->ig_list, &ig.device_list);
+	}
+out:
+	BUG_ON(device == NULL);
+	device->refcount++;
+	mutex_unlock(&ig.device_list_mutex);
+	return device;
+}
+
+/* if there's no demand for this device, release it */
+static void iser_device_try_release(struct iser_device *device)
+{
+	mutex_lock(&ig.device_list_mutex);
+	device->refcount--;
+	iser_err("device %p refcount %d\n",device,device->refcount);
+	if (!device->refcount) {
+		iser_free_device_ib_res(device);
+		list_del(&device->ig_list);
+		kfree(device);
+	}
+	mutex_unlock(&ig.device_list_mutex);
+}
+
+int iser_conn_state_comp(struct iser_conn *ib_conn,
+			enum iser_ib_conn_state comp)
+{
+	int ret;
+
+	spin_lock_bh(&ib_conn->lock);
+	ret = (ib_conn->state == comp);
+	spin_unlock_bh(&ib_conn->lock);
+	return ret;
+}
+
+static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
+				     enum iser_ib_conn_state comp,
+				     enum iser_ib_conn_state exch)
+{
+	int ret;
+
+	spin_lock_bh(&ib_conn->lock);
+	if ((ret = (ib_conn->state == comp)))
+		ib_conn->state = exch;
+	spin_unlock_bh(&ib_conn->lock);
+	return ret;
+}
+
+/**
+ * triggers start of the disconnect procedures and wait for them to be done
+ */
+void iser_conn_terminate(struct iser_conn *ib_conn)
+{
+	int err = 0;
+
+	/* change the ib conn state only if the conn is UP, however always call
+	 * rdma_disconnect since this is the only way to cause the CMA to change
+	 * the QP state to ERROR
+	 */
+
+	iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP, ISER_CONN_TERMINATING);
+	err = rdma_disconnect(ib_conn->cma_id);
+	if (err)
+		iser_err("Failed to disconnect, conn: 0x%p err %d\n",
+			 ib_conn,err);
+
+	wait_event_interruptible(ib_conn->wait,
+				 ib_conn->state == ISER_CONN_DOWN);
+
+	iser_conn_release(ib_conn);
+}
+
+static void iser_connect_error(struct rdma_cm_id *cma_id)
+{
+	struct iser_conn *ib_conn;
+	ib_conn = (struct iser_conn *)cma_id->context;
+
+	ib_conn->state = ISER_CONN_DOWN;
+	wake_up_interruptible(&ib_conn->wait);
+}
+
+static void iser_addr_handler(struct rdma_cm_id *cma_id)
+{
+	struct iser_device *device;
+	struct iser_conn   *ib_conn;
+	int    ret;
+
+	device = iser_device_find_by_ib_device(cma_id);
+	ib_conn = (struct iser_conn *)cma_id->context;
+	ib_conn->device = device;
+
+	ret = rdma_resolve_route(cma_id, 1000);
+	if (ret) {
+		iser_err("resolve route failed: %d\n", ret);
+		iser_connect_error(cma_id);
+	}
+	return;
+}
+
+static void iser_route_handler(struct rdma_cm_id *cma_id)
+{
+	struct rdma_conn_param conn_param;
+	int    ret;
+
+	ret = iser_create_ib_conn_res((struct iser_conn *)cma_id->context);
+	if (ret)
+		goto failure;
+
+	iser_dbg("path.mtu is %d setting it to %d\n",
+		 cma_id->route.path_rec->mtu, IB_MTU_1024);
+
+	/* we must set the MTU to 1024 as this is what the target is assuming */
+	if (cma_id->route.path_rec->mtu > IB_MTU_1024)
+		cma_id->route.path_rec->mtu = IB_MTU_1024;
+
+	memset(&conn_param, 0, sizeof conn_param);
+	conn_param.responder_resources = 4;
+	conn_param.initiator_depth     = 1;
+	conn_param.retry_count	       = 7;
+	conn_param.rnr_retry_count     = 6;
+
+	ret = rdma_connect(cma_id, &conn_param);
+	if (ret) {
+		iser_err("failure connecting: %d\n", ret);
+		goto failure;
+	}
+
+	return;
+failure:
+	iser_connect_error(cma_id);
+}
+
+static void iser_connected_handler(struct rdma_cm_id *cma_id)
+{
+	struct iser_conn *ib_conn;
+
+	ib_conn = (struct iser_conn *)cma_id->context;
+	ib_conn->state = ISER_CONN_UP;
+	wake_up_interruptible(&ib_conn->wait);
+}
+
+static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
+{
+	struct iser_conn *ib_conn;
+
+	ib_conn = (struct iser_conn *)cma_id->context;
+	ib_conn->disc_evt_flag = 1;
+
+	/* getting here when the state is UP means that the conn is being *
+	 * terminated asynchronously from the iSCSI layer's perspective.  */
+	if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
+				      ISER_CONN_TERMINATING))
+		iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
+				   ISCSI_ERR_CONN_FAILED);
+
+	/* Complete the termination process if no posts are pending */
+	if ((atomic_read(&ib_conn->post_recv_buf_count) == 0) &&
+	    (atomic_read(&ib_conn->post_send_buf_count) == 0)) {
+		ib_conn->state = ISER_CONN_DOWN;
+		wake_up_interruptible(&ib_conn->wait);
+	}
+}
+
+static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
+{
+	int ret = 0;
+
+	iser_err("event %d conn %p id %p\n",event->event,cma_id->context,cma_id);
+
+	switch (event->event) {
+	case RDMA_CM_EVENT_ADDR_RESOLVED:
+		iser_addr_handler(cma_id);
+		break;
+	case RDMA_CM_EVENT_ROUTE_RESOLVED:
+		iser_route_handler(cma_id);
+		break;
+	case RDMA_CM_EVENT_ESTABLISHED:
+		iser_connected_handler(cma_id);
+		break;
+	case RDMA_CM_EVENT_ADDR_ERROR:
+	case RDMA_CM_EVENT_ROUTE_ERROR:
+	case RDMA_CM_EVENT_CONNECT_ERROR:
+	case RDMA_CM_EVENT_UNREACHABLE:
+	case RDMA_CM_EVENT_REJECTED:
+		iser_err("event: %d, error: %d\n", event->event, event->status);
+		iser_connect_error(cma_id);
+		break;
+	case RDMA_CM_EVENT_DISCONNECTED:
+		iser_disconnected_handler(cma_id);
+		break;
+	case RDMA_CM_EVENT_DEVICE_REMOVAL:
+		BUG();
+		break;
+	case RDMA_CM_EVENT_CONNECT_RESPONSE:
+		BUG();
+		break;
+	case RDMA_CM_EVENT_CONNECT_REQUEST:
+	default:
+		break;
+	}
+	return ret;
+}
+
+int iser_conn_init(struct iser_conn **ibconn)
+{
+	struct iser_conn *ib_conn;
+
+	ib_conn = kzalloc(sizeof *ib_conn, GFP_KERNEL);
+	if (!ib_conn) {
+		iser_err("can't alloc memory for struct iser_conn\n");
+		return -ENOMEM;
+	}
+	ib_conn->state = ISER_CONN_INIT;
+	init_waitqueue_head(&ib_conn->wait);
+	atomic_set(&ib_conn->post_recv_buf_count, 0);
+	atomic_set(&ib_conn->post_send_buf_count, 0);
+	INIT_WORK(&ib_conn->comperror_work, iser_comp_error_worker,
+		  ib_conn);
+	INIT_LIST_HEAD(&ib_conn->conn_list);
+	spin_lock_init(&ib_conn->lock);
+
+	*ibconn = ib_conn;
+	return 0;
+}
+
+ /**
+ * starts the process of connecting to the target
+ * sleeps untill the connection is established or rejected
+ */
+int iser_connect(struct iser_conn   *ib_conn,
+		 struct sockaddr_in *src_addr,
+		 struct sockaddr_in *dst_addr,
+		 int                 non_blocking)
+{
+	struct sockaddr *src, *dst;
+	int err = 0;
+
+	sprintf(ib_conn->name,"%d.%d.%d.%d:%d",
+		NIPQUAD(dst_addr->sin_addr.s_addr), dst_addr->sin_port);
+
+	/* the device is known only --after-- address resolution */
+	ib_conn->device = NULL;
+
+	iser_err("connecting to: %d.%d.%d.%d, port 0x%x\n",
+		 NIPQUAD(dst_addr->sin_addr), dst_addr->sin_port);
+
+	ib_conn->state = ISER_CONN_PENDING;
+
+	ib_conn->cma_id = rdma_create_id(iser_cma_handler,
+					     (void *)ib_conn,
+					     RDMA_PS_TCP);
+	if (IS_ERR(ib_conn->cma_id)) {
+		err = PTR_ERR(ib_conn->cma_id);
+		iser_err("rdma_create_id failed: %d\n", err);
+		goto id_failure;
+	}
+
+	src = (struct sockaddr *)src_addr;
+	dst = (struct sockaddr *)dst_addr;
+	err = rdma_resolve_addr(ib_conn->cma_id, src, dst, 1000);
+	if (err) {
+		iser_err("rdma_resolve_addr failed: %d\n", err);
+		goto addr_failure;
+	}
+
+	if (!non_blocking) {
+		wait_event_interruptible(ib_conn->wait,
+					 (ib_conn->state != ISER_CONN_PENDING));
+
+		if (ib_conn->state != ISER_CONN_UP) {
+			err =  -EIO;
+			goto connect_failure;
+		}
+	}
+
+	mutex_lock(&ig.connlist_mutex);
+	list_add(&ib_conn->conn_list, &ig.connlist);
+	mutex_unlock(&ig.connlist_mutex);
+	return 0;
+
+id_failure:
+	ib_conn->cma_id = NULL;
+addr_failure:
+	ib_conn->state = ISER_CONN_DOWN;
+connect_failure:
+	iser_conn_release(ib_conn);
+	return err;
+}
+
+/**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+void iser_conn_release(struct iser_conn *ib_conn)
+{
+	struct iser_device  *device = ib_conn->device;
+
+	BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+	mutex_lock(&ig.connlist_mutex);
+	list_del(&ib_conn->conn_list);
+	mutex_unlock(&ig.connlist_mutex);
+
+	iser_free_ib_conn_res(ib_conn);
+	ib_conn->device = NULL;
+	/* on EVENT_ADDR_ERROR there's no device yet for this conn */
+	if (device != NULL)
+		iser_device_try_release(device);
+	kfree(ib_conn);
+}
+
+
+/**
+ * iser_reg_page_vec - Register physical memory
+ *
+ * returns: 0 on success, errno code on failure
+ */
+int iser_reg_page_vec(struct iser_conn     *ib_conn,
+		      struct iser_page_vec *page_vec,
+		      struct iser_mem_reg  *mem_reg)
+{
+	struct ib_pool_fmr *mem;
+	u64		   io_addr;
+	u64		   *page_list;
+	int		   status;
+
+	page_list = page_vec->pages;
+	io_addr	  = page_list[0];
+
+	mem  = ib_fmr_pool_map_phys(ib_conn->fmr_pool,
+				    page_list,
+				    page_vec->length,
+				    &io_addr);
+
+	if (IS_ERR(mem)) {
+		status = (int)PTR_ERR(mem);
+		iser_err("ib_fmr_pool_map_phys failed: %d\n", status);
+		return status;
+	}
+
+	mem_reg->lkey  = mem->fmr->lkey;
+	mem_reg->rkey  = mem->fmr->rkey;
+	mem_reg->len   = page_vec->length * PAGE_SIZE;
+	mem_reg->va    = io_addr;
+	mem_reg->mem_h = (void *)mem;
+
+	mem_reg->va   += page_vec->offset;
+	mem_reg->len   = page_vec->data_size;
+
+	iser_dbg("PHYSICAL Mem.register, [PHYS p_array: 0x%p, sz: %d, "
+		 "entry[0]: (0x%08lx,%ld)] -> "
+		 "[lkey: 0x%08X mem_h: 0x%p va: 0x%08lX sz: %ld]\n",
+		 page_vec, page_vec->length,
+		 (unsigned long)page_vec->pages[0],
+		 (unsigned long)page_vec->data_size,
+		 (unsigned int)mem_reg->lkey, mem_reg->mem_h,
+		 (unsigned long)mem_reg->va, (unsigned long)mem_reg->len);
+	return 0;
+}
+
+/**
+ * Unregister (previosuly registered) memory.
+ */
+void iser_unreg_mem(struct iser_mem_reg *reg)
+{
+	int ret;
+
+	iser_dbg("PHYSICAL Mem.Unregister mem_h %p\n",reg->mem_h);
+
+	ret = ib_fmr_pool_unmap((struct ib_pool_fmr *)reg->mem_h);
+	if (ret)
+		iser_err("ib_fmr_pool_unmap failed %d\n", ret);
+
+	reg->mem_h = NULL;
+}
+
+/**
+ * iser_dto_to_iov - builds IOV from a dto descriptor
+ */
+static void iser_dto_to_iov(struct iser_dto *dto, struct ib_sge *iov, int iov_len)
+{
+	int		     i;
+	struct ib_sge	     *sge;
+	struct iser_regd_buf *regd_buf;
+
+	if (dto->regd_vector_len > iov_len) {
+		iser_err("iov size %d too small for posting dto of len %d\n",
+			 iov_len, dto->regd_vector_len);
+		BUG();
+	}
+
+	for (i = 0; i < dto->regd_vector_len; i++) {
+		sge	    = &iov[i];
+		regd_buf  = dto->regd[i];
+
+		sge->addr   = regd_buf->reg.va;
+		sge->length = regd_buf->reg.len;
+		sge->lkey   = regd_buf->reg.lkey;
+
+		if (dto->used_sz[i] > 0)  /* Adjust size */
+			sge->length = dto->used_sz[i];
+
+		/* offset and length should not exceed the regd buf length */
+		if (sge->length + dto->offset[i] > regd_buf->reg.len) {
+			iser_err("Used len:%ld + offset:%d, exceed reg.buf.len:"
+				 "%ld in dto:0x%p [%d], va:0x%08lX\n",
+				 (unsigned long)sge->length, dto->offset[i],
+				 (unsigned long)regd_buf->reg.len, dto, i,
+				 (unsigned long)sge->addr);
+			BUG();
+		}
+
+		sge->addr += dto->offset[i]; /* Adjust offset */
+	}
+}
+
+/**
+ * iser_post_recv - Posts a receive buffer.
+ *
+ * returns 0 on success, -1 on failure
+ */
+int iser_post_recv(struct iser_desc *rx_desc)
+{
+	int		  ib_ret, ret_val = 0;
+	struct ib_recv_wr recv_wr, *recv_wr_failed;
+	struct ib_sge	  iov[2];
+	struct iser_conn  *ib_conn;
+	struct iser_dto   *recv_dto = &rx_desc->dto;
+
+	/* Retrieve conn */
+	ib_conn = recv_dto->conn->ib_conn;
+
+	iser_dto_to_iov(recv_dto, iov, 2);
+
+	recv_wr.next	= NULL;
+	recv_wr.sg_list = iov;
+	recv_wr.num_sge = recv_dto->regd_vector_len;
+	recv_wr.wr_id	= (unsigned long)rx_desc;
+
+	atomic_inc(&ib_conn->post_recv_buf_count);
+	ib_ret	= ib_post_recv(ib_conn->qp, &recv_wr, &recv_wr_failed);
+	if (ib_ret) {
+		iser_err("ib_post_recv failed ret=%d\n", ib_ret);
+		atomic_dec(&ib_conn->post_recv_buf_count);
+		ret_val = -1;
+	}
+
+	return ret_val;
+}
+
+/**
+ * iser_start_send - Initiate a Send DTO operation
+ *
+ * returns 0 on success, -1 on failure
+ */
+int iser_post_send(struct iser_desc *tx_desc)
+{
+	int		  ib_ret, ret_val = 0;
+	struct ib_send_wr send_wr, *send_wr_failed;
+	struct ib_sge	  iov[MAX_REGD_BUF_VECTOR_LEN];
+	struct iser_conn  *ib_conn;
+	struct iser_dto   *dto = &tx_desc->dto;
+
+	ib_conn = dto->conn->ib_conn;
+
+	iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN);
+
+	send_wr.next	   = NULL;
+	send_wr.wr_id	   = (unsigned long)tx_desc;
+	send_wr.sg_list	   = iov;
+	send_wr.num_sge	   = dto->regd_vector_len;
+	send_wr.opcode	   = IB_WR_SEND;
+	send_wr.send_flags = dto->notify_enable ? IB_SEND_SIGNALED : 0;
+
+	atomic_inc(&ib_conn->post_send_buf_count);
+
+	ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed);
+	if (ib_ret) {
+		iser_err("Failed to start SEND DTO, dto: 0x%p, IOV len: %d\n",
+			 dto, dto->regd_vector_len);
+		iser_err("ib_post_send failed, ret:%d\n", ib_ret);
+		atomic_dec(&ib_conn->post_send_buf_count);
+		ret_val = -1;
+	}
+
+	return ret_val;
+}
+
+static void iser_comp_error_worker(void *data)
+{
+	struct iser_conn *ib_conn = data;
+
+	/* getting here when the state is UP means that the conn is being *
+	 * terminated asynchronously from the iSCSI layer's perspective.  */
+	if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
+				      ISER_CONN_TERMINATING))
+		iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
+					ISCSI_ERR_CONN_FAILED);
+
+	/* complete the termination process if disconnect event was delivered *
+	 * note there are no more non completed posts to the QP               */
+	if (ib_conn->disc_evt_flag) {
+		ib_conn->state = ISER_CONN_DOWN;
+		wake_up_interruptible(&ib_conn->wait);
+	}
+}
+
+static void iser_handle_comp_error(struct iser_desc *desc)
+{
+	struct iser_dto  *dto     = &desc->dto;
+	struct iser_conn *ib_conn = dto->conn->ib_conn;
+
+	iser_dto_buffs_release(dto);
+
+	if (desc->type == ISCSI_RX) {
+		kfree(desc->data);
+		kmem_cache_free(ig.desc_cache, desc);
+		atomic_dec(&ib_conn->post_recv_buf_count);
+	} else { /* type is TX control/command/dataout */
+		if (desc->type == ISCSI_TX_DATAOUT)
+			kmem_cache_free(ig.desc_cache, desc);
+		atomic_dec(&ib_conn->post_send_buf_count);
+	}
+
+	if (atomic_read(&ib_conn->post_recv_buf_count) == 0 &&
+	    atomic_read(&ib_conn->post_send_buf_count) == 0)
+		schedule_work(&ib_conn->comperror_work);
+}
+
+static void iser_cq_tasklet_fn(unsigned long data)
+{
+	 struct iser_device  *device = (struct iser_device *)data;
+	 struct ib_cq	     *cq = device->cq;
+	 struct ib_wc	     wc;
+	 struct iser_desc    *desc;
+	 unsigned long	     xfer_len;
+
+	while (ib_poll_cq(cq, 1, &wc) == 1) {
+		desc	 = (struct iser_desc *) (unsigned long) wc.wr_id;
+		BUG_ON(desc == NULL);
+
+		if (wc.status == IB_WC_SUCCESS) {
+			if (desc->type == ISCSI_RX) {
+				xfer_len = (unsigned long)wc.byte_len;
+				iser_rcv_completion(desc, xfer_len);
+			} else /* type == ISCSI_TX_CONTROL/SCSI_CMD/DOUT */
+				iser_snd_completion(desc);
+		} else {
+			iser_err("comp w. error op %d status %d\n",desc->type,wc.status);
+			iser_handle_comp_error(desc);
+		}
+	}
+	/* #warning "it is assumed here that arming CQ only once its empty" *
+	 * " would not cause interrupts to be missed"                       */
+	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+}
+
+static void iser_cq_callback(struct ib_cq *cq, void *cq_context)
+{
+	struct iser_device  *device = (struct iser_device *)cq_context;
+
+	tasklet_schedule(&device->cq_tasklet);
+}
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 5f561fc..a29d5ce 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -78,14 +78,19 @@
 {
 	int retval;
 	struct evdev_list *list = file->private_data;
+
 	retval = fasync_helper(fd, file, on, &list->fasync);
+
 	return retval < 0 ? retval : 0;
 }
 
-static int evdev_flush(struct file * file, fl_owner_t id)
+static int evdev_flush(struct file *file, fl_owner_t id)
 {
 	struct evdev_list *list = file->private_data;
-	if (!list->evdev->exist) return -ENODEV;
+
+	if (!list->evdev->exist)
+		return -ENODEV;
+
 	return input_flush_device(&list->evdev->handle, file);
 }
 
@@ -300,6 +305,7 @@
 static unsigned int evdev_poll(struct file *file, poll_table *wait)
 {
 	struct evdev_list *list = file->private_data;
+
 	poll_wait(file, &list->evdev->wait, wait);
 	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
 		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3038c26..de2e754 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -28,20 +28,6 @@
 MODULE_DESCRIPTION("Input core");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(input_allocate_device);
-EXPORT_SYMBOL(input_register_device);
-EXPORT_SYMBOL(input_unregister_device);
-EXPORT_SYMBOL(input_register_handler);
-EXPORT_SYMBOL(input_unregister_handler);
-EXPORT_SYMBOL(input_grab_device);
-EXPORT_SYMBOL(input_release_device);
-EXPORT_SYMBOL(input_open_device);
-EXPORT_SYMBOL(input_close_device);
-EXPORT_SYMBOL(input_accept_process);
-EXPORT_SYMBOL(input_flush_device);
-EXPORT_SYMBOL(input_event);
-EXPORT_SYMBOL_GPL(input_class);
-
 #define INPUT_DEVICES	256
 
 static LIST_HEAD(input_dev_list);
@@ -63,11 +49,13 @@
 		case EV_SYN:
 			switch (code) {
 				case SYN_CONFIG:
-					if (dev->event) dev->event(dev, type, code, value);
+					if (dev->event)
+						dev->event(dev, type, code, value);
 					break;
 
 				case SYN_REPORT:
-					if (dev->sync) return;
+					if (dev->sync)
+						return;
 					dev->sync = 1;
 					break;
 			}
@@ -136,7 +124,8 @@
 			if (code > MSC_MAX || !test_bit(code, dev->mscbit))
 				return;
 
-			if (dev->event) dev->event(dev, type, code, value);
+			if (dev->event)
+				dev->event(dev, type, code, value);
 
 			break;
 
@@ -146,7 +135,9 @@
 				return;
 
 			change_bit(code, dev->led);
-			if (dev->event) dev->event(dev, type, code, value);
+
+			if (dev->event)
+				dev->event(dev, type, code, value);
 
 			break;
 
@@ -158,21 +149,25 @@
 			if (!!test_bit(code, dev->snd) != !!value)
 				change_bit(code, dev->snd);
 
-			if (dev->event) dev->event(dev, type, code, value);
+			if (dev->event)
+				dev->event(dev, type, code, value);
 
 			break;
 
 		case EV_REP:
 
-			if (code > REP_MAX || value < 0 || dev->rep[code] == value) return;
+			if (code > REP_MAX || value < 0 || dev->rep[code] == value)
+				return;
 
 			dev->rep[code] = value;
-			if (dev->event) dev->event(dev, type, code, value);
+			if (dev->event)
+				dev->event(dev, type, code, value);
 
 			break;
 
 		case EV_FF:
-			if (dev->event) dev->event(dev, type, code, value);
+			if (dev->event)
+				dev->event(dev, type, code, value);
 			break;
 	}
 
@@ -186,6 +181,7 @@
 			if (handle->open)
 				handle->handler->event(handle, type, code, value);
 }
+EXPORT_SYMBOL(input_event);
 
 static void input_repeat_key(unsigned long data)
 {
@@ -208,6 +204,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(input_accept_process);
 
 int input_grab_device(struct input_handle *handle)
 {
@@ -217,12 +214,14 @@
 	handle->dev->grab = handle;
 	return 0;
 }
+EXPORT_SYMBOL(input_grab_device);
 
 void input_release_device(struct input_handle *handle)
 {
 	if (handle->dev->grab == handle)
 		handle->dev->grab = NULL;
 }
+EXPORT_SYMBOL(input_release_device);
 
 int input_open_device(struct input_handle *handle)
 {
@@ -245,6 +244,7 @@
 
 	return err;
 }
+EXPORT_SYMBOL(input_open_device);
 
 int input_flush_device(struct input_handle* handle, struct file* file)
 {
@@ -253,6 +253,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(input_flush_device);
 
 void input_close_device(struct input_handle *handle)
 {
@@ -268,6 +269,7 @@
 
 	mutex_unlock(&dev->mutex);
 }
+EXPORT_SYMBOL(input_close_device);
 
 static void input_link_handle(struct input_handle *handle)
 {
@@ -335,9 +337,11 @@
 static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
 {
 	int state = input_devices_state;
+
 	poll_wait(file, &input_devices_poll_wait, wait);
 	if (state != input_devices_state)
 		return POLLIN | POLLRDNORM;
+
 	return 0;
 }
 
@@ -629,7 +633,7 @@
 
 	len = input_print_modalias(buf, PAGE_SIZE, id, 1);
 
-	return max_t(int, len, PAGE_SIZE);
+	return min_t(int, len, PAGE_SIZE);
 }
 static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
 
@@ -862,6 +866,7 @@
 	.release		= input_dev_release,
 	.uevent			= input_dev_uevent,
 };
+EXPORT_SYMBOL_GPL(input_class);
 
 struct input_dev *input_allocate_device(void)
 {
@@ -872,12 +877,27 @@
 		dev->dynalloc = 1;
 		dev->cdev.class = &input_class;
 		class_device_initialize(&dev->cdev);
+		mutex_init(&dev->mutex);
 		INIT_LIST_HEAD(&dev->h_list);
 		INIT_LIST_HEAD(&dev->node);
 	}
 
 	return dev;
 }
+EXPORT_SYMBOL(input_allocate_device);
+
+void input_free_device(struct input_dev *dev)
+{
+	if (dev) {
+
+		mutex_lock(&dev->mutex);
+		dev->name = dev->phys = dev->uniq = NULL;
+		mutex_unlock(&dev->mutex);
+
+		input_put_device(dev);
+	}
+}
+EXPORT_SYMBOL(input_free_device);
 
 int input_register_device(struct input_dev *dev)
 {
@@ -895,7 +915,6 @@
 		return -EINVAL;
 	}
 
-	mutex_init(&dev->mutex);
 	set_bit(EV_SYN, dev->evbit);
 
 	/*
@@ -956,12 +975,14 @@
  fail1:	class_device_del(&dev->cdev);
 	return error;
 }
+EXPORT_SYMBOL(input_register_device);
 
 void input_unregister_device(struct input_dev *dev)
 {
-	struct list_head * node, * next;
+	struct list_head *node, *next;
 
-	if (!dev) return;
+	if (!dev)
+		return;
 
 	del_timer_sync(&dev->timer);
 
@@ -979,8 +1000,13 @@
 	sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
 	class_device_unregister(&dev->cdev);
 
+	mutex_lock(&dev->mutex);
+	dev->name = dev->phys = dev->uniq = NULL;
+	mutex_unlock(&dev->mutex);
+
 	input_wakeup_procfs_readers();
 }
+EXPORT_SYMBOL(input_unregister_device);
 
 void input_register_handler(struct input_handler *handler)
 {
@@ -988,7 +1014,8 @@
 	struct input_handle *handle;
 	struct input_device_id *id;
 
-	if (!handler) return;
+	if (!handler)
+		return;
 
 	INIT_LIST_HEAD(&handler->h_list);
 
@@ -1005,10 +1032,11 @@
 
 	input_wakeup_procfs_readers();
 }
+EXPORT_SYMBOL(input_register_handler);
 
 void input_unregister_handler(struct input_handler *handler)
 {
-	struct list_head * node, * next;
+	struct list_head *node, *next;
 
 	list_for_each_safe(node, next, &handler->h_list) {
 		struct input_handle * handle = to_handle_h(node);
@@ -1024,6 +1052,7 @@
 
 	input_wakeup_procfs_readers();
 }
+EXPORT_SYMBOL(input_unregister_handler);
 
 static int input_open_file(struct inode *inode, struct file *file)
 {
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 949bdce..d671575 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -81,10 +81,7 @@
 			return 0;
 	}
 
-	if (value < -32767) return -32767;
-	if (value >  32767) return  32767;
-
-	return value;
+	return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
 }
 
 static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
@@ -96,7 +93,8 @@
 	switch (type) {
 
 		case EV_KEY:
-			if (code < BTN_MISC || value == 2) return;
+			if (code < BTN_MISC || value == 2)
+				return;
 			event.type = JS_EVENT_BUTTON;
 			event.number = joydev->keymap[code - BTN_MISC];
 			event.value = value;
@@ -106,7 +104,8 @@
 			event.type = JS_EVENT_AXIS;
 			event.number = joydev->absmap[code];
 			event.value = joydev_correct(value, joydev->corr + event.number);
-			if (event.value == joydev->abs[event.number]) return;
+			if (event.value == joydev->abs[event.number])
+				return;
 			joydev->abs[event.number] = event.value;
 			break;
 
@@ -134,7 +133,9 @@
 {
 	int retval;
 	struct joydev_list *list = file->private_data;
+
 	retval = fasync_helper(fd, file, on, &list->fasync);
+
 	return retval < 0 ? retval : 0;
 }
 
@@ -222,12 +223,12 @@
 		return sizeof(struct JS_DATA_TYPE);
 	}
 
-	if (list->startup == joydev->nabs + joydev->nkey
-		&& list->head == list->tail && (file->f_flags & O_NONBLOCK))
-			return -EAGAIN;
+	if (list->startup == joydev->nabs + joydev->nkey &&
+	    list->head == list->tail && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
 
 	retval = wait_event_interruptible(list->joydev->wait,
-		 			  !list->joydev->exist ||
+					  !list->joydev->exist ||
 					  list->startup < joydev->nabs + joydev->nkey ||
 					  list->head != list->tail);
 
@@ -276,8 +277,9 @@
 static unsigned int joydev_poll(struct file *file, poll_table *wait)
 {
 	struct joydev_list *list = file->private_data;
+
 	poll_wait(file, &list->joydev->wait, wait);
-	return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? 
+	return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
 		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
@@ -291,20 +293,26 @@
 		case JS_SET_CAL:
 			return copy_from_user(&joydev->glue.JS_CORR, argp,
 				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+
 		case JS_GET_CAL:
 			return copy_to_user(argp, &joydev->glue.JS_CORR,
 				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+
 		case JS_SET_TIMEOUT:
 			return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+
 		case JS_GET_TIMEOUT:
 			return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 
 		case JSIOCGVERSION:
 			return put_user(JS_VERSION, (__u32 __user *) argp);
+
 		case JSIOCGAXES:
 			return put_user(joydev->nabs, (__u8 __user *) argp);
+
 		case JSIOCGBUTTONS:
 			return put_user(joydev->nkey, (__u8 __user *) argp);
+
 		case JSIOCSCORR:
 			if (copy_from_user(joydev->corr, argp,
 				      sizeof(joydev->corr[0]) * joydev->nabs))
@@ -314,38 +322,49 @@
 			        joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
 			}
 			return 0;
+
 		case JSIOCGCORR:
 			return copy_to_user(argp, joydev->corr,
 						sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
+
 		case JSIOCSAXMAP:
 			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 				return -EFAULT;
 			for (i = 0; i < joydev->nabs; i++) {
-				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
+				if (joydev->abspam[i] > ABS_MAX)
+					return -EINVAL;
 				joydev->absmap[joydev->abspam[i]] = i;
 			}
 			return 0;
+
 		case JSIOCGAXMAP:
 			return copy_to_user(argp, joydev->abspam,
 						sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
+
 		case JSIOCSBTNMAP:
 			if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
 				return -EFAULT;
 			for (i = 0; i < joydev->nkey; i++) {
-				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
+				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
+					return -EINVAL;
 				joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
 			}
 			return 0;
+
 		case JSIOCGBTNMAP:
 			return copy_to_user(argp, joydev->keypam,
 						sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
+
 		default:
 			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
 				int len;
-				if (!dev->name) return 0;
+				if (!dev->name)
+					return 0;
 				len = strlen(dev->name) + 1;
-				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-				if (copy_to_user(argp, dev->name, len)) return -EFAULT;
+				if (len > _IOC_SIZE(cmd))
+					len = _IOC_SIZE(cmd);
+				if (copy_to_user(argp, dev->name, len))
+					return -EFAULT;
 				return len;
 			}
 	}
@@ -362,7 +381,9 @@
 	struct JS_DATA_SAVE_TYPE_32 ds32;
 	int err;
 
-	if (!joydev->exist) return -ENODEV;
+	if (!joydev->exist)
+		return -ENODEV;
+
 	switch(cmd) {
 	case JS_SET_TIMELIMIT:
 		err = get_user(tmp32, (s32 __user *) arg);
@@ -395,8 +416,7 @@
 		ds32.JS_SAVE       = joydev->glue.JS_SAVE;
 		ds32.JS_CORR       = joydev->glue.JS_CORR;
 
-		err = copy_to_user(argp, &ds32,
-					  sizeof(ds32)) ? -EFAULT : 0;
+		err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
 		break;
 
 	default:
@@ -412,7 +432,8 @@
 	struct joydev *joydev = list->joydev;
 	void __user *argp = (void __user *)arg;
 
-	if (!joydev->exist) return -ENODEV;
+	if (!joydev->exist)
+		return -ENODEV;
 
 	switch(cmd) {
 		case JS_SET_TIMELIMIT:
@@ -546,8 +567,8 @@
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
 		.evbit = { BIT(EV_KEY) },
 		.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
-	}, 	/* Avoid itouchpads, touchscreens and tablets */
-	{ }, 	/* Terminating entry */
+	},	/* Avoid itouchpads, touchscreens and tablets */
+	{ }	/* Terminating entry */
 };
 
 static struct input_device_id joydev_ids[] = {
@@ -566,7 +587,7 @@
 		.evbit = { BIT(EV_ABS) },
 		.absbit = { BIT(ABS_THROTTLE) },
 	},
-	{ }, 	/* Terminating entry */
+	{ }	/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(input, joydev_ids);
@@ -579,7 +600,7 @@
 	.minor =	JOYDEV_MINOR_BASE,
 	.name =		"joydev",
 	.id_table =	joydev_ids,
-	.blacklist = 	joydev_blacklist,
+	.blacklist =	joydev_blacklist,
 };
 
 static int __init joydev_init(void)
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index 4612d13..b11a4bb 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -306,7 +306,7 @@
 	gameport_set_poll_handler(gameport, a3d_poll);
 	gameport_set_poll_interval(gameport, 20);
 
-	sprintf(a3d->phys, "%s/input0", gameport->phys);
+	snprintf(a3d->phys, sizeof(a3d->phys), "%s/input0", gameport->phys);
 
 	input_dev->name = a3d_names[a3d->mode];
 	input_dev->phys = a3d->phys;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 3121961..01dc0b1 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -408,21 +408,23 @@
 
 static void analog_name(struct analog *analog)
 {
-	sprintf(analog->name, "Analog %d-axis %d-button",
-		hweight8(analog->mask & ANALOG_AXES_STD),
-		hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
-		hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
+	snprintf(analog->name, sizeof(analog->name), "Analog %d-axis %d-button",
+		 hweight8(analog->mask & ANALOG_AXES_STD),
+		 hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
+		 hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
 
 	if (analog->mask & ANALOG_HATS_ALL)
-		sprintf(analog->name, "%s %d-hat",
-			analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
+		snprintf(analog->name, sizeof(analog->name), "%s %d-hat",
+			 analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
 
 	if (analog->mask & ANALOG_HAT_FCS)
-			strcat(analog->name, " FCS");
+		strlcat(analog->name, " FCS", sizeof(analog->name));
 	if (analog->mask & ANALOG_ANY_CHF)
-			strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
+		strlcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF",
+			sizeof(analog->name));
 
-	strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
+	strlcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick",
+		sizeof(analog->name));
 }
 
 /*
@@ -435,7 +437,8 @@
 	int i, j, t, v, w, x, y, z;
 
 	analog_name(analog);
-	sprintf(analog->phys, "%s/input%d", port->gameport->phys, index);
+	snprintf(analog->phys, sizeof(analog->phys),
+		 "%s/input%d", port->gameport->phys, index);
 	analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
 
 	analog->dev = input_dev = input_allocate_device();
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 1909f7e..d5e42eb 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -202,7 +202,8 @@
 			goto fail3;
 		}
 
-		sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i);
+		snprintf(cobra->phys[i], sizeof(cobra->phys[i]),
+			 "%s/input%d", gameport->phys, i);
 
 		input_dev->name = "Creative Labs Blaster GamePad Cobra";
 		input_dev->phys = cobra->phys[i];
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index e618946..6f31f05 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -620,7 +620,8 @@
 			goto err_unreg_devs;
 		}
 
-		sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
+		snprintf(db9->phys[i], sizeof(db9->phys[i]),
+			 "%s/input%d", db9->pd->port->name, i);
 
 		input_dev->name = db9_mode->name;
 		input_dev->phys = db9->phys[i];
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index ecbdb6b..fe12aa3 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -761,7 +761,8 @@
 		if (!pads[i])
 			continue;
 
-		sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
+		snprintf(gc->phys[i], sizeof(gc->phys[i]),
+			 "%s/input%d", gc->pd->port->name, i);
 		err = gc_setup_pad(gc, i, pads[i]);
 		if (err)
 			goto err_unreg_devs;
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 8a3ad45..e4a699f 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -298,7 +298,7 @@
 	gameport_set_poll_handler(gameport, gf2k_poll);
 	gameport_set_poll_interval(gameport, 20);
 
-	sprintf(gf2k->phys, "%s/input0", gameport->phys);
+	snprintf(gf2k->phys, sizeof(gf2k->phys), "%s/input0", gameport->phys);
 
 	gf2k->length = gf2k_lens[gf2k->id];
 
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 20cb98a..17a90c4 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -354,7 +354,8 @@
 			goto fail3;
 		}
 
-		sprintf(grip->phys[i], "%s/input%d", gameport->phys, i);
+		snprintf(grip->phys[i], sizeof(grip->phys[i]),
+			 "%s/input%d", gameport->phys, i);
 
 		input_dev->name = grip_name[grip->mode[i]];
 		input_dev->phys = grip->phys[i];
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 6e2c721..840ed9b 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -222,7 +222,7 @@
 	gameport_set_poll_handler(gameport, guillemot_poll);
 	gameport_set_poll_interval(gameport, 20);
 
-	sprintf(guillemot->phys, "%s/input0", gameport->phys);
+	snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys);
 	guillemot->type = guillemot_type + i;
 
 	input_dev->name = guillemot_type[i].name;
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 2b8e845..50c9076 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -47,7 +47,7 @@
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
 			mutex_unlock(&iforce->mem_mutex);
-			return -ENOMEM;
+			return -ENOSPC;
 		}
 		mutex_unlock(&iforce->mem_mutex);
 	}
@@ -80,7 +80,7 @@
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
 			mutex_unlock(&iforce->mem_mutex);
-			return -ENOMEM;
+			return -ENOSPC;
 		}
 		mutex_unlock(&iforce->mem_mutex);
 	}
@@ -120,7 +120,7 @@
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
 			mutex_unlock(&iforce->mem_mutex);
-			return -ENOMEM;
+			return -ENOSPC;
 		}
 		mutex_unlock(&iforce->mem_mutex);
 	}
@@ -157,7 +157,7 @@
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
 			mutex_unlock(&iforce->mem_mutex);
-			return -ENOMEM;
+			return -ENOSPC;
 		}
 		mutex_unlock(&iforce->mem_mutex);
 	}
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index ab0a26b..6d99e3c 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -86,7 +86,7 @@
 
 static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct iforce* iforce = (struct iforce*)(dev->private);
+	struct iforce* iforce = dev->private;
 	unsigned char data[3];
 
 	if (type != EV_FF)
@@ -138,7 +138,7 @@
  */
 static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
 {
-	struct iforce* iforce = (struct iforce*)(dev->private);
+	struct iforce* iforce = dev->private;
 	int id;
 	int ret;
 	int is_update;
@@ -218,7 +218,7 @@
  */
 static int iforce_erase_effect(struct input_dev *dev, int effect_id)
 {
-	struct iforce* iforce = (struct iforce*)(dev->private);
+	struct iforce* iforce = dev->private;
 	int err = 0;
 	struct iforce_core_effect* core_effect;
 
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index c4ed017..bbfeb9c 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -251,7 +251,7 @@
 	gameport_set_poll_handler(gameport, interact_poll);
 	gameport_set_poll_interval(gameport, 20);
 
-	sprintf(interact->phys, "%s/input0", gameport->phys);
+	snprintf(interact->phys, sizeof(interact->phys), "%s/input0", gameport->phys);
 
 	interact->type = i;
 	interact->length = interact_type[i].length;
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index ca3cc23..168b106 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -162,7 +162,7 @@
 		goto fail;
 
 	magellan->dev = input_dev;
-	sprintf(magellan->phys, "%s/input0", serio->phys);
+	snprintf(magellan->phys, sizeof(magellan->phys), "%s/input0", serio->phys);
 
 	input_dev->name = "LogiCad3D Magellan / SpaceMouse";
 	input_dev->phys = magellan->phys;
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 95c0de7..e58b22c 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -541,7 +541,7 @@
  * Unfortunately I don't know how to do this for the other SW types.
  */
 
-static void sw_3dp_id(unsigned char *buf, char *comment)
+static void sw_3dp_id(unsigned char *buf, char *comment, size_t size)
 {
 	int i;
 	char pnp[8], rev[9];
@@ -554,7 +554,7 @@
 
 	pnp[7] = rev[8] = 0;
 
-	sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+	snprintf(comment, size, " [PnP %d.%02d id %s rev %s]",
 		(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |		/* Two 6-bit values */
 			sw_get_bits(buf, 16, 6, 1)) / 100,
 		(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
@@ -695,7 +695,7 @@
 						sw->type = SW_ID_FFP;
 						sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
 					} else
-					sw->type = SW_ID_PP;
+						sw->type = SW_ID_PP;
 					break;
 				case 66:
 					sw->bits = 3;
@@ -703,7 +703,8 @@
 					sw->length = 22;
 				case 64:
 					sw->type = SW_ID_3DP;
-					if (j == 160) sw_3dp_id(idbuf, comment);
+					if (j == 160)
+						sw_3dp_id(idbuf, comment, sizeof(comment));
 					break;
 			}
 		}
@@ -733,8 +734,10 @@
 	for (i = 0; i < sw->number; i++) {
 		int bits, code;
 
-		sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
-		sprintf(sw->phys[i], "%s/input%d", gameport->phys, i);
+		snprintf(sw->name, sizeof(sw->name),
+			 "Microsoft SideWinder %s", sw_name[sw->type]);
+		snprintf(sw->phys[i], sizeof(sw->phys[i]),
+			 "%s/input%d", gameport->phys, i);
 
 		sw->dev[i] = input_dev = input_allocate_device();
 		if (!input_dev) {
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index d6f8db8..75eb5ca 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -220,7 +220,7 @@
 		goto fail;
 
 	spaceball->dev = input_dev;
-	sprintf(spaceball->phys, "%s/input0", serio->phys);
+	snprintf(spaceball->phys, sizeof(spaceball->phys), "%s/input0", serio->phys);
 
 	input_dev->name = spaceball_names[id];
 	input_dev->phys = spaceball->phys;
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 7c123a0..3e2782e 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -177,7 +177,7 @@
 		goto fail;
 
 	spaceorb->dev = input_dev;
-	sprintf(spaceorb->phys, "%s/input0", serio->phys);
+	snprintf(spaceorb->phys, sizeof(spaceorb->phys), "%s/input0", serio->phys);
 
 	input_dev->name = "SpaceTec SpaceOrb 360 / Avenger";
 	input_dev->phys = spaceorb->phys;
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index 0a9ed1d..011ec48 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -148,7 +148,7 @@
 		goto fail;
 
 	stinger->dev = input_dev;
-	sprintf(stinger->phys, "%s/serio0", serio->phys);
+	snprintf(stinger->phys, sizeof(stinger->phys), "%s/serio0", serio->phys);
 
 	input_dev->name = "Gravis Stinger";
 	input_dev->phys = stinger->phys;
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 7f8b009..076f237 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -199,7 +199,7 @@
 		goto fail;
 
 	twidjoy->dev = input_dev;
-	sprintf(twidjoy->phys, "%s/input0", serio->phys);
+	snprintf(twidjoy->phys, sizeof(twidjoy->phys), "%s/input0", serio->phys);
 
 	input_dev->name = "Handykey Twiddler";
 	input_dev->phys = twidjoy->phys;
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index 1849b17..f9c1a03 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -154,7 +154,7 @@
 		goto fail;
 
 	warrior->dev = input_dev;
-	sprintf(warrior->phys, "%s/input0", serio->phys);
+	snprintf(warrior->phys, sizeof(warrior->phys), "%s/input0", serio->phys);
 
 	input_dev->name = "Logitech WingMan Warrior";
 	input_dev->phys = warrior->phys;
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index fad04b6..ffde8f8 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -55,7 +55,7 @@
 module_param_named(softraw, atkbd_softraw, bool, 0);
 MODULE_PARM_DESC(softraw, "Use software generated rawmode");
 
-static int atkbd_scroll = 0;
+static int atkbd_scroll;
 module_param_named(scroll, atkbd_scroll, bool, 0);
 MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
 
@@ -150,8 +150,8 @@
 #define ATKBD_RET_EMUL0		0xe0
 #define ATKBD_RET_EMUL1		0xe1
 #define ATKBD_RET_RELEASE	0xf0
-#define ATKBD_RET_HANGUEL	0xf1
-#define ATKBD_RET_HANJA		0xf2
+#define ATKBD_RET_HANJA		0xf1
+#define ATKBD_RET_HANGEUL	0xf2
 #define ATKBD_RET_ERR		0xff
 
 #define ATKBD_KEY_UNKNOWN	  0
@@ -170,6 +170,13 @@
 #define ATKBD_LED_EVENT_BIT	0
 #define ATKBD_REP_EVENT_BIT	1
 
+#define ATKBD_XL_ERR		0x01
+#define ATKBD_XL_BAT		0x02
+#define ATKBD_XL_ACK		0x04
+#define ATKBD_XL_NAK		0x08
+#define ATKBD_XL_HANGEUL	0x10
+#define ATKBD_XL_HANJA		0x20
+
 static struct {
 	unsigned char keycode;
 	unsigned char set2;
@@ -211,8 +218,7 @@
 	unsigned char emul;
 	unsigned char resend;
 	unsigned char release;
-	unsigned char bat_xl;
-	unsigned char err_xl;
+	unsigned long xl_bit;
 	unsigned int last;
 	unsigned long time;
 
@@ -245,17 +251,65 @@
 ATKBD_DEFINE_ATTR(softrepeat);
 ATKBD_DEFINE_ATTR(softraw);
 
+static const unsigned int xl_table[] = {
+	ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
+	ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
+};
 
-static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
+/*
+ * Checks if we should mangle the scancode to extract 'release' bit
+ * in translated mode.
+ */
+static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
 {
-	input_regs(dev, regs);
-	if (value == 3) {
-		input_report_key(dev, code, 1);
-		input_sync(dev);
-		input_report_key(dev, code, 0);
-	} else
-		input_event(dev, EV_KEY, code, value);
-	input_sync(dev);
+	int i;
+
+	if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(xl_table); i++)
+		if (code == xl_table[i])
+			return test_bit(i, &xl_bit);
+
+	return 1;
+}
+
+/*
+ * Calculates new value of xl_bit so the driver can distinguish
+ * between make/break pair of scancodes for select keys and PS/2
+ * protocol responses.
+ */
+static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
+		if (!((code ^ xl_table[i]) & 0x7f)) {
+			if (code & 0x80)
+				__clear_bit(i, &atkbd->xl_bit);
+			else
+				__set_bit(i, &atkbd->xl_bit);
+			break;
+		}
+	}
+}
+
+/*
+ * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
+ * keeping kernel 2.4 compatibility for set 2
+ */
+static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
+{
+	if (atkbd->set == 3) {
+		if (atkbd->emul == 1)
+			code |= 0x100;
+        } else {
+		code = (code & 0x7f) | ((code & 0x80) << 1);
+		if (atkbd->emul == 1)
+			code |= 0x80;
+	}
+
+	return code;
 }
 
 /*
@@ -267,9 +321,11 @@
 			unsigned int flags, struct pt_regs *regs)
 {
 	struct atkbd *atkbd = serio_get_drvdata(serio);
+	struct input_dev *dev = atkbd->dev;
 	unsigned int code = data;
-	int scroll = 0, hscroll = 0, click = -1;
+	int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
 	int value;
+	unsigned char keycode;
 
 #ifdef ATKBD_DEBUG
 	printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
@@ -298,25 +354,17 @@
 	if (!atkbd->enabled)
 		goto out;
 
-	input_event(atkbd->dev, EV_MSC, MSC_RAW, code);
+	input_event(dev, EV_MSC, MSC_RAW, code);
 
 	if (atkbd->translated) {
 
-		if (atkbd->emul ||
-		    (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 &&
-		     code != ATKBD_RET_HANGUEL && code != ATKBD_RET_HANJA &&
-		     (code != ATKBD_RET_ERR || atkbd->err_xl) &&
-	             (code != ATKBD_RET_BAT || atkbd->bat_xl))) {
+		if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
 			atkbd->release = code >> 7;
 			code &= 0x7f;
 		}
 
-		if (!atkbd->emul) {
-		     if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
-			atkbd->bat_xl = !(data >> 7);
-		     if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
-			atkbd->err_xl = !(data >> 7);
-		}
+		if (!atkbd->emul)
+			atkbd_calculate_xl_bit(atkbd, data);
 	}
 
 	switch (code) {
@@ -333,47 +381,48 @@
 		case ATKBD_RET_RELEASE:
 			atkbd->release = 1;
 			goto out;
-		case ATKBD_RET_HANGUEL:
-			atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3);
+		case ATKBD_RET_ACK:
+		case ATKBD_RET_NAK:
+			printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
+			       "Some program might be trying access hardware directly.\n",
+			       data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
 			goto out;
+		case ATKBD_RET_HANGEUL:
 		case ATKBD_RET_HANJA:
-			atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3);
-			goto out;
+			/*
+			 * These keys do not report release and thus need to be
+			 * flagged properly
+			 */
+			add_release_event = 1;
+			break;
 		case ATKBD_RET_ERR:
 			printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
 			goto out;
 	}
 
-	if (atkbd->set != 3)
-		code = (code & 0x7f) | ((code & 0x80) << 1);
-	if (atkbd->emul) {
-		if (--atkbd->emul)
-			goto out;
-		code |= (atkbd->set != 3) ? 0x80 : 0x100;
-	}
+	code = atkbd_compat_scancode(atkbd, code);
 
-	if (atkbd->keycode[code] != ATKBD_KEY_NULL)
-		input_event(atkbd->dev, EV_MSC, MSC_SCAN, code);
+	if (atkbd->emul && --atkbd->emul)
+		goto out;
 
-	switch (atkbd->keycode[code]) {
+	keycode = atkbd->keycode[code];
+
+	if (keycode != ATKBD_KEY_NULL)
+		input_event(dev, EV_MSC, MSC_SCAN, code);
+
+	switch (keycode) {
 		case ATKBD_KEY_NULL:
 			break;
 		case ATKBD_KEY_UNKNOWN:
-			if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
-				printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
-				       "like XFree86, might be trying access hardware directly.\n",
-				       data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
-			} else {
-				printk(KERN_WARNING "atkbd.c: Unknown key %s "
-				       "(%s set %d, code %#x on %s).\n",
-				       atkbd->release ? "released" : "pressed",
-				       atkbd->translated ? "translated" : "raw",
-				       atkbd->set, code, serio->phys);
-				printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
-				       "to make it known.\n",
-				       code & 0x80 ? "e0" : "", code & 0x7f);
-			}
-			input_sync(atkbd->dev);
+			printk(KERN_WARNING
+			       "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
+			       atkbd->release ? "released" : "pressed",
+			       atkbd->translated ? "translated" : "raw",
+			       atkbd->set, code, serio->phys);
+			printk(KERN_WARNING
+			       "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
+			       code & 0x80 ? "e0" : "", code & 0x7f);
+			input_sync(dev);
 			break;
 		case ATKBD_SCR_1:
 			scroll = 1 - atkbd->release * 2;
@@ -397,33 +446,35 @@
 			hscroll = 1;
 			break;
 		default:
-			value = atkbd->release ? 0 :
-				(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key)));
-
-			switch (value) {	/* Workaround Toshiba laptop multiple keypress */
-				case 0:
-					atkbd->last = 0;
-					break;
-				case 1:
-					atkbd->last = code;
-					atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2;
-					break;
-				case 2:
-					if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
-						value = 1;
-					break;
+			if (atkbd->release) {
+				value = 0;
+				atkbd->last = 0;
+			} else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
+				/* Workaround Toshiba laptop multiple keypress */
+				value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
+			} else {
+				value = 1;
+				atkbd->last = code;
+				atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
 			}
 
-			atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value);
+			input_regs(dev, regs);
+			input_report_key(dev, keycode, value);
+			input_sync(dev);
+
+			if (value && add_release_event) {
+				input_report_key(dev, keycode, 0);
+				input_sync(dev);
+			}
 	}
 
 	if (atkbd->scroll) {
-		input_regs(atkbd->dev, regs);
+		input_regs(dev, regs);
 		if (click != -1)
-			input_report_key(atkbd->dev, BTN_MIDDLE, click);
-		input_report_rel(atkbd->dev, REL_WHEEL, scroll);
-		input_report_rel(atkbd->dev, REL_HWHEEL, hscroll);
-		input_sync(atkbd->dev);
+			input_report_key(dev, BTN_MIDDLE, click);
+		input_report_rel(dev, REL_WHEEL, scroll);
+		input_report_rel(dev, REL_HWHEEL, hscroll);
+		input_sync(dev);
 	}
 
 	atkbd->release = 0;
@@ -764,6 +815,9 @@
 			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
 				atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
 	}
+
+	atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL;
+	atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA;
 }
 
 /*
@@ -776,12 +830,15 @@
 	int i;
 
 	if (atkbd->extra)
-		sprintf(atkbd->name, "AT Set 2 Extra keyboard");
+		snprintf(atkbd->name, sizeof(atkbd->name),
+			 "AT Set 2 Extra keyboard");
 	else
-		sprintf(atkbd->name, "AT %s Set %d keyboard",
-			atkbd->translated ? "Translated" : "Raw", atkbd->set);
+		snprintf(atkbd->name, sizeof(atkbd->name),
+			 "AT %s Set %d keyboard",
+			 atkbd->translated ? "Translated" : "Raw", atkbd->set);
 
-	sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys);
+	snprintf(atkbd->phys, sizeof(atkbd->phys),
+		 "%s/input0", atkbd->ps2dev.serio->phys);
 
 	input_dev->name = atkbd->name;
 	input_dev->phys = atkbd->phys;
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 77c4d96..5174224 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -384,18 +384,21 @@
 	 */
 	switch (lk->id[4]) {
 		case 1:
-			sprintf (lk->name, "DEC LK201 keyboard");
+			strlcpy (lk->name, "DEC LK201 keyboard",
+				 sizeof (lk->name));
 
 			if (lk201_compose_is_alt)
 				lk->keycode[0xb1] = KEY_LEFTALT;
 			break;
 
 		case 2:
-			sprintf (lk->name, "DEC LK401 keyboard");
+			strlcpy (lk->name, "DEC LK401 keyboard",
+				 sizeof (lk->name));
 			break;
 
 		default:
-			sprintf (lk->name, "Unknown DEC keyboard");
+			strlcpy (lk->name, "Unknown DEC keyboard",
+				 sizeof (lk->name));
 			printk (KERN_ERR "lkkbd: keyboard on %s is unknown, "
 					"please report to Jan-Benedict Glaw "
 					"<jbglaw@lug-owl.de>\n", lk->phys);
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index d10983c..40a3f55 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -96,7 +96,7 @@
 
 	nkbd->serio = serio;
 	nkbd->dev = input_dev;
-	sprintf(nkbd->phys, "%s/input0", serio->phys);
+	snprintf(nkbd->phys, sizeof(nkbd->phys), "%s/input0", serio->phys);
 	memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
 
 	input_dev->name = "Newton Keyboard";
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index b15b6d8..9dbd7b8 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -263,7 +263,7 @@
 		goto fail;
 	}
 
-	sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
+	snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type);
 	memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
 
 	input_dev->name = sunkbd->name;
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index 4135e3e..0821d53 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -100,7 +100,7 @@
 
 	xtkbd->serio = serio;
 	xtkbd->dev = input_dev;
-	sprintf(xtkbd->phys, "%s/input0", serio->phys);
+	snprintf(xtkbd->phys, sizeof(xtkbd->phys), "%s/input0", serio->phys);
 	memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
 
 	input_dev->name = "XT Keyboard";
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index a0e2e79..070d753 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -470,7 +470,7 @@
 		dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
 	}
 
-	sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys);
+	snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
 	dev2->phys = priv->phys;
 	dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
 	dev2->id.bustype = BUS_I8042;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 136321a..8bc9f51 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -150,9 +150,20 @@
  */
 
 	if (psmouse->type == PSMOUSE_IMEX) {
-		input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
-		input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
-		input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+		switch (packet[3] & 0xC0) {
+			case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
+				input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+				break;
+			case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
+				input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+				break;
+			case 0x00:
+			case 0xC0:
+				input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
+				input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
+				input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+				break;
+		}
 	}
 
 /*
@@ -466,9 +477,25 @@
 	if (param[0] != 4)
 		return -1;
 
+/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
+	param[0] = 200;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  80;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  40;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+
+	param[0] = 200;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] = 200;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  60;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+
 	if (set_properties) {
 		set_bit(BTN_MIDDLE, psmouse->dev->keybit);
 		set_bit(REL_WHEEL, psmouse->dev->relbit);
+		set_bit(REL_HWHEEL, psmouse->dev->relbit);
 		set_bit(BTN_SIDE, psmouse->dev->keybit);
 		set_bit(BTN_EXTRA, psmouse->dev->keybit);
 
@@ -1057,8 +1084,8 @@
 	if (psmouse->resync_time && psmouse->poll(psmouse))
 		psmouse->resync_time = 0;
 
-	sprintf(psmouse->devname, "%s %s %s",
-		psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+	snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s",
+		 psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
 
 	input_dev->name = psmouse->devname;
 	input_dev->phys = psmouse->phys;
@@ -1099,7 +1126,7 @@
 	ps2_init(&psmouse->ps2dev, serio);
 	INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse);
 	psmouse->dev = input_dev;
-	sprintf(psmouse->phys, "%s/input0", serio->phys);
+	snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
 
 	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 2f9a04a..a897424 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -254,7 +254,7 @@
 		goto fail;
 
 	sermouse->dev = input_dev;
-	sprintf(sermouse->phys, "%s/input0", serio->phys);
+	snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys);
 	sermouse->type = serio->id.proto;
 
 	input_dev->name = sermouse_protocols[sermouse->type];
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index 36e9442..7b85bc2 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -153,22 +153,25 @@
 {
 	switch (mouse->type) {
 		case 0x02:
-			sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse");
+			strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse",
+				 sizeof (mouse->name));
 			break;
 
 		case 0x04:
-			sprintf (mouse->name, "DEC VSXXX-AB digitizer");
+			strlcpy (mouse->name, "DEC VSXXX-AB digitizer",
+				 sizeof (mouse->name));
 			break;
 
 		default:
-			sprintf (mouse->name, "unknown DEC pointer device "
-					"(type = 0x%02x)", mouse->type);
+			snprintf (mouse->name, sizeof (mouse->name),
+				  "unknown DEC pointer device (type = 0x%02x)",
+				  mouse->type);
 			break;
 	}
 
-	printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x "
-			"on port %s\n", mouse->name, mouse->version,
-			mouse->country, mouse->phys);
+	printk (KERN_INFO
+		"Found %s version 0x%02x from country 0x%02x on port %s\n",
+		mouse->name, mouse->version, mouse->country, mouse->phys);
 }
 
 /*
@@ -503,8 +506,9 @@
 
 	mouse->dev = input_dev;
 	mouse->serio = serio;
-	sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer");
-	sprintf (mouse->phys, "%s/input0", serio->phys);
+	strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
+		 sizeof (mouse->name));
+	snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys);
 
 	input_dev->name = mouse->name;
 	input_dev->phys = mouse->phys;
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index b685a50..eb721b1 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -123,7 +123,9 @@
 
 	if (mousedev->touch) {
 		size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
-		if (size == 0) size = 256 * 2;
+		if (size == 0)
+			size = 256 * 2;
+
 		switch (code) {
 			case ABS_X:
 				fx(0) = value;
@@ -155,18 +157,24 @@
 	switch (code) {
 		case ABS_X:
 			size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
-			if (size == 0) size = xres ? : 1;
-			if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X];
-			if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X];
+			if (size == 0)
+				size = xres ? : 1;
+			if (value > dev->absmax[ABS_X])
+				value = dev->absmax[ABS_X];
+			if (value < dev->absmin[ABS_X])
+				value = dev->absmin[ABS_X];
 			mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
 			mousedev->packet.abs_event = 1;
 			break;
 
 		case ABS_Y:
 			size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
-			if (size == 0) size = yres ? : 1;
-			if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y];
-			if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y];
+			if (size == 0)
+				size = yres ? : 1;
+			if (value > dev->absmax[ABS_Y])
+				value = dev->absmax[ABS_Y];
+			if (value < dev->absmin[ABS_Y])
+				value = dev->absmin[ABS_Y];
 			mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
 			mousedev->packet.abs_event = 1;
 			break;
@@ -202,7 +210,7 @@
 		case BTN_SIDE:		index = 3; break;
 		case BTN_4:
 		case BTN_EXTRA:		index = 4; break;
-		default: 		return;
+		default:		return;
 	}
 
 	if (value) {
@@ -285,10 +293,9 @@
 		mousedev->touch = mousedev->pkt_count = 0;
 		mousedev->frac_dx = 0;
 		mousedev->frac_dy = 0;
-	}
-	else
-		if (!mousedev->touch)
-			mousedev->touch = jiffies;
+
+	} else if (!mousedev->touch)
+		mousedev->touch = jiffies;
 }
 
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
@@ -327,7 +334,7 @@
 					mousedev->pkt_count++;
 					/* Input system eats duplicate events, but we need all of them
 					 * to do correct averaging so apply present one forward
-			 		 */
+					 */
 					fx(0) = fx(1);
 					fy(0) = fy(1);
 				}
@@ -346,7 +353,9 @@
 {
 	int retval;
 	struct mousedev_list *list = file->private_data;
+
 	retval = fasync_helper(fd, file, on, &list->fasync);
+
 	return retval < 0 ? retval : 0;
 }
 
@@ -507,14 +516,16 @@
 				list->imexseq = 0;
 				list->mode = MOUSEDEV_EMUL_EXPS;
 			}
-		} else list->imexseq = 0;
+		} else
+			list->imexseq = 0;
 
 		if (c == mousedev_imps_seq[list->impsseq]) {
 			if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
 				list->impsseq = 0;
 				list->mode = MOUSEDEV_EMUL_IMPS;
 			}
-		} else list->impsseq = 0;
+		} else
+			list->impsseq = 0;
 
 		list->ps2[0] = 0xfa;
 
@@ -598,6 +609,7 @@
 static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 {
 	struct mousedev_list *list = file->private_data;
+
 	poll_wait(file, &list->mousedev->wait, wait);
 	return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
 		(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 161afdd..386023c 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -773,8 +773,7 @@
 
 	ts->last_msg = m;
 
-	if (request_irq(spi->irq, ads7846_irq,
-			SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+	if (request_irq(spi->irq, ads7846_irq, SA_TRIGGER_FALLING,
 			spi->dev.driver->name, ts)) {
 		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
 		err = -EBUSY;
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 466da19..b769b21 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -129,7 +129,7 @@
 
 	gunze->serio = serio;
 	gunze->dev = input_dev;
-	sprintf(gunze->phys, "%s/input0", serio->phys);
+	snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
 
 	input_dev->private = gunze;
 	input_dev->name = "Gunze AHL-51S TouchScreen";
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index a18d56b..2de2139 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -363,7 +363,7 @@
 
 	ts->serio = serio;
 	ts->dev = input_dev;
-	sprintf(ts->phys, "%s/input0", serio->phys);
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", serio->phys);
 
 	input_dev->name = "H3600 TouchScreen";
 	input_dev->phys = ts->phys;
@@ -399,16 +399,14 @@
 	set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
 	if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
-			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
-			"h3600_action", &ts->dev)) {
+			SA_SHIRQ | SA_INTERRUPT, "h3600_action", &ts->dev)) {
 		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
 		err = -EBUSY;
 		goto fail2;
 	}
 
 	if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
-			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
-			"h3600_suspend", &ts->dev)) {
+			SA_SHIRQ | SA_INTERRUPT, "h3600_suspend", &ts->dev)) {
 		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
 		err = -EBUSY;
 		goto fail3;
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 1d0d37e..8647a90 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -143,7 +143,7 @@
 
 	mtouch->serio = serio;
 	mtouch->dev = input_dev;
-	sprintf(mtouch->phys, "%s/input0", serio->phys);
+	snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
 
 	input_dev->private = mtouch;
 	input_dev->name = "MicroTouch Serial TouchScreen";
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index d678d14..5f9ecad 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -35,7 +35,7 @@
  * e-mail - mail your message to <jsimmons@infradead.org>.
  */
 
-#define TSDEV_MINOR_BASE 	128
+#define TSDEV_MINOR_BASE	128
 #define TSDEV_MINORS		32
 /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
 #define TSDEV_MINOR_MASK	15
@@ -230,6 +230,7 @@
 static unsigned int tsdev_poll(struct file *file, poll_table * wait)
 {
 	struct tsdev_list *list = file->private_data;
+
 	poll_wait(file, &list->tsdev->wait, wait);
 	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
 		(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
@@ -248,11 +249,13 @@
 				  sizeof (struct ts_calibration)))
 			retval = -EFAULT;
 		break;
+
 	case TS_SET_CAL:
 		if (copy_from_user (&tsdev->cal, (void __user *)arg,
 				    sizeof (struct ts_calibration)))
 			retval = -EFAULT;
 		break;
+
 	default:
 		retval = -EINVAL;
 		break;
@@ -284,9 +287,11 @@
 		case ABS_X:
 			tsdev->x = value;
 			break;
+
 		case ABS_Y:
 			tsdev->y = value;
 			break;
+
 		case ABS_PRESSURE:
 			if (value > handle->dev->absmax[ABS_PRESSURE])
 				value = handle->dev->absmax[ABS_PRESSURE];
@@ -307,6 +312,7 @@
 			else if (tsdev->x > xres)
 				tsdev->x = xres;
 			break;
+
 		case REL_Y:
 			tsdev->y += value;
 			if (tsdev->y < 0)
@@ -323,6 +329,7 @@
 			case 0:
 				tsdev->pressure = 0;
 				break;
+
 			case 1:
 				if (!tsdev->pressure)
 					tsdev->pressure = 1;
@@ -370,9 +377,8 @@
 	struct class_device *cdev;
 	int minor, delta;
 
-	for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
-	     minor++);
-	if (minor >= TSDEV_MINORS/2) {
+	for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
+	if (minor >= TSDEV_MINORS / 2) {
 		printk(KERN_ERR
 		       "tsdev: You have way too many touchscreens\n");
 		return NULL;
@@ -444,22 +450,22 @@
 	      .evbit	= { BIT(EV_KEY) | BIT(EV_REL) },
 	      .keybit	= { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
 	      .relbit	= { BIT(REL_X) | BIT(REL_Y) },
-	 },/* A mouse like device, at least one button, two relative axes */
+	}, /* A mouse like device, at least one button, two relative axes */
 
 	{
 	      .flags	= INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
 	      .evbit	= { BIT(EV_KEY) | BIT(EV_ABS) },
 	      .keybit	= { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
 	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) },
-	 },/* A tablet like device, at least touch detection, two absolute axes */
+	}, /* A tablet like device, at least touch detection, two absolute axes */
 
 	{
 	      .flags	= INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
 	      .evbit	= { BIT(EV_ABS) },
 	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
-	 },/* A tablet like device with several gradations of pressure */
+	}, /* A tablet like device with several gradations of pressure */
 
-	{},/* Terminating entry */
+	{} /* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(input, tsdev_ids);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 173c899..2e541fa 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -87,6 +87,11 @@
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 struct capiminor;
 
+struct datahandle_queue {
+	struct list_head	list;
+	u16			datahandle;
+};
+
 struct capiminor {
 	struct list_head list;
 	struct capincci  *nccip;
@@ -109,12 +114,9 @@
 	int                 outbytes;
 
 	/* transmit path */
-	struct datahandle_queue {
-		    struct datahandle_queue *next;
-		    u16                    datahandle;
-	} *ackqueue;
+	struct list_head ackqueue;
 	int nack;
-
+	spinlock_t ackqlock;
 };
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
@@ -156,48 +158,54 @@
 
 static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
 {
-	struct datahandle_queue *n, **pp;
+	struct datahandle_queue *n;
+	unsigned long flags;
 
 	n = kmalloc(sizeof(*n), GFP_ATOMIC);
-	if (!n) {
-	   printk(KERN_ERR "capi: alloc datahandle failed\n");
-	   return -1;
+	if (unlikely(!n)) {
+		printk(KERN_ERR "capi: alloc datahandle failed\n");
+		return -1;
 	}
-	n->next = NULL;
 	n->datahandle = datahandle;
-	for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
-	*pp = n;
+	INIT_LIST_HEAD(&n->list);
+	spin_lock_irqsave(&mp->ackqlock, flags);
+	list_add_tail(&n->list, &mp->ackqueue);
 	mp->nack++;
+	spin_unlock_irqrestore(&mp->ackqlock, flags);
 	return 0;
 }
 
 static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
 {
-	struct datahandle_queue **pp, *p;
+	struct datahandle_queue *p, *tmp;
+	unsigned long flags;
 
-	for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
- 		if ((*pp)->datahandle == datahandle) {
-			p = *pp;
-			*pp = (*pp)->next;
+	spin_lock_irqsave(&mp->ackqlock, flags);
+	list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+ 		if (p->datahandle == datahandle) {
+			list_del(&p->list);
 			kfree(p);
 			mp->nack--;
+			spin_unlock_irqrestore(&mp->ackqlock, flags);
 			return 0;
 		}
 	}
+	spin_unlock_irqrestore(&mp->ackqlock, flags);
 	return -1;
 }
 
 static void capiminor_del_all_ack(struct capiminor *mp)
 {
-	struct datahandle_queue **pp, *p;
+	struct datahandle_queue *p, *tmp;
+	unsigned long flags;
 
-	pp = &mp->ackqueue;
-	while (*pp) {
-		p = *pp;
-		*pp = (*pp)->next;
+	spin_lock_irqsave(&mp->ackqlock, flags);
+	list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+		list_del(&p->list);
 		kfree(p);
 		mp->nack--;
 	}
+	spin_unlock_irqrestore(&mp->ackqlock, flags);
 }
 
 
@@ -220,6 +228,8 @@
 	mp->ncci = ncci;
 	mp->msgid = 0;
 	atomic_set(&mp->ttyopencount,0);
+	INIT_LIST_HEAD(&mp->ackqueue);
+	spin_lock_init(&mp->ackqlock);
 
 	skb_queue_head_init(&mp->inqueue);
 	skb_queue_head_init(&mp->outqueue);
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index f1a1f9a..1f5ebe9 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -592,7 +592,7 @@
 } /* put_address */
 
 /*************************************/
-/* report a succesfull interrogation */
+/* report a successful interrogation */
 /*************************************/
 static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
 { char *src = ic->parm.dss1_io.data;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index eb41aba..8a45715 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -65,23 +65,22 @@
 
 MODULE_DEVICE_TABLE(usb, gigaset_table);
 
-/*======================= local function prototypes =============================*/
+/*======================= local function prototypes ==========================*/
 
-/* This function is called if a new device is connected to the USB port. It
- * checks whether this new device belongs to this driver.
- */
+/* function called if a new device belonging to this driver is connected */
 static int gigaset_probe(struct usb_interface *interface,
 			 const struct usb_device_id *id);
 
 /* Function will be called if the device is unplugged */
 static void gigaset_disconnect(struct usb_interface *interface);
 
-static void read_ctrl_callback(struct urb *, struct pt_regs *);
+static int atread_submit(struct cardstate *, int);
 static void stopurbs(struct bas_bc_state *);
+static int req_submit(struct bc_state *, int, int, int);
 static int atwrite_submit(struct cardstate *, unsigned char *, int);
 static int start_cbsend(struct cardstate *);
 
-/*==============================================================================*/
+/*============================================================================*/
 
 struct bas_cardstate {
 	struct usb_device	*udev;		/* USB device pointer */
@@ -91,6 +90,7 @@
 	struct urb		*urb_ctrl;	/* control pipe default URB */
 	struct usb_ctrlrequest	dr_ctrl;
 	struct timer_list	timer_ctrl;	/* control request timeout */
+	int			retry_ctrl;
 
 	struct timer_list	timer_atrdy;	/* AT command ready timeout */
 	struct urb		*urb_cmd_out;	/* for sending AT commands */
@@ -307,6 +307,7 @@
  * hang up any existing connection because of an unrecoverable error
  * This function may be called from any context and takes care of scheduling
  * the necessary actions for execution outside of interrupt context.
+ * cs->lock must not be held.
  * argument:
  *	B channel control structure
  */
@@ -325,14 +326,17 @@
 
 /* error_reset
  * reset Gigaset device because of an unrecoverable error
- * This function may be called from any context, and should take care of
+ * This function may be called from any context, and takes care of
  * scheduling the necessary actions for execution outside of interrupt context.
- * Right now, it just generates a kernel message calling for help.
+ * cs->lock must not be held.
  * argument:
  *	controller state structure
  */
 static inline void error_reset(struct cardstate *cs)
 {
+	/* close AT command channel to recover (ignore errors) */
+	req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
+
 	//FIXME try to recover without bothering the user
 	dev_err(cs->dev,
 	    "unrecoverable error - please disconnect Gigaset base to reset\n");
@@ -403,14 +407,30 @@
 {
 	struct cardstate *cs = (struct cardstate *) data;
 	struct bas_cardstate *ucs = cs->hw.bas;
+	int rc;
 
 	if (!ucs->rcvbuf_size) {
 		gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
 		return;
 	}
 
-	dev_err(cs->dev, "timeout reading AT response\n");
-	error_reset(cs);	//FIXME retry?
+	if (ucs->retry_cmd_in++ < BAS_RETRY) {
+		dev_notice(cs->dev, "control read: timeout, retry %d\n",
+			   ucs->retry_cmd_in);
+		rc = atread_submit(cs, BAS_TIMEOUT);
+		if (rc >= 0 || rc == -ENODEV)
+			/* resubmitted or disconnected */
+			/* - bypass regular exit block */
+			return;
+	} else {
+		dev_err(cs->dev,
+			"control read: timeout, giving up after %d tries\n",
+			ucs->retry_cmd_in);
+	}
+	kfree(ucs->rcvbuf);
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+	error_reset(cs);
 }
 
 /* set/clear bits in base connection state, return previous state
@@ -428,6 +448,96 @@
 	return state;
 }
 
+/* read_ctrl_callback
+ * USB completion handler for control pipe input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ *	urb	USB request block
+ *		urb->context = inbuf structure for controller state
+ */
+static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct inbuf_t *inbuf = urb->context;
+	struct cardstate *cs = inbuf->cs;
+	struct bas_cardstate *ucs = cs->hw.bas;
+	int have_data = 0;
+	unsigned numbytes;
+	int rc;
+
+	update_basstate(ucs, 0, BS_ATRDPEND);
+
+	if (!ucs->rcvbuf_size) {
+		dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
+		return;
+	}
+
+	del_timer(&ucs->timer_cmd_in);
+
+	switch (urb->status) {
+	case 0:				/* normal completion */
+		numbytes = urb->actual_length;
+		if (unlikely(numbytes != ucs->rcvbuf_size)) {
+			dev_warn(cs->dev,
+			       "control read: received %d chars, expected %d\n",
+				 numbytes, ucs->rcvbuf_size);
+			if (numbytes > ucs->rcvbuf_size)
+				numbytes = ucs->rcvbuf_size;
+		}
+
+		/* copy received bytes to inbuf */
+		have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
+
+		if (unlikely(numbytes < ucs->rcvbuf_size)) {
+			/* incomplete - resubmit for remaining bytes */
+			ucs->rcvbuf_size -= numbytes;
+			ucs->retry_cmd_in = 0;
+			rc = atread_submit(cs, BAS_TIMEOUT);
+			if (rc >= 0 || rc == -ENODEV)
+				/* resubmitted or disconnected */
+				/* - bypass regular exit block */
+				return;
+			error_reset(cs);
+		}
+		break;
+
+	case -ENOENT:			/* cancelled */
+	case -ECONNRESET:		/* cancelled (async) */
+	case -EINPROGRESS:		/* pending */
+	case -ENODEV:			/* device removed */
+	case -ESHUTDOWN:		/* device shut down */
+		/* no action necessary */
+		gig_dbg(DEBUG_USBREQ, "%s: %s",
+			__func__, get_usb_statmsg(urb->status));
+		break;
+
+	default:			/* severe trouble */
+		dev_warn(cs->dev, "control read: %s\n",
+			 get_usb_statmsg(urb->status));
+		if (ucs->retry_cmd_in++ < BAS_RETRY) {
+			dev_notice(cs->dev, "control read: retry %d\n",
+				   ucs->retry_cmd_in);
+			rc = atread_submit(cs, BAS_TIMEOUT);
+			if (rc >= 0 || rc == -ENODEV)
+				/* resubmitted or disconnected */
+				/* - bypass regular exit block */
+				return;
+		} else {
+			dev_err(cs->dev,
+				"control read: giving up after %d tries\n",
+				ucs->retry_cmd_in);
+		}
+		error_reset(cs);
+	}
+
+	kfree(ucs->rcvbuf);
+	ucs->rcvbuf = NULL;
+	ucs->rcvbuf_size = 0;
+	if (have_data) {
+		gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
+		gigaset_schedule_event(cs);
+	}
+}
+
 /* atread_submit
  * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout
  * parameters:
@@ -466,7 +576,7 @@
 	if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
 		update_basstate(ucs, 0, BS_ATRDPEND);
 		dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n",
-			get_usb_statmsg(ret));
+			get_usb_rcmsg(ret));
 		return ret;
 	}
 
@@ -611,9 +721,12 @@
 			kfree(ucs->rcvbuf);
 			ucs->rcvbuf = NULL;
 			ucs->rcvbuf_size = 0;
-			if (rc != -ENODEV)
+			if (rc != -ENODEV) {
 				//FIXME corrective action?
+				spin_unlock_irqrestore(&cs->lock, flags);
 				error_reset(cs);
+				break;
+			}
 		}
 		spin_unlock_irqrestore(&cs->lock, flags);
 		break;
@@ -643,97 +756,6 @@
 	}
 }
 
-/* read_ctrl_callback
- * USB completion handler for control pipe input
- * called by the USB subsystem in interrupt context
- * parameter:
- *	urb	USB request block
- *		urb->context = inbuf structure for controller state
- */
-static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
-{
-	struct inbuf_t *inbuf = urb->context;
-	struct cardstate *cs = inbuf->cs;
-	struct bas_cardstate *ucs = cs->hw.bas;
-	int have_data = 0;
-	unsigned numbytes;
-	int rc;
-
-	update_basstate(ucs, 0, BS_ATRDPEND);
-
-	if (!ucs->rcvbuf_size) {
-		dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
-		return;
-	}
-
-	del_timer(&ucs->timer_cmd_in);
-
-	switch (urb->status) {
-	case 0:				/* normal completion */
-		numbytes = urb->actual_length;
-		if (unlikely(numbytes == 0)) {
-			dev_warn(cs->dev,
-				 "control read: empty block received\n");
-			goto retry;
-		}
-		if (unlikely(numbytes != ucs->rcvbuf_size)) {
-			dev_warn(cs->dev,
-			       "control read: received %d chars, expected %d\n",
-				 numbytes, ucs->rcvbuf_size);
-			if (numbytes > ucs->rcvbuf_size)
-				numbytes = ucs->rcvbuf_size;
-		}
-
-		/* copy received bytes to inbuf */
-		have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
-
-		if (unlikely(numbytes < ucs->rcvbuf_size)) {
-			/* incomplete - resubmit for remaining bytes */
-			ucs->rcvbuf_size -= numbytes;
-			ucs->retry_cmd_in = 0;
-			goto retry;
-		}
-		break;
-
-	case -ENOENT:			/* cancelled */
-	case -ECONNRESET:		/* cancelled (async) */
-	case -EINPROGRESS:		/* pending */
-	case -ENODEV:			/* device removed */
-	case -ESHUTDOWN:		/* device shut down */
-		/* no action necessary */
-		gig_dbg(DEBUG_USBREQ, "%s: %s",
-			__func__, get_usb_statmsg(urb->status));
-		break;
-
-	default:			/* severe trouble */
-		dev_warn(cs->dev, "control read: %s\n",
-			 get_usb_statmsg(urb->status));
-	retry:
-		if (ucs->retry_cmd_in++ < BAS_RETRY) {
-			dev_notice(cs->dev, "control read: retry %d\n",
-				   ucs->retry_cmd_in);
-			rc = atread_submit(cs, BAS_TIMEOUT);
-			if (rc >= 0 || rc == -ENODEV)
-				/* resubmitted or disconnected */
-				/* - bypass regular exit block */
-				return;
-		} else {
-			dev_err(cs->dev,
-				"control read: giving up after %d tries\n",
-				ucs->retry_cmd_in);
-		}
-		error_reset(cs);
-	}
-
-	kfree(ucs->rcvbuf);
-	ucs->rcvbuf = NULL;
-	ucs->rcvbuf_size = 0;
-	if (have_data) {
-		gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
-		gigaset_schedule_event(cs);
-	}
-}
-
 /* read_iso_callback
  * USB completion handler for B channel isochronous input
  * called by the USB subsystem in interrupt context
@@ -1378,6 +1400,7 @@
 	case HD_CLOSE_B1CHANNEL:
 		dev_err(bcs->cs->dev, "timeout closing channel %d\n",
 			bcs->channel + 1);
+		error_reset(bcs->cs);
 		break;
 
 	default:
@@ -1396,22 +1419,61 @@
 static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
 {
 	struct bas_cardstate *ucs = urb->context;
+	int rc;
 	unsigned long flags;
 
-	spin_lock_irqsave(&ucs->lock, flags);
-	if (urb->status && ucs->pending) {
-		dev_err(&ucs->interface->dev,
-			"control request 0x%02x failed: %s\n",
-			ucs->pending, get_usb_statmsg(urb->status));
-		del_timer(&ucs->timer_ctrl);
-		ucs->pending = 0;
-	}
-	/* individual handling of specific request types */
-	switch (ucs->pending) {
-	case HD_DEVICE_INIT_ACK:		/* no reply expected */
-		ucs->pending = 0;
+	/* check status */
+	switch (urb->status) {
+	case 0:					/* normal completion */
+		spin_lock_irqsave(&ucs->lock, flags);
+		switch (ucs->pending) {
+		case HD_DEVICE_INIT_ACK:	/* no reply expected */
+			del_timer(&ucs->timer_ctrl);
+			ucs->pending = 0;
+			break;
+		}
+		spin_unlock_irqrestore(&ucs->lock, flags);
+		return;
+
+	case -ENOENT:			/* cancelled */
+	case -ECONNRESET:		/* cancelled (async) */
+	case -EINPROGRESS:		/* pending */
+	case -ENODEV:			/* device removed */
+	case -ESHUTDOWN:		/* device shut down */
+		/* ignore silently */
+		gig_dbg(DEBUG_USBREQ, "%s: %s",
+			__func__, get_usb_statmsg(urb->status));
 		break;
+
+	default:				/* any failure */
+		if (++ucs->retry_ctrl > BAS_RETRY) {
+			dev_err(&ucs->interface->dev,
+				"control request 0x%02x failed: %s\n",
+				ucs->dr_ctrl.bRequest,
+				get_usb_statmsg(urb->status));
+			break;		/* give up */
+		}
+		dev_notice(&ucs->interface->dev,
+			   "control request 0x%02x: %s, retry %d\n",
+			   ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
+			   ucs->retry_ctrl);
+		/* urb->dev is clobbered by USB subsystem */
+		urb->dev = ucs->udev;
+		rc = usb_submit_urb(urb, SLAB_ATOMIC);
+		if (unlikely(rc)) {
+			dev_err(&ucs->interface->dev,
+				"could not resubmit request 0x%02x: %s\n",
+				ucs->dr_ctrl.bRequest, get_usb_rcmsg(rc));
+			break;
+		}
+		/* resubmitted */
+		return;
 	}
+
+	/* failed, clear pending request */
+	spin_lock_irqsave(&ucs->lock, flags);
+	del_timer(&ucs->timer_ctrl);
+	ucs->pending = 0;
 	spin_unlock_irqrestore(&ucs->lock, flags);
 }
 
@@ -1455,9 +1517,11 @@
 			     usb_sndctrlpipe(ucs->udev, 0),
 			     (unsigned char*) &ucs->dr_ctrl, NULL, 0,
 			     write_ctrl_callback, ucs);
-	if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) {
+	ucs->retry_ctrl = 0;
+	ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC);
+	if (unlikely(ret)) {
 		dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n",
-			req, get_usb_statmsg(ret));
+			req, get_usb_rcmsg(ret));
 		spin_unlock_irqrestore(&ucs->lock, flags);
 		return ret;
 	}
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 18e05c0..44f02db 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -1262,7 +1262,8 @@
 		break;
 	case ACT_HUPMODEM:
 		/* send "+++" (hangup in unimodem mode) */
-		cs->ops->write_cmd(cs, "+++", 3, NULL);
+		if (cs->connected)
+			cs->ops->write_cmd(cs, "+++", 3, NULL);
 		break;
 	case ACT_RING:
 		/* get fresh AT state structure for new CID */
@@ -1294,7 +1295,6 @@
 		break;
 	case ACT_ICALL:
 		handle_icall(cs, bcs, p_at_state);
-		at_state = *p_at_state;
 		break;
 	case ACT_FAILSDOWN:
 		dev_warn(cs->dev, "Could not shut down the device.\n");
@@ -1334,10 +1334,8 @@
 			 */
 			at_state->pending_commands |= PC_DLE0;
 			atomic_set(&cs->commands_pending, 1);
-		} else {
+		} else
 			disconnect(p_at_state);
-			at_state = *p_at_state;
-		}
 		break;
 	case ACT_FAKEDLE0:
 		at_state->int_var[VAR_ZDLE] = 0;
@@ -1354,10 +1352,8 @@
 		at_state->cid = -1;
 		if (bcs && cs->onechannel)
 			at_state->pending_commands |= PC_DLE0;
-		else {
+		else
 			disconnect(p_at_state);
-			at_state = *p_at_state;
-		}
 		schedule_init(cs, MS_RECOVER);
 		break;
 	case ACT_FAILDLE0:
@@ -1410,7 +1406,6 @@
 
 	case ACT_ABORTACCEPT:	/* hangup/error/timeout during ICALL processing */
 		disconnect(p_at_state);
-		at_state = *p_at_state;
 		break;
 
 	case ACT_ABORTDIAL:	/* error/timeout during dial preparation */
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index abecabf..aacbf0d 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1402,12 +1402,12 @@
 			}
 			/* No, locate it in the table */
 			if (cset == 0) {
-				for (i = 0; i < IESIZE; i++)
+				for (i = 0; i < IESIZE_NI1; i++)
 					if (*buf == ielist_ni1[i].nr)
 						break;
 
 				/* When not found, give appropriate msg */
-				if (i != IESIZE) {
+				if (i != IESIZE_NI1) {
 					dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
 					dp += ielist_ni1[i].f(dp, buf);
 				} else
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 81accdf..b26e509 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -933,7 +933,7 @@
 			count_put = count_pull;
 			if(count_put > 1)
 				tty_insert_flip_string(tty, skb->data, count_put - 1);
-			last = skb->data[count_put] - 1;
+			last = skb->data[count_put - 1];
 			len -= count_put;
 #ifdef CONFIG_ISDN_AUDIO
 		}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index f573d5a..9650998 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -93,5 +93,14 @@
 	  This allows LEDs to be controlled by IDE disk activity.
 	  If unsure, say Y.
 
+config LEDS_TRIGGER_HEARTBEAT
+	tristate "LED Heartbeat Trigger"
+	depends LEDS_TRIGGERS
+	help
+	  This allows LEDs to be controlled by a CPU load average.
+	  The flash frequency is a hyperbolic function of the 1-minute
+	  load average.
+	  If unsure, say Y.
+
 endmenu
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index dcea100..88d3b6e 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -16,3 +16,4 @@
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
 obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)	+= ledtrig-ide-disk.o
+obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)	+= ledtrig-heartbeat.o
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
new file mode 100644
index 0000000..4bf8cec
--- /dev/null
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -0,0 +1,118 @@
+/*
+ * LED Heartbeat Trigger
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * Based on Richard Purdie's ledtrig-timer.c and some arch's
+ * CONFIG_HEARTBEAT code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+struct heartbeat_trig_data {
+	unsigned int phase;
+	unsigned int period;
+	struct timer_list timer;
+};
+
+static void led_heartbeat_function(unsigned long data)
+{
+	struct led_classdev *led_cdev = (struct led_classdev *) data;
+	struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+	unsigned long brightness = LED_OFF;
+	unsigned long delay = 0;
+
+	/* acts like an actual heart beat -- ie thump-thump-pause... */
+	switch (heartbeat_data->phase) {
+	case 0:
+		/*
+		 * The hyperbolic function below modifies the
+		 * heartbeat period length in dependency of the
+		 * current (1min) load. It goes through the points
+		 * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
+		 */
+		heartbeat_data->period = 300 +
+			(6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
+		heartbeat_data->period =
+			msecs_to_jiffies(heartbeat_data->period);
+		delay = msecs_to_jiffies(70);
+		heartbeat_data->phase++;
+		brightness = LED_FULL;
+		break;
+	case 1:
+		delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
+		heartbeat_data->phase++;
+		break;
+	case 2:
+		delay = msecs_to_jiffies(70);
+		heartbeat_data->phase++;
+		brightness = LED_FULL;
+		break;
+	default:
+		delay = heartbeat_data->period - heartbeat_data->period / 4 -
+			msecs_to_jiffies(70);
+		heartbeat_data->phase = 0;
+		break;
+	}
+
+	led_set_brightness(led_cdev, brightness);
+	mod_timer(&heartbeat_data->timer, jiffies + delay);
+}
+
+static void heartbeat_trig_activate(struct led_classdev *led_cdev)
+{
+	struct heartbeat_trig_data *heartbeat_data;
+
+	heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
+	if (!heartbeat_data)
+		return;
+
+	led_cdev->trigger_data = heartbeat_data;
+	setup_timer(&heartbeat_data->timer,
+		    led_heartbeat_function, (unsigned long) led_cdev);
+	heartbeat_data->phase = 0;
+	led_heartbeat_function(heartbeat_data->timer.data);
+}
+
+static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+
+	if (heartbeat_data) {
+		del_timer_sync(&heartbeat_data->timer);
+		kfree(heartbeat_data);
+	}
+}
+
+static struct led_trigger heartbeat_led_trigger = {
+	.name     = "heartbeat",
+	.activate = heartbeat_trig_activate,
+	.deactivate = heartbeat_trig_deactivate,
+};
+
+static int __init heartbeat_trig_init(void)
+{
+	return led_trigger_register(&heartbeat_led_trigger);
+}
+
+static void __exit heartbeat_trig_exit(void)
+{
+	led_trigger_unregister(&heartbeat_led_trigger);
+}
+
+module_init(heartbeat_trig_init);
+module_exit(heartbeat_trig_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Heartbeat LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index ccf5df4..37cd6ee 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -99,17 +99,22 @@
 	  devices are not fully supported in the bay as I never had one to
 	  try with
 
-# made a separate option since backlight may end up beeing used
-# on non-powerbook machines (but only on PMU based ones AFAIK)
 config PMAC_BACKLIGHT
 	bool "Backlight control for LCD screens"
 	depends on ADB_PMU && (BROKEN || !PPC64)
 	help
-	  Say Y here to build in code to manage the LCD backlight on a
-	  Macintosh PowerBook.  With this code, the backlight will be turned
-	  on and off appropriately on power-management and lid-open/lid-closed
-	  events; also, the PowerBook button device will be enabled so you can
-	  change the screen brightness.
+	  Say Y here to enable Macintosh specific extensions of the generic
+	  backlight code. With this enabled, the brightness keys on older
+	  PowerBooks will be enabled so you can change the screen brightness.
+	  Newer models should use an userspace daemon like pbbuttonsd.
+
+config PMAC_BACKLIGHT_LEGACY
+	bool "Provide legacy ioctl's on /dev/pmu for the backlight"
+	depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
+	help
+	  Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
+	  programs which use this old interface. New and updated programs
+	  should use the backlight classes in sysfs.
 
 config ADB_MACIO
 	bool "Include MacIO (CHRP) ADB driver"
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6081acd..45a268f 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -11,7 +11,8 @@
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
 
-obj-$(CONFIG_ADB_PMU)		+= via-pmu.o
+obj-$(CONFIG_ADB_PMU)		+= via-pmu.o via-pmu-event.o
+obj-$(CONFIG_PMAC_BACKLIGHT)	+= via-pmu-backlight.o
 obj-$(CONFIG_ADB_CUDA)		+= via-cuda.o
 obj-$(CONFIG_PMAC_APM_EMU)	+= apm_emu.o
 obj-$(CONFIG_PMAC_SMU)		+= smu.o
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 394334e..cbfbbe2 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -179,7 +179,7 @@
 	/* 0x65 */ KEY_F9,		/*  67 */
 	/* 0x66 */ KEY_HANJA,		/* 123 */
 	/* 0x67 */ KEY_F11,		/*  87 */
-	/* 0x68 */ KEY_HANGUEL,		/* 122 */
+	/* 0x68 */ KEY_HANGEUL,		/* 122 */
 	/* 0x69 */ KEY_SYSRQ,		/*  99 */
 	/* 0x6a */ 0,
 	/* 0x6b */ KEY_SCROLLLOCK,	/*  70 */
@@ -503,9 +503,7 @@
 	case 0x1f: /* Powerbook button device */
 	  {
 		int down = (data[1] == (data[1] & 0xf));
-#ifdef CONFIG_PMAC_BACKLIGHT
-		int backlight = get_backlight_level();
-#endif
+
 		/*
 		 * XXX: Where is the contrast control for the passive?
 		 *  -- Cort
@@ -530,29 +528,17 @@
 
 		case 0xa:	/* brightness decrease */
 #ifdef CONFIG_PMAC_BACKLIGHT
-			if (!disable_kernel_backlight) {
-				if (down && backlight >= 0) {
-					if (backlight > BACKLIGHT_OFF)
-						set_backlight_level(backlight-1);
-					else
-						set_backlight_level(BACKLIGHT_OFF);
-				}
-			}
-#endif /* CONFIG_PMAC_BACKLIGHT */
+			if (!disable_kernel_backlight && down)
+				pmac_backlight_key_down();
+#endif
 			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
 			break;
 
 		case 0x9:	/* brightness increase */
 #ifdef CONFIG_PMAC_BACKLIGHT
-			if (!disable_kernel_backlight) {
-				if (down && backlight >= 0) {
-					if (backlight < BACKLIGHT_MAX)
-						set_backlight_level(backlight+1);
-					else 
-						set_backlight_level(BACKLIGHT_MAX);
-				}
-			}
-#endif /* CONFIG_PMAC_BACKLIGHT */
+			if (!disable_kernel_backlight && down)
+				pmac_backlight_key_up();
+#endif
 			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
 			break;
 
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
new file mode 100644
index 0000000..b42d05f
--- /dev/null
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -0,0 +1,150 @@
+/*
+ * Backlight code for via-pmu
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ * Copyright (C) 2006      Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ */
+
+#include <asm/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/backlight.h>
+#include <asm/prom.h>
+
+#define MAX_PMU_LEVEL 0xFF
+
+static struct device_node *vias;
+static struct backlight_properties pmu_backlight_data;
+
+static int pmu_backlight_get_level_brightness(struct fb_info *info,
+		int level)
+{
+	int pmulevel;
+
+	/* Get and convert the value */
+	mutex_lock(&info->bl_mutex);
+	pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
+	mutex_unlock(&info->bl_mutex);
+
+	if (pmulevel < 0)
+		pmulevel = 0;
+	else if (pmulevel > MAX_PMU_LEVEL)
+		pmulevel = MAX_PMU_LEVEL;
+
+	return pmulevel;
+}
+
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+	struct fb_info *info = class_get_devdata(&bd->class_dev);
+	struct adb_request req;
+	int pmulevel, level = bd->props->brightness;
+
+	if (vias == NULL)
+		return -ENODEV;
+
+	if (bd->props->power != FB_BLANK_UNBLANK ||
+	    bd->props->fb_blank != FB_BLANK_UNBLANK)
+		level = 0;
+
+	pmulevel = pmu_backlight_get_level_brightness(info, level);
+
+	pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
+	pmu_wait_complete(&req);
+
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+		PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
+	pmu_wait_complete(&req);
+
+	return 0;
+}
+
+static int pmu_backlight_get_brightness(struct backlight_device *bd)
+{
+	return bd->props->brightness;
+}
+
+static struct backlight_properties pmu_backlight_data = {
+	.owner		= THIS_MODULE,
+	.get_brightness	= pmu_backlight_get_brightness,
+	.update_status	= pmu_backlight_update_status,
+	.max_brightness	= (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void __init pmu_backlight_init(struct device_node *in_vias)
+{
+	struct backlight_device *bd;
+	struct fb_info *info;
+	char name[10];
+	int level, autosave;
+
+	vias = in_vias;
+
+	/* Special case for the old PowerBook since I can't test on it */
+	autosave =
+		machine_is_compatible("AAPL,3400/2400") ||
+		machine_is_compatible("AAPL,3500");
+
+	if (!autosave &&
+	    !pmac_has_backlight_type("pmu") &&
+	    !machine_is_compatible("AAPL,PowerBook1998") &&
+	    !machine_is_compatible("PowerBook1,1"))
+		return;
+
+	/* Actually, this is a hack, but I don't know of a better way
+	 * to get the first framebuffer device.
+	 */
+	info = registered_fb[0];
+	if (!info) {
+		printk("pmubl: No framebuffer found\n");
+		goto error;
+	}
+
+	snprintf(name, sizeof(name), "pmubl%d", info->node);
+
+	bd = backlight_device_register(name, info, &pmu_backlight_data);
+	if (IS_ERR(bd)) {
+		printk("pmubl: Backlight registration failed\n");
+		goto error;
+	}
+
+	mutex_lock(&info->bl_mutex);
+	info->bl_dev = bd;
+	fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
+	mutex_unlock(&info->bl_mutex);
+
+	level = pmu_backlight_data.max_brightness;
+
+	if (autosave) {
+		/* read autosaved value if available */
+		struct adb_request req;
+		pmu_request(&req, NULL, 2, 0xd9, 0);
+		pmu_wait_complete(&req);
+
+		mutex_lock(&info->bl_mutex);
+		level = pmac_backlight_curve_lookup(info,
+				(req.reply[0] >> 4) *
+				pmu_backlight_data.max_brightness / 15);
+		mutex_unlock(&info->bl_mutex);
+	}
+
+	up(&bd->sem);
+	bd->props->brightness = level;
+	bd->props->power = FB_BLANK_UNBLANK;
+	bd->props->update_status(bd);
+	down(&bd->sem);
+
+	mutex_lock(&pmac_backlight_mutex);
+	if (!pmac_backlight)
+		pmac_backlight = bd;
+	mutex_unlock(&pmac_backlight_mutex);
+
+	printk("pmubl: Backlight initialized (%s)\n", name);
+
+	return;
+
+error:
+	return;
+}
diff --git a/drivers/macintosh/via-pmu-event.c b/drivers/macintosh/via-pmu-event.c
new file mode 100644
index 0000000..25cd565
--- /dev/null
+++ b/drivers/macintosh/via-pmu-event.c
@@ -0,0 +1,80 @@
+/*
+ * via-pmu event device for reporting some events that come through the PMU
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include "via-pmu-event.h"
+
+static struct input_dev *pmu_input_dev;
+
+static int __init via_pmu_event_init(void)
+{
+	int err;
+
+	/* do other models report button/lid status? */
+	if (pmu_get_model() != PMU_KEYLARGO_BASED)
+		return -ENODEV;
+
+	pmu_input_dev = input_allocate_device();
+	if (!pmu_input_dev)
+		return -ENOMEM;
+
+	pmu_input_dev->name = "PMU";
+	pmu_input_dev->id.bustype = BUS_HOST;
+	pmu_input_dev->id.vendor = 0x0001;
+	pmu_input_dev->id.product = 0x0001;
+	pmu_input_dev->id.version = 0x0100;
+
+	set_bit(EV_KEY, pmu_input_dev->evbit);
+	set_bit(EV_SW, pmu_input_dev->evbit);
+	set_bit(KEY_POWER, pmu_input_dev->keybit);
+	set_bit(SW_LID, pmu_input_dev->swbit);
+
+	err = input_register_device(pmu_input_dev);
+	if (err)
+		input_free_device(pmu_input_dev);
+	return err;
+}
+
+void via_pmu_event(int key, int down)
+{
+
+	if (unlikely(!pmu_input_dev))
+		return;
+
+	switch (key) {
+	case PMU_EVT_POWER:
+		input_report_key(pmu_input_dev, KEY_POWER, down);
+		break;
+	case PMU_EVT_LID:
+		input_report_switch(pmu_input_dev, SW_LID, down);
+		break;
+	default:
+		/* no such key handled */
+		return;
+	}
+
+	input_sync(pmu_input_dev);
+}
+
+late_initcall(via_pmu_event_init);
diff --git a/drivers/macintosh/via-pmu-event.h b/drivers/macintosh/via-pmu-event.h
new file mode 100644
index 0000000..72c54de
--- /dev/null
+++ b/drivers/macintosh/via-pmu-event.h
@@ -0,0 +1,8 @@
+#ifndef __VIA_PMU_EVENT_H
+#define __VIA_PMU_EVENT_H
+
+#define PMU_EVT_POWER	0
+#define PMU_EVT_LID	1
+extern void via_pmu_event(int key, int down);
+
+#endif /* __VIA_PMU_EVENT_H */
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index c63d4e7..1ab4f16 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -69,6 +69,8 @@
 #include <asm/open_pic.h>
 #endif
 
+#include "via-pmu-event.h"
+
 /* Some compile options */
 #undef SUSPEND_USES_PMU
 #define DEBUG_SLEEP
@@ -144,7 +146,6 @@
 static int data_len;
 static volatile int adb_int_pending;
 static volatile int disable_poll;
-static struct adb_request bright_req_1, bright_req_2;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
@@ -161,7 +162,7 @@
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 static int option_lid_wakeup = 1;
 #endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT)
+#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
 static int sleep_in_progress;
 #endif
 static unsigned long async_req_locks;
@@ -208,10 +209,6 @@
 			  int count, int *eof, void *data);
 static int proc_get_irqstats(char *page, char **start, off_t off,
 			  int count, int *eof, void *data);
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int pmu_set_backlight_level(int level, void* data);
-static int pmu_set_backlight_enable(int on, int level, void* data);
-#endif /* CONFIG_PMAC_BACKLIGHT */
 static void pmu_pass_intr(unsigned char *data, int len);
 static int proc_get_batt(char *page, char **start, off_t off,
 			int count, int *eof, void *data);
@@ -292,13 +289,6 @@
 	"Core99"
 };
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static struct backlight_controller pmu_backlight_controller = {
-	pmu_set_backlight_enable,
-	pmu_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 int __init find_via_pmu(void)
 {
 	u64 taddr;
@@ -417,8 +407,6 @@
 	if (vias == NULL)
 		return -ENODEV;
 
-	bright_req_1.complete = 1;
-	bright_req_2.complete = 1;
 	batt_req.complete = 1;
 
 #ifndef CONFIG_PPC_MERGE
@@ -483,9 +471,9 @@
 		return -ENODEV;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	/* Enable backlight */
-	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+	/* Initialize backlight */
+	pmu_backlight_init(vias);
+#endif
 
 #ifdef CONFIG_PPC32
   	if (machine_is_compatible("AAPL,3400/2400") ||
@@ -1424,7 +1412,7 @@
 #ifdef CONFIG_INPUT_ADBHID
 			if (!disable_kernel_backlight)
 #endif /* CONFIG_INPUT_ADBHID */
-				set_backlight_level(data[1] >> 4);
+				pmac_backlight_set_legacy_brightness(data[1] >> 4);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 	}
 	/* Tick interrupt */
@@ -1441,6 +1429,12 @@
 		if (pmu_battery_count)
 			query_battery_state();
 		pmu_pass_intr(data, len);
+		/* len == 6 is probably a bad check. But how do I
+		 * know what PMU versions send what events here? */
+		if (len == 6) {
+			via_pmu_event(PMU_EVT_POWER, !!(data[1]&8));
+			via_pmu_event(PMU_EVT_LID, data[1]&1);
+		}
 	} else {
 	       pmu_pass_intr(data, len);
 	}
@@ -1674,61 +1668,6 @@
 	return IRQ_NONE;
 }
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_to_bright[] = {
-	0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
-	0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
-};
- 
-static int
-pmu_set_backlight_enable(int on, int level, void* data)
-{
-	struct adb_request req;
-	
-	if (vias == NULL)
-		return -ENODEV;
-
-	if (on) {
-		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
-			    backlight_to_bright[level]);
-		pmu_wait_complete(&req);
-	}
-	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
-		    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
-       	pmu_wait_complete(&req);
-
-	return 0;
-}
-
-static void
-pmu_bright_complete(struct adb_request *req)
-{
-	if (req == &bright_req_1)
-		clear_bit(1, &async_req_locks);
-	if (req == &bright_req_2)
-		clear_bit(2, &async_req_locks);
-}
-
-static int
-pmu_set_backlight_level(int level, void* data)
-{
-	if (vias == NULL)
-		return -ENODEV;
-
-	if (test_and_set_bit(1, &async_req_locks))
-		return -EAGAIN;
-	pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
-		backlight_to_bright[level]);
-	if (test_and_set_bit(2, &async_req_locks))
-		return -EAGAIN;
-	pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
-		    PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
-					 PMU_POW_ON : PMU_POW_OFF));
-
-	return 0;
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 void
 pmu_enable_irled(int on)
 {
@@ -2145,9 +2084,8 @@
 		return -EBUSY;
 	}
 
-	/* Wait for completion of async backlight requests */
-	while (!bright_req_1.complete || !bright_req_2.complete ||
-			!batt_req.complete)
+	/* Wait for completion of async requests */
+	while (!batt_req.complete)
 		pmu_poll();
 
 	/* Giveup the lazy FPU & vec so we don't have to back them
@@ -2678,26 +2616,34 @@
 			return put_user(1, argp);
 #endif /* CONFIG_PM && CONFIG_PPC32 */
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-	/* Backlight should have its own device or go via
-	 * the fbdev
-	 */
+#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
+	/* Compatibility ioctl's for backlight */
 	case PMU_IOC_GET_BACKLIGHT:
+	{
+		int brightness;
+
 		if (sleep_in_progress)
 			return -EBUSY;
-		error = get_backlight_level();
-		if (error < 0)
-			return error;
-		return put_user(error, argp);
+
+		brightness = pmac_backlight_get_legacy_brightness();
+		if (brightness < 0)
+			return brightness;
+		else
+			return put_user(brightness, argp);
+
+	}
 	case PMU_IOC_SET_BACKLIGHT:
 	{
-		__u32 value;
+		int brightness;
+
 		if (sleep_in_progress)
 			return -EBUSY;
-		error = get_user(value, argp);
-		if (!error)
-			error = set_backlight_level(value);
-		break;
+
+		error = get_user(brightness, argp);
+		if (error)
+			return error;
+
+		return pmac_backlight_set_legacy_brightness(brightness);
 	}
 #ifdef CONFIG_INPUT_ADBHID
 	case PMU_IOC_GRAB_BACKLIGHT: {
@@ -2713,7 +2659,7 @@
 		return 0;
 	}
 #endif /* CONFIG_INPUT_ADBHID */
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
 	case PMU_IOC_GET_MODEL:
 	    	return put_user(pmu_kind, argp);
 	case PMU_IOC_HAS_ADB:
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index ac25a48..bf869ed 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -90,7 +90,7 @@
 	depends on BLK_DEV_MD && EXPERIMENTAL
 	---help---
 	  RAID-10 provides a combination of striping (RAID-0) and
-	  mirroring (RAID-1) with easier configuration and more flexable
+	  mirroring (RAID-1) with easier configuration and more flexible
 	  layout.
 	  Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to
 	  be the same size (or at least, only as much as the smallest device
@@ -104,8 +104,8 @@
 
 	  If unsure, say Y.
 
-config MD_RAID5
-	tristate "RAID-4/RAID-5 mode"
+config MD_RAID456
+	tristate "RAID-4/RAID-5/RAID-6 mode"
 	depends on BLK_DEV_MD
 	---help---
 	  A RAID-5 set of N drives with a capacity of C MB per drive provides
@@ -116,20 +116,28 @@
 	  while a RAID-5 set distributes the parity across the drives in one
 	  of the available parity distribution methods.
 
+	  A RAID-6 set of N drives with a capacity of C MB per drive
+	  provides the capacity of C * (N - 2) MB, and protects
+	  against a failure of any two drives. For a given sector
+	  (row) number, (N - 2) drives contain data sectors, and two
+	  drives contains two independent redundancy syndromes.  Like
+	  RAID-5, RAID-6 distributes the syndromes across the drives
+	  in one of the available parity distribution methods.
+
 	  Information about Software RAID on Linux is contained in the
 	  Software-RAID mini-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>. There you will also
 	  learn where to get the supporting user space utilities raidtools.
 
-	  If you want to use such a RAID-4/RAID-5 set, say Y.  To
+	  If you want to use such a RAID-4/RAID-5/RAID-6 set, say Y.  To
 	  compile this code as a module, choose M here: the module
-	  will be called raid5.
+	  will be called raid456.
 
 	  If unsure, say Y.
 
 config MD_RAID5_RESHAPE
 	bool "Support adding drives to a raid-5 array (experimental)"
-	depends on MD_RAID5 && EXPERIMENTAL
+	depends on MD_RAID456 && EXPERIMENTAL
 	---help---
 	  A RAID-5 set can be expanded by adding extra drives. This
 	  requires "restriping" the array which means (almost) every
@@ -139,7 +147,7 @@
 	  is online.  However it is still EXPERIMENTAL code.  It should
 	  work, but please be sure that you have backups.
 
-	  You will need mdadm verion 2.4.1 or later to use this
+	  You will need mdadm version 2.4.1 or later to use this
 	  feature safely.  During the early stage of reshape there is
 	  a critical section where live data is being over-written.  A
 	  crash during this time needs extra care for recovery.  The
@@ -154,28 +162,6 @@
 	  There should be enough spares already present to make the new
 	  array workable.
 
-config MD_RAID6
-	tristate "RAID-6 mode"
-	depends on BLK_DEV_MD
-	---help---
-	  A RAID-6 set of N drives with a capacity of C MB per drive
-	  provides the capacity of C * (N - 2) MB, and protects
-	  against a failure of any two drives. For a given sector
-	  (row) number, (N - 2) drives contain data sectors, and two
-	  drives contains two independent redundancy syndromes.  Like
-	  RAID-5, RAID-6 distributes the syndromes across the drives
-	  in one of the available parity distribution methods.
-
-	  RAID-6 requires mdadm-1.5.0 or later, available at:
-
-	  ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/
-
-	  If you want to use such a RAID-6 set, say Y.  To compile
-	  this code as a module, choose M here: the module will be
-	  called raid6.
-
-	  If unsure, say Y.
-
 config MD_MULTIPATH
 	tristate "Multipath I/O support"
 	depends on BLK_DEV_MD
@@ -235,7 +221,7 @@
        tristate "Snapshot target (EXPERIMENTAL)"
        depends on BLK_DEV_DM && EXPERIMENTAL
        ---help---
-         Allow volume managers to take writeable snapshots of a device.
+         Allow volume managers to take writable snapshots of a device.
 
 config DM_MIRROR
        tristate "Mirror target (EXPERIMENTAL)"
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index d3efedf..34957a6 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -8,7 +8,7 @@
 dm-snapshot-objs := dm-snap.o dm-exception-store.o
 dm-mirror-objs	:= dm-log.o dm-raid1.o
 md-mod-objs     := md.o bitmap.o
-raid6-objs	:= raid6main.o raid6algos.o raid6recov.o raid6tables.o \
+raid456-objs	:= raid5.o raid6algos.o raid6recov.o raid6tables.o \
 		   raid6int1.o raid6int2.o raid6int4.o \
 		   raid6int8.o raid6int16.o raid6int32.o \
 		   raid6altivec1.o raid6altivec2.o raid6altivec4.o \
@@ -25,8 +25,7 @@
 obj-$(CONFIG_MD_RAID0)		+= raid0.o
 obj-$(CONFIG_MD_RAID1)		+= raid1.o
 obj-$(CONFIG_MD_RAID10)		+= raid10.o
-obj-$(CONFIG_MD_RAID5)		+= raid5.o xor.o
-obj-$(CONFIG_MD_RAID6)		+= raid6.o xor.o
+obj-$(CONFIG_MD_RAID456)	+= raid456.o xor.o
 obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
 obj-$(CONFIG_MD_FAULTY)		+= faulty.o
 obj-$(CONFIG_BLK_DEV_MD)	+= md-mod.o
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index f8ffaee..ebbd2d8 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -7,7 +7,6 @@
  * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.:
  * - added disk storage for bitmap
  * - changes to allow various bitmap chunk sizes
- * - added bitmap daemon (to asynchronously clear bitmap bits from disk)
  */
 
 /*
@@ -15,9 +14,6 @@
  *
  * flush after percent set rather than just time based. (maybe both).
  * wait if count gets too high, wake when it drops to half.
- * allow bitmap to be mirrored with superblock (before or after...)
- * allow hot-add to re-instate a current device.
- * allow hot-add of bitmap after quiessing device
  */
 
 #include <linux/module.h>
@@ -73,24 +69,6 @@
 
 
 /*
- * test if the bitmap is active
- */
-int bitmap_active(struct bitmap *bitmap)
-{
-	unsigned long flags;
-	int res = 0;
-
-	if (!bitmap)
-		return res;
-	spin_lock_irqsave(&bitmap->lock, flags);
-	res = bitmap->flags & BITMAP_ACTIVE;
-	spin_unlock_irqrestore(&bitmap->lock, flags);
-	return res;
-}
-
-#define WRITE_POOL_SIZE 256
-
-/*
  * just a placeholder - calls kmalloc for bitmap pages
  */
 static unsigned char *bitmap_alloc_page(struct bitmap *bitmap)
@@ -269,6 +247,8 @@
 
 		if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) {
 			page->index = index;
+			attach_page_buffers(page, NULL); /* so that free_buffer will
+							  * quietly no-op */
 			return page;
 		}
 	}
@@ -300,77 +280,132 @@
  */
 static int write_page(struct bitmap *bitmap, struct page *page, int wait)
 {
-	int ret = -ENOMEM;
+	struct buffer_head *bh;
 
 	if (bitmap->file == NULL)
 		return write_sb_page(bitmap->mddev, bitmap->offset, page, wait);
 
-	flush_dcache_page(page); /* make sure visible to anyone reading the file */
+	bh = page_buffers(page);
 
-	if (wait)
-		lock_page(page);
-	else {
-		if (TestSetPageLocked(page))
-			return -EAGAIN; /* already locked */
-		if (PageWriteback(page)) {
-			unlock_page(page);
-			return -EAGAIN;
-		}
+	while (bh && bh->b_blocknr) {
+		atomic_inc(&bitmap->pending_writes);
+		set_buffer_locked(bh);
+		set_buffer_mapped(bh);
+		submit_bh(WRITE, bh);
+		bh = bh->b_this_page;
 	}
 
-	ret = page->mapping->a_ops->prepare_write(bitmap->file, page, 0, PAGE_SIZE);
-	if (!ret)
-		ret = page->mapping->a_ops->commit_write(bitmap->file, page, 0,
-			PAGE_SIZE);
-	if (ret) {
-		unlock_page(page);
-		return ret;
+	if (wait) {
+		wait_event(bitmap->write_wait,
+			   atomic_read(&bitmap->pending_writes)==0);
+		return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
 	}
-
-	set_page_dirty(page); /* force it to be written out */
-
-	if (!wait) {
-		/* add to list to be waited for by daemon */
-		struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO);
-		item->page = page;
-		get_page(page);
-		spin_lock(&bitmap->write_lock);
-		list_add(&item->list, &bitmap->complete_pages);
-		spin_unlock(&bitmap->write_lock);
-		md_wakeup_thread(bitmap->writeback_daemon);
-	}
-	return write_one_page(page, wait);
+	return 0;
 }
 
-/* read a page from a file, pinning it into cache, and return bytes_read */
-static struct page *read_page(struct file *file, unsigned long index,
-					unsigned long *bytes_read)
+static void end_bitmap_write(struct buffer_head *bh, int uptodate)
 {
-	struct inode *inode = file->f_mapping->host;
+	struct bitmap *bitmap = bh->b_private;
+	unsigned long flags;
+
+	if (!uptodate) {
+		spin_lock_irqsave(&bitmap->lock, flags);
+		bitmap->flags |= BITMAP_WRITE_ERROR;
+		spin_unlock_irqrestore(&bitmap->lock, flags);
+	}
+	if (atomic_dec_and_test(&bitmap->pending_writes))
+		wake_up(&bitmap->write_wait);
+}
+
+/* copied from buffer.c */
+static void
+__clear_page_buffers(struct page *page)
+{
+	ClearPagePrivate(page);
+	set_page_private(page, 0);
+	page_cache_release(page);
+}
+static void free_buffers(struct page *page)
+{
+	struct buffer_head *bh = page_buffers(page);
+
+	while (bh) {
+		struct buffer_head *next = bh->b_this_page;
+		free_buffer_head(bh);
+		bh = next;
+	}
+	__clear_page_buffers(page);
+	put_page(page);
+}
+
+/* read a page from a file.
+ * We both read the page, and attach buffers to the page to record the
+ * address of each block (using bmap).  These addresses will be used
+ * to write the block later, completely bypassing the filesystem.
+ * This usage is similar to how swap files are handled, and allows us
+ * to write to a file with no concerns of memory allocation failing.
+ */
+static struct page *read_page(struct file *file, unsigned long index,
+			      struct bitmap *bitmap,
+			      unsigned long count)
+{
 	struct page *page = NULL;
-	loff_t isize = i_size_read(inode);
-	unsigned long end_index = isize >> PAGE_SHIFT;
+	struct inode *inode = file->f_dentry->d_inode;
+	struct buffer_head *bh;
+	sector_t block;
 
 	PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE,
 			(unsigned long long)index << PAGE_SHIFT);
 
-	page = read_cache_page(inode->i_mapping, index,
-			(filler_t *)inode->i_mapping->a_ops->readpage, file);
+	page = alloc_page(GFP_KERNEL);
+	if (!page)
+		page = ERR_PTR(-ENOMEM);
 	if (IS_ERR(page))
 		goto out;
-	wait_on_page_locked(page);
-	if (!PageUptodate(page) || PageError(page)) {
+
+	bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);
+	if (!bh) {
 		put_page(page);
-		page = ERR_PTR(-EIO);
+		page = ERR_PTR(-ENOMEM);
 		goto out;
 	}
+	attach_page_buffers(page, bh);
+	block = index << (PAGE_SHIFT - inode->i_blkbits);
+	while (bh) {
+		if (count == 0)
+			bh->b_blocknr = 0;
+		else {
+			bh->b_blocknr = bmap(inode, block);
+			if (bh->b_blocknr == 0) {
+				/* Cannot use this file! */
+				free_buffers(page);
+				page = ERR_PTR(-EINVAL);
+				goto out;
+			}
+			bh->b_bdev = inode->i_sb->s_bdev;
+			if (count < (1<<inode->i_blkbits))
+				count = 0;
+			else
+				count -= (1<<inode->i_blkbits);
 
-	if (index > end_index) /* we have read beyond EOF */
-		*bytes_read = 0;
-	else if (index == end_index) /* possible short read */
-		*bytes_read = isize & ~PAGE_MASK;
-	else
-		*bytes_read = PAGE_SIZE; /* got a full page */
+			bh->b_end_io = end_bitmap_write;
+			bh->b_private = bitmap;
+			atomic_inc(&bitmap->pending_writes);
+			set_buffer_locked(bh);
+			set_buffer_mapped(bh);
+			submit_bh(READ, bh);
+		}
+		block++;
+		bh = bh->b_this_page;
+	}
+	page->index = index;
+
+	wait_event(bitmap->write_wait,
+		   atomic_read(&bitmap->pending_writes)==0);
+	if (bitmap->flags & BITMAP_WRITE_ERROR) {
+		free_buffers(page);
+		page = ERR_PTR(-EIO);
+	}
 out:
 	if (IS_ERR(page))
 		printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n",
@@ -441,16 +476,14 @@
 	char *reason = NULL;
 	bitmap_super_t *sb;
 	unsigned long chunksize, daemon_sleep, write_behind;
-	unsigned long bytes_read;
 	unsigned long long events;
 	int err = -EINVAL;
 
 	/* page 0 is the superblock, read it... */
 	if (bitmap->file)
-		bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read);
+		bitmap->sb_page = read_page(bitmap->file, 0, bitmap, PAGE_SIZE);
 	else {
 		bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0);
-		bytes_read = PAGE_SIZE;
 	}
 	if (IS_ERR(bitmap->sb_page)) {
 		err = PTR_ERR(bitmap->sb_page);
@@ -460,13 +493,6 @@
 
 	sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
 
-	if (bytes_read < sizeof(*sb)) { /* short read */
-		printk(KERN_INFO "%s: bitmap file superblock truncated\n",
-			bmname(bitmap));
-		err = -ENOSPC;
-		goto out;
-	}
-
 	chunksize = le32_to_cpu(sb->chunksize);
 	daemon_sleep = le32_to_cpu(sb->daemon_sleep);
 	write_behind = le32_to_cpu(sb->write_behind);
@@ -550,7 +576,6 @@
 		spin_unlock_irqrestore(&bitmap->lock, flags);
 		return;
 	}
-	get_page(bitmap->sb_page);
 	spin_unlock_irqrestore(&bitmap->lock, flags);
 	sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
 	switch (op) {
@@ -561,7 +586,6 @@
 		default: BUG();
 	}
 	kunmap_atomic(sb, KM_USER0);
-	put_page(bitmap->sb_page);
 }
 
 /*
@@ -614,48 +638,17 @@
 
 	while (pages--)
 		if (map[pages]->index != 0) /* 0 is sb_page, release it below */
-			put_page(map[pages]);
+			free_buffers(map[pages]);
 	kfree(map);
 	kfree(attr);
 
-	safe_put_page(sb_page);
-}
-
-static void bitmap_stop_daemon(struct bitmap *bitmap);
-
-/* dequeue the next item in a page list -- don't call from irq context */
-static struct page_list *dequeue_page(struct bitmap *bitmap)
-{
-	struct page_list *item = NULL;
-	struct list_head *head = &bitmap->complete_pages;
-
-	spin_lock(&bitmap->write_lock);
-	if (list_empty(head))
-		goto out;
-	item = list_entry(head->prev, struct page_list, list);
-	list_del(head->prev);
-out:
-	spin_unlock(&bitmap->write_lock);
-	return item;
-}
-
-static void drain_write_queues(struct bitmap *bitmap)
-{
-	struct page_list *item;
-
-	while ((item = dequeue_page(bitmap))) {
-		/* don't bother to wait */
-		put_page(item->page);
-		mempool_free(item, bitmap->write_pool);
-	}
-
-	wake_up(&bitmap->write_wait);
+	if (sb_page)
+		free_buffers(sb_page);
 }
 
 static void bitmap_file_put(struct bitmap *bitmap)
 {
 	struct file *file;
-	struct inode *inode;
 	unsigned long flags;
 
 	spin_lock_irqsave(&bitmap->lock, flags);
@@ -663,17 +656,14 @@
 	bitmap->file = NULL;
 	spin_unlock_irqrestore(&bitmap->lock, flags);
 
-	bitmap_stop_daemon(bitmap);
-
-	drain_write_queues(bitmap);
-
+	if (file)
+		wait_event(bitmap->write_wait,
+			   atomic_read(&bitmap->pending_writes)==0);
 	bitmap_file_unmap(bitmap);
 
 	if (file) {
-		inode = file->f_mapping->host;
-		spin_lock(&inode->i_lock);
-		atomic_set(&inode->i_writecount, 1); /* allow writes again */
-		spin_unlock(&inode->i_lock);
+		struct inode *inode = file->f_dentry->d_inode;
+		invalidate_inode_pages(inode->i_mapping);
 		fput(file);
 	}
 }
@@ -708,26 +698,27 @@
 }
 
 enum bitmap_page_attr {
-	BITMAP_PAGE_DIRTY = 1, // there are set bits that need to be synced
-	BITMAP_PAGE_CLEAN = 2, // there are bits that might need to be cleared
-	BITMAP_PAGE_NEEDWRITE=4, // there are cleared bits that need to be synced
+	BITMAP_PAGE_DIRTY = 0, // there are set bits that need to be synced
+	BITMAP_PAGE_CLEAN = 1, // there are bits that might need to be cleared
+	BITMAP_PAGE_NEEDWRITE=2, // there are cleared bits that need to be synced
 };
 
 static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
 				enum bitmap_page_attr attr)
 {
-	bitmap->filemap_attr[page->index] |= attr;
+	__set_bit((page->index<<2) + attr, bitmap->filemap_attr);
 }
 
 static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
 				enum bitmap_page_attr attr)
 {
-	bitmap->filemap_attr[page->index] &= ~attr;
+	__clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
 }
 
-static inline unsigned long get_page_attr(struct bitmap *bitmap, struct page *page)
+static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
+					   enum bitmap_page_attr attr)
 {
-	return bitmap->filemap_attr[page->index];
+	return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
 }
 
 /*
@@ -751,11 +742,6 @@
 	page = filemap_get_page(bitmap, chunk);
 	bit = file_page_offset(chunk);
 
-
-	/* make sure the page stays cached until it gets written out */
-	if (! (get_page_attr(bitmap, page) & BITMAP_PAGE_DIRTY))
-		get_page(page);
-
  	/* set the bit */
 	kaddr = kmap_atomic(page, KM_USER0);
 	if (bitmap->flags & BITMAP_HOSTENDIAN)
@@ -775,7 +761,8 @@
  * sync the dirty pages of the bitmap file to disk */
 int bitmap_unplug(struct bitmap *bitmap)
 {
-	unsigned long i, attr, flags;
+	unsigned long i, flags;
+	int dirty, need_write;
 	struct page *page;
 	int wait = 0;
 	int err;
@@ -792,35 +779,26 @@
 			return 0;
 		}
 		page = bitmap->filemap[i];
-		attr = get_page_attr(bitmap, page);
+		dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+		need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
 		clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
 		clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-		if ((attr & BITMAP_PAGE_DIRTY))
+		if (dirty)
 			wait = 1;
 		spin_unlock_irqrestore(&bitmap->lock, flags);
 
-		if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) {
+		if (dirty | need_write)
 			err = write_page(bitmap, page, 0);
-			if (err == -EAGAIN) {
-				if (attr & BITMAP_PAGE_DIRTY)
-					err = write_page(bitmap, page, 1);
-				else
-					err = 0;
-			}
-			if (err)
-				return 1;
-		}
 	}
 	if (wait) { /* if any writes were performed, we need to wait on them */
-		if (bitmap->file) {
-			spin_lock_irq(&bitmap->write_lock);
-			wait_event_lock_irq(bitmap->write_wait,
-					    list_empty(&bitmap->complete_pages), bitmap->write_lock,
-					    wake_up_process(bitmap->writeback_daemon->tsk));
-			spin_unlock_irq(&bitmap->write_lock);
-		} else
+		if (bitmap->file)
+			wait_event(bitmap->write_wait,
+				   atomic_read(&bitmap->pending_writes)==0);
+		else
 			md_super_wait(bitmap->mddev);
 	}
+	if (bitmap->flags & BITMAP_WRITE_ERROR)
+		bitmap_file_kick(bitmap);
 	return 0;
 }
 
@@ -842,7 +820,7 @@
 	struct page *page = NULL, *oldpage = NULL;
 	unsigned long num_pages, bit_cnt = 0;
 	struct file *file;
-	unsigned long bytes, offset, dummy;
+	unsigned long bytes, offset;
 	int outofdate;
 	int ret = -ENOSPC;
 	void *paddr;
@@ -879,7 +857,12 @@
 	if (!bitmap->filemap)
 		goto out;
 
-	bitmap->filemap_attr = kzalloc(sizeof(long) * num_pages, GFP_KERNEL);
+	/* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
+	bitmap->filemap_attr = kzalloc(
+		(((num_pages*4/8)+sizeof(unsigned long)-1)
+		 /sizeof(unsigned long))
+		*sizeof(unsigned long),
+		GFP_KERNEL);
 	if (!bitmap->filemap_attr)
 		goto out;
 
@@ -890,7 +873,12 @@
 		index = file_page_index(i);
 		bit = file_page_offset(i);
 		if (index != oldindex) { /* this is a new page, read it in */
+			int count;
 			/* unmap the old page, we're done with it */
+			if (index == num_pages-1)
+				count = bytes - index * PAGE_SIZE;
+			else
+				count = PAGE_SIZE;
 			if (index == 0) {
 				/*
 				 * if we're here then the superblock page
@@ -900,7 +888,7 @@
 				page = bitmap->sb_page;
 				offset = sizeof(bitmap_super_t);
 			} else if (file) {
-				page = read_page(file, index, &dummy);
+				page = read_page(file, index, bitmap, count);
 				offset = 0;
 			} else {
 				page = read_sb_page(bitmap->mddev, bitmap->offset, index);
@@ -971,12 +959,11 @@
 	/* We don't actually write all bitmap blocks here,
 	 * just flag them as needing to be written
 	 */
+	int i;
 
-	unsigned long chunks = bitmap->chunks;
-	unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t);
-	unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE;
-	while (num_pages--)
-		bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE;
+	for (i=0; i < bitmap->file_pages; i++)
+		set_page_attr(bitmap, bitmap->filemap[i],
+			      BITMAP_PAGE_NEEDWRITE);
 }
 
 
@@ -1007,7 +994,6 @@
 	struct page *page = NULL, *lastpage = NULL;
 	int err = 0;
 	int blocks;
-	int attr;
 	void *paddr;
 
 	if (bitmap == NULL)
@@ -1029,43 +1015,34 @@
 
 		if (page != lastpage) {
 			/* skip this page unless it's marked as needing cleaning */
-			if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) {
-				if (attr & BITMAP_PAGE_NEEDWRITE) {
-					get_page(page);
+			if (!test_page_attr(bitmap, page, BITMAP_PAGE_CLEAN)) {
+				int need_write = test_page_attr(bitmap, page,
+								BITMAP_PAGE_NEEDWRITE);
+				if (need_write)
 					clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-				}
+
 				spin_unlock_irqrestore(&bitmap->lock, flags);
-				if (attr & BITMAP_PAGE_NEEDWRITE) {
+				if (need_write) {
 					switch (write_page(bitmap, page, 0)) {
-					case -EAGAIN:
-						set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-						break;
 					case 0:
 						break;
 					default:
 						bitmap_file_kick(bitmap);
 					}
-					put_page(page);
 				}
 				continue;
 			}
 
 			/* grab the new page, sync and release the old */
-			get_page(page);
 			if (lastpage != NULL) {
-				if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) {
+				if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
 					clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
 					spin_unlock_irqrestore(&bitmap->lock, flags);
 					err = write_page(bitmap, lastpage, 0);
-					if (err == -EAGAIN) {
-						err = 0;
-						set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
-					}
 				} else {
 					set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
 					spin_unlock_irqrestore(&bitmap->lock, flags);
 				}
-				put_page(lastpage);
 				if (err)
 					bitmap_file_kick(bitmap);
 			} else
@@ -1107,131 +1084,19 @@
 	/* now sync the final page */
 	if (lastpage != NULL) {
 		spin_lock_irqsave(&bitmap->lock, flags);
-		if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) {
+		if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
 			clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
 			spin_unlock_irqrestore(&bitmap->lock, flags);
 			err = write_page(bitmap, lastpage, 0);
-			if (err == -EAGAIN) {
-				set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
-				err = 0;
-			}
 		} else {
 			set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
 			spin_unlock_irqrestore(&bitmap->lock, flags);
 		}
-
-		put_page(lastpage);
 	}
 
 	return err;
 }
 
-static void daemon_exit(struct bitmap *bitmap, mdk_thread_t **daemon)
-{
-	mdk_thread_t *dmn;
-	unsigned long flags;
-
-	/* if no one is waiting on us, we'll free the md thread struct
-	 * and exit, otherwise we let the waiter clean things up */
-	spin_lock_irqsave(&bitmap->lock, flags);
-	if ((dmn = *daemon)) { /* no one is waiting, cleanup and exit */
-		*daemon = NULL;
-		spin_unlock_irqrestore(&bitmap->lock, flags);
-		kfree(dmn);
-		complete_and_exit(NULL, 0); /* do_exit not exported */
-	}
-	spin_unlock_irqrestore(&bitmap->lock, flags);
-}
-
-static void bitmap_writeback_daemon(mddev_t *mddev)
-{
-	struct bitmap *bitmap = mddev->bitmap;
-	struct page *page;
-	struct page_list *item;
-	int err = 0;
-
-	if (signal_pending(current)) {
-		printk(KERN_INFO
-		       "%s: bitmap writeback daemon got signal, exiting...\n",
-		       bmname(bitmap));
-		err = -EINTR;
-		goto out;
-	}
-	if (bitmap == NULL)
-		/* about to be stopped. */
-		return;
-
-	PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap));
-	/* wait on bitmap page writebacks */
-	while ((item = dequeue_page(bitmap))) {
-		page = item->page;
-		mempool_free(item, bitmap->write_pool);
-		PRINTK("wait on page writeback: %p\n", page);
-		wait_on_page_writeback(page);
-		PRINTK("finished page writeback: %p\n", page);
-
-		err = PageError(page);
-		put_page(page);
-		if (err) {
-			printk(KERN_WARNING "%s: bitmap file writeback "
-			       "failed (page %lu): %d\n",
-			       bmname(bitmap), page->index, err);
-			bitmap_file_kick(bitmap);
-			goto out;
-		}
-	}
- out:
-	wake_up(&bitmap->write_wait);
-	if (err) {
-		printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n",
-		       bmname(bitmap), err);
-		daemon_exit(bitmap, &bitmap->writeback_daemon);
-	}
-}
-
-static mdk_thread_t *bitmap_start_daemon(struct bitmap *bitmap,
-				void (*func)(mddev_t *), char *name)
-{
-	mdk_thread_t *daemon;
-	char namebuf[32];
-
-#ifdef INJECT_FATAL_FAULT_2
-	daemon = NULL;
-#else
-	sprintf(namebuf, "%%s_%s", name);
-	daemon = md_register_thread(func, bitmap->mddev, namebuf);
-#endif
-	if (!daemon) {
-		printk(KERN_ERR "%s: failed to start bitmap daemon\n",
-			bmname(bitmap));
-		return ERR_PTR(-ECHILD);
-	}
-
-	md_wakeup_thread(daemon); /* start it running */
-
-	PRINTK("%s: %s daemon (pid %d) started...\n",
-		bmname(bitmap), name, daemon->tsk->pid);
-
-	return daemon;
-}
-
-static void bitmap_stop_daemon(struct bitmap *bitmap)
-{
-	/* the daemon can't stop itself... it'll just exit instead... */
-	if (bitmap->writeback_daemon && ! IS_ERR(bitmap->writeback_daemon) &&
-	    current->pid != bitmap->writeback_daemon->tsk->pid) {
-		mdk_thread_t *daemon;
-		unsigned long flags;
-
-		spin_lock_irqsave(&bitmap->lock, flags);
-		daemon = bitmap->writeback_daemon;
-		bitmap->writeback_daemon = NULL;
-		spin_unlock_irqrestore(&bitmap->lock, flags);
-		if (daemon && ! IS_ERR(daemon))
-			md_unregister_thread(daemon); /* destroy the thread */
-	}
-}
-
 static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
 					    sector_t offset, int *blocks,
 					    int create)
@@ -1500,8 +1365,6 @@
 
 	/* free all allocated memory */
 
-	mempool_destroy(bitmap->write_pool);
-
 	if (bp) /* deallocate the page memory */
 		for (k = 0; k < pages; k++)
 			if (bp[k].map && !bp[k].hijacked)
@@ -1549,20 +1412,20 @@
 		return -ENOMEM;
 
 	spin_lock_init(&bitmap->lock);
-	bitmap->mddev = mddev;
-
-	spin_lock_init(&bitmap->write_lock);
-	INIT_LIST_HEAD(&bitmap->complete_pages);
+	atomic_set(&bitmap->pending_writes, 0);
 	init_waitqueue_head(&bitmap->write_wait);
-	bitmap->write_pool = mempool_create_kmalloc_pool(WRITE_POOL_SIZE,
-						sizeof(struct page_list));
-	err = -ENOMEM;
-	if (!bitmap->write_pool)
-		goto error;
+
+	bitmap->mddev = mddev;
 
 	bitmap->file = file;
 	bitmap->offset = mddev->bitmap_offset;
-	if (file) get_file(file);
+	if (file) {
+		get_file(file);
+		do_sync_file_range(file, 0, LLONG_MAX,
+				   SYNC_FILE_RANGE_WAIT_BEFORE |
+				   SYNC_FILE_RANGE_WRITE |
+				   SYNC_FILE_RANGE_WAIT_AFTER);
+	}
 	/* read superblock from bitmap file (this sets bitmap->chunksize) */
 	err = bitmap_read_sb(bitmap);
 	if (err)
@@ -1594,8 +1457,6 @@
 	if (!bitmap->bp)
 		goto error;
 
-	bitmap->flags |= BITMAP_ACTIVE;
-
 	/* now that we have some pages available, initialize the in-memory
 	 * bitmap from the on-disk bitmap */
 	start = 0;
@@ -1613,15 +1474,6 @@
 
 	mddev->bitmap = bitmap;
 
-	if (file)
-		/* kick off the bitmap writeback daemon */
-		bitmap->writeback_daemon =
-			bitmap_start_daemon(bitmap,
-					    bitmap_writeback_daemon,
-					    "bitmap_wb");
-
-	if (IS_ERR(bitmap->writeback_daemon))
-		return PTR_ERR(bitmap->writeback_daemon);
 	mddev->thread->timeout = bitmap->daemon_sleep * HZ;
 
 	return bitmap_update_sb(bitmap);
@@ -1638,4 +1490,3 @@
 EXPORT_SYMBOL(bitmap_end_sync);
 EXPORT_SYMBOL(bitmap_unplug);
 EXPORT_SYMBOL(bitmap_close_sync);
-EXPORT_SYMBOL(bitmap_daemon_work);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 61a590b..6022ed1 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -20,7 +20,7 @@
 
 #include "dm.h"
 
-#define PFX	"crypt: "
+#define DM_MSG_PREFIX "crypt"
 
 /*
  * per bio private data
@@ -125,19 +125,19 @@
 	u8 *salt;
 
 	if (opts == NULL) {
-		ti->error = PFX "Digest algorithm missing for ESSIV mode";
+		ti->error = "Digest algorithm missing for ESSIV mode";
 		return -EINVAL;
 	}
 
 	/* Hash the cipher key with the given hash algorithm */
 	hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
 	if (hash_tfm == NULL) {
-		ti->error = PFX "Error initializing ESSIV hash";
+		ti->error = "Error initializing ESSIV hash";
 		return -EINVAL;
 	}
 
 	if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) {
-		ti->error = PFX "Expected digest algorithm for ESSIV hash";
+		ti->error = "Expected digest algorithm for ESSIV hash";
 		crypto_free_tfm(hash_tfm);
 		return -EINVAL;
 	}
@@ -145,7 +145,7 @@
 	saltsize = crypto_tfm_alg_digestsize(hash_tfm);
 	salt = kmalloc(saltsize, GFP_KERNEL);
 	if (salt == NULL) {
-		ti->error = PFX "Error kmallocing salt storage in ESSIV";
+		ti->error = "Error kmallocing salt storage in ESSIV";
 		crypto_free_tfm(hash_tfm);
 		return -ENOMEM;
 	}
@@ -159,20 +159,20 @@
 	                             CRYPTO_TFM_MODE_ECB |
 	                             CRYPTO_TFM_REQ_MAY_SLEEP);
 	if (essiv_tfm == NULL) {
-		ti->error = PFX "Error allocating crypto tfm for ESSIV";
+		ti->error = "Error allocating crypto tfm for ESSIV";
 		kfree(salt);
 		return -EINVAL;
 	}
 	if (crypto_tfm_alg_blocksize(essiv_tfm)
 	    != crypto_tfm_alg_ivsize(cc->tfm)) {
-		ti->error = PFX "Block size of ESSIV cipher does "
+		ti->error = "Block size of ESSIV cipher does "
 			        "not match IV size of block cipher";
 		crypto_free_tfm(essiv_tfm);
 		kfree(salt);
 		return -EINVAL;
 	}
 	if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) {
-		ti->error = PFX "Failed to set key for ESSIV cipher";
+		ti->error = "Failed to set key for ESSIV cipher";
 		crypto_free_tfm(essiv_tfm);
 		kfree(salt);
 		return -EINVAL;
@@ -521,7 +521,7 @@
 	unsigned long long tmpll;
 
 	if (argc != 5) {
-		ti->error = PFX "Not enough arguments";
+		ti->error = "Not enough arguments";
 		return -EINVAL;
 	}
 
@@ -532,21 +532,21 @@
 	ivmode = strsep(&ivopts, ":");
 
 	if (tmp)
-		DMWARN(PFX "Unexpected additional cipher options");
+		DMWARN("Unexpected additional cipher options");
 
 	key_size = strlen(argv[1]) >> 1;
 
 	cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
 	if (cc == NULL) {
 		ti->error =
-			PFX "Cannot allocate transparent encryption context";
+			"Cannot allocate transparent encryption context";
 		return -ENOMEM;
 	}
 
 	cc->key_size = key_size;
 	if ((!key_size && strcmp(argv[1], "-") != 0) ||
 	    (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
-		ti->error = PFX "Error decoding key";
+		ti->error = "Error decoding key";
 		goto bad1;
 	}
 
@@ -562,22 +562,22 @@
 	else if (strcmp(chainmode, "ecb") == 0)
 		crypto_flags = CRYPTO_TFM_MODE_ECB;
 	else {
-		ti->error = PFX "Unknown chaining mode";
+		ti->error = "Unknown chaining mode";
 		goto bad1;
 	}
 
 	if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) {
-		ti->error = PFX "This chaining mode requires an IV mechanism";
+		ti->error = "This chaining mode requires an IV mechanism";
 		goto bad1;
 	}
 
 	tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
 	if (!tfm) {
-		ti->error = PFX "Error allocating crypto tfm";
+		ti->error = "Error allocating crypto tfm";
 		goto bad1;
 	}
 	if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) {
-		ti->error = PFX "Expected cipher algorithm";
+		ti->error = "Expected cipher algorithm";
 		goto bad2;
 	}
 
@@ -595,7 +595,7 @@
 	else if (strcmp(ivmode, "essiv") == 0)
 		cc->iv_gen_ops = &crypt_iv_essiv_ops;
 	else {
-		ti->error = PFX "Invalid IV mode";
+		ti->error = "Invalid IV mode";
 		goto bad2;
 	}
 
@@ -610,7 +610,7 @@
 	else {
 		cc->iv_size = 0;
 		if (cc->iv_gen_ops) {
-			DMWARN(PFX "Selected cipher does not support IVs");
+			DMWARN("Selected cipher does not support IVs");
 			if (cc->iv_gen_ops->dtr)
 				cc->iv_gen_ops->dtr(cc);
 			cc->iv_gen_ops = NULL;
@@ -619,36 +619,36 @@
 
 	cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
 	if (!cc->io_pool) {
-		ti->error = PFX "Cannot allocate crypt io mempool";
+		ti->error = "Cannot allocate crypt io mempool";
 		goto bad3;
 	}
 
 	cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
 	if (!cc->page_pool) {
-		ti->error = PFX "Cannot allocate page mempool";
+		ti->error = "Cannot allocate page mempool";
 		goto bad4;
 	}
 
 	if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
-		ti->error = PFX "Error setting key";
+		ti->error = "Error setting key";
 		goto bad5;
 	}
 
 	if (sscanf(argv[2], "%llu", &tmpll) != 1) {
-		ti->error = PFX "Invalid iv_offset sector";
+		ti->error = "Invalid iv_offset sector";
 		goto bad5;
 	}
 	cc->iv_offset = tmpll;
 
 	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
-		ti->error = PFX "Invalid device sector";
+		ti->error = "Invalid device sector";
 		goto bad5;
 	}
 	cc->start = tmpll;
 
 	if (dm_get_device(ti, argv[3], cc->start, ti->len,
 	                  dm_table_get_mode(ti->table), &cc->dev)) {
-		ti->error = PFX "Device lookup failed";
+		ti->error = "Device lookup failed";
 		goto bad5;
 	}
 
@@ -657,7 +657,7 @@
 			*(ivopts - 1) = ':';
 		cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL);
 		if (!cc->iv_mode) {
-			ti->error = PFX "Error kmallocing iv_mode string";
+			ti->error = "Error kmallocing iv_mode string";
 			goto bad5;
 		}
 		strcpy(cc->iv_mode, ivmode);
@@ -918,13 +918,13 @@
 	_kcryptd_workqueue = create_workqueue("kcryptd");
 	if (!_kcryptd_workqueue) {
 		r = -ENOMEM;
-		DMERR(PFX "couldn't create kcryptd");
+		DMERR("couldn't create kcryptd");
 		goto bad1;
 	}
 
 	r = dm_register_target(&crypt_target);
 	if (r < 0) {
-		DMERR(PFX "register failed %d", r);
+		DMERR("register failed %d", r);
 		goto bad2;
 	}
 
@@ -942,7 +942,7 @@
 	int r = dm_unregister_target(&crypt_target);
 
 	if (r < 0)
-		DMERR(PFX "unregister failed %d", r);
+		DMERR("unregister failed %d", r);
 
 	destroy_workqueue(_kcryptd_workqueue);
 	kmem_cache_destroy(_crypt_io_pool);
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index c706767..2a374cc 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -12,6 +12,8 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 
+#define DM_MSG_PREFIX "multipath emc"
+
 struct emc_handler {
 	spinlock_t lock;
 
@@ -66,7 +68,7 @@
 
 	bio = bio_alloc(GFP_ATOMIC, 1);
 	if (!bio) {
-		DMERR("dm-emc: get_failover_bio: bio_alloc() failed.");
+		DMERR("get_failover_bio: bio_alloc() failed.");
 		return NULL;
 	}
 
@@ -78,13 +80,13 @@
 
 	page = alloc_page(GFP_ATOMIC);
 	if (!page) {
-		DMERR("dm-emc: get_failover_bio: alloc_page() failed.");
+		DMERR("get_failover_bio: alloc_page() failed.");
 		bio_put(bio);
 		return NULL;
 	}
 
 	if (bio_add_page(bio, page, data_size, 0) != data_size) {
-		DMERR("dm-emc: get_failover_bio: alloc_page() failed.");
+		DMERR("get_failover_bio: alloc_page() failed.");
 		__free_page(page);
 		bio_put(bio);
 		return NULL;
@@ -103,7 +105,7 @@
 	/* FIXME: Figure out why it fails with GFP_ATOMIC. */
 	rq = blk_get_request(q, WRITE, __GFP_WAIT);
 	if (!rq) {
-		DMERR("dm-emc: get_failover_req: blk_get_request failed");
+		DMERR("get_failover_req: blk_get_request failed");
 		return NULL;
 	}
 
@@ -160,7 +162,7 @@
 
 	bio = get_failover_bio(path, data_size);
 	if (!bio) {
-		DMERR("dm-emc: emc_trespass_get: no bio");
+		DMERR("emc_trespass_get: no bio");
 		return NULL;
 	}
 
@@ -173,7 +175,7 @@
 	/* get request for block layer packet command */
 	rq = get_failover_req(h, bio, path);
 	if (!rq) {
-		DMERR("dm-emc: emc_trespass_get: no rq");
+		DMERR("emc_trespass_get: no rq");
 		free_bio(bio);
 		return NULL;
 	}
@@ -200,18 +202,18 @@
 	 * initial state passed into us and then get an update here.
 	 */
 	if (!q) {
-		DMINFO("dm-emc: emc_pg_init: no queue");
+		DMINFO("emc_pg_init: no queue");
 		goto fail_path;
 	}
 
 	/* FIXME: The request should be pre-allocated. */
 	rq = emc_trespass_get(hwh->context, path);
 	if (!rq) {
-		DMERR("dm-emc: emc_pg_init: no rq");
+		DMERR("emc_pg_init: no rq");
 		goto fail_path;
 	}
 
-	DMINFO("dm-emc: emc_pg_init: sending switch-over command");
+	DMINFO("emc_pg_init: sending switch-over command");
 	elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
 	return;
 
@@ -241,18 +243,18 @@
 		hr = 0;
 		short_trespass = 0;
 	} else if (argc != 2) {
-		DMWARN("dm-emc hwhandler: incorrect number of arguments");
+		DMWARN("incorrect number of arguments");
 		return -EINVAL;
 	} else {
 		if ((sscanf(argv[0], "%u", &short_trespass) != 1)
 			|| (short_trespass > 1)) {
-			DMWARN("dm-emc: invalid trespass mode selected");
+			DMWARN("invalid trespass mode selected");
 			return -EINVAL;
 		}
 
 		if ((sscanf(argv[1], "%u", &hr) != 1)
 			|| (hr > 1)) {
-			DMWARN("dm-emc: invalid honor reservation flag selected");
+			DMWARN("invalid honor reservation flag selected");
 			return -EINVAL;
 		}
 	}
@@ -264,14 +266,14 @@
 	hwh->context = h;
 
 	if ((h->short_trespass = short_trespass))
-		DMWARN("dm-emc: short trespass command will be send");
+		DMWARN("short trespass command will be send");
 	else
-		DMWARN("dm-emc: long trespass command will be send");
+		DMWARN("long trespass command will be send");
 
 	if ((h->hr = hr))
-		DMWARN("dm-emc: honor reservation bit will be set");
+		DMWARN("honor reservation bit will be set");
 	else
-		DMWARN("dm-emc: honor reservation bit will not be set (default)");
+		DMWARN("honor reservation bit will not be set (default)");
 
 	return 0;
 }
@@ -336,9 +338,9 @@
 	int r = dm_register_hw_handler(&emc_hwh);
 
 	if (r < 0)
-		DMERR("emc: register failed %d", r);
+		DMERR("register failed %d", r);
 
-	DMINFO("dm-emc version 0.0.3 loaded");
+	DMINFO("version 0.0.3 loaded");
 
 	return r;
 }
@@ -348,7 +350,7 @@
 	int r = dm_unregister_hw_handler(&emc_hwh);
 
 	if (r < 0)
-		DMERR("emc: unregister failed %d", r);
+		DMERR("unregister failed %d", r);
 }
 
 module_init(dm_emc_init);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index cc07bbe..d12379b 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -16,6 +16,8 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 
+#define DM_MSG_PREFIX "snapshots"
+
 /*-----------------------------------------------------------------
  * Persistent snapshots, by persistent we mean that the snapshot
  * will survive a reboot.
@@ -91,7 +93,6 @@
 	struct dm_snapshot *snap;	/* up pointer to my snapshot */
 	int version;
 	int valid;
-	uint32_t chunk_size;
 	uint32_t exceptions_per_area;
 
 	/*
@@ -133,7 +134,7 @@
 	int r = -ENOMEM;
 	size_t len;
 
-	len = ps->chunk_size << SECTOR_SHIFT;
+	len = ps->snap->chunk_size << SECTOR_SHIFT;
 
 	/*
 	 * Allocate the chunk_size block of memory that will hold
@@ -160,8 +161,8 @@
 	unsigned long bits;
 
 	where.bdev = ps->snap->cow->bdev;
-	where.sector = ps->chunk_size * chunk;
-	where.count = ps->chunk_size;
+	where.sector = ps->snap->chunk_size * chunk;
+	where.count = ps->snap->chunk_size;
 
 	return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
 }
@@ -188,7 +189,7 @@
 
 static int zero_area(struct pstore *ps, uint32_t area)
 {
-	memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+	memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
 	return area_io(ps, area, WRITE);
 }
 
@@ -196,6 +197,7 @@
 {
 	int r;
 	struct disk_header *dh;
+	chunk_t chunk_size;
 
 	r = chunk_io(ps, 0, READ);
 	if (r)
@@ -210,8 +212,29 @@
 		*new_snapshot = 0;
 		ps->valid = le32_to_cpu(dh->valid);
 		ps->version = le32_to_cpu(dh->version);
-		ps->chunk_size = le32_to_cpu(dh->chunk_size);
+		chunk_size = le32_to_cpu(dh->chunk_size);
+		if (ps->snap->chunk_size != chunk_size) {
+			DMWARN("chunk size %llu in device metadata overrides "
+			       "table chunk size of %llu.",
+			       (unsigned long long)chunk_size,
+			       (unsigned long long)ps->snap->chunk_size);
 
+			/* We had a bogus chunk_size. Fix stuff up. */
+			dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+			free_area(ps);
+
+			ps->snap->chunk_size = chunk_size;
+			ps->snap->chunk_mask = chunk_size - 1;
+			ps->snap->chunk_shift = ffs(chunk_size) - 1;
+
+			r = alloc_area(ps);
+			if (r)
+				return r;
+
+			r = dm_io_get(sectors_to_pages(chunk_size));
+			if (r)
+				return r;
+		}
 	} else {
 		DMWARN("Invalid/corrupt snapshot");
 		r = -ENXIO;
@@ -224,13 +247,13 @@
 {
 	struct disk_header *dh;
 
-	memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+	memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
 
 	dh = (struct disk_header *) ps->area;
 	dh->magic = cpu_to_le32(SNAP_MAGIC);
 	dh->valid = cpu_to_le32(ps->valid);
 	dh->version = cpu_to_le32(ps->version);
-	dh->chunk_size = cpu_to_le32(ps->chunk_size);
+	dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
 
 	return chunk_io(ps, 0, WRITE);
 }
@@ -365,7 +388,7 @@
 {
 	struct pstore *ps = get_info(store);
 
-	dm_io_put(sectors_to_pages(ps->chunk_size));
+	dm_io_put(sectors_to_pages(ps->snap->chunk_size));
 	vfree(ps->callbacks);
 	free_area(ps);
 	kfree(ps);
@@ -384,6 +407,16 @@
 		return r;
 
 	/*
+	 * Now we know correct chunk_size, complete the initialisation.
+	 */
+	ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) /
+				  sizeof(struct disk_exception);
+	ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
+			sizeof(*ps->callbacks));
+	if (!ps->callbacks)
+		return -ENOMEM;
+
+	/*
 	 * Do we need to setup a new snapshot ?
 	 */
 	if (new_snapshot) {
@@ -533,9 +566,6 @@
 	ps->snap = store->snap;
 	ps->valid = 1;
 	ps->version = SNAPSHOT_DISK_VERSION;
-	ps->chunk_size = chunk_size;
-	ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) /
-	    sizeof(struct disk_exception);
 	ps->next_free = 2;	/* skipping the header and first area */
 	ps->current_committed = 0;
 
@@ -543,18 +573,9 @@
 	if (r)
 		goto bad;
 
-	/*
-	 * Allocate space for all the callbacks.
-	 */
 	ps->callback_count = 0;
 	atomic_set(&ps->pending_count, 0);
-	ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
-				   sizeof(*ps->callbacks));
-
-	if (!ps->callbacks) {
-		r = -ENOMEM;
-		goto bad;
-	}
+	ps->callbacks = NULL;
 
 	store->destroy = persistent_destroy;
 	store->read_metadata = persistent_read_metadata;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 8edd643..3edb347 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the GPL.
  */
@@ -19,6 +19,7 @@
 
 #include <asm/uaccess.h>
 
+#define DM_MSG_PREFIX "ioctl"
 #define DM_DRIVER_EMAIL "dm-devel@redhat.com"
 
 /*-----------------------------------------------------------------
@@ -48,7 +49,7 @@
 static struct list_head _name_buckets[NUM_BUCKETS];
 static struct list_head _uuid_buckets[NUM_BUCKETS];
 
-static void dm_hash_remove_all(void);
+static void dm_hash_remove_all(int keep_open_devices);
 
 /*
  * Guards access to both hash tables.
@@ -73,7 +74,7 @@
 
 static void dm_hash_exit(void)
 {
-	dm_hash_remove_all();
+	dm_hash_remove_all(0);
 	devfs_remove(DM_DIR);
 }
 
@@ -102,8 +103,10 @@
 	unsigned int h = hash_str(str);
 
 	list_for_each_entry (hc, _name_buckets + h, name_list)
-		if (!strcmp(hc->name, str))
+		if (!strcmp(hc->name, str)) {
+			dm_get(hc->md);
 			return hc;
+		}
 
 	return NULL;
 }
@@ -114,8 +117,10 @@
 	unsigned int h = hash_str(str);
 
 	list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
-		if (!strcmp(hc->uuid, str))
+		if (!strcmp(hc->uuid, str)) {
+			dm_get(hc->md);
 			return hc;
+		}
 
 	return NULL;
 }
@@ -191,7 +196,7 @@
  */
 static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
 {
-	struct hash_cell *cell;
+	struct hash_cell *cell, *hc;
 
 	/*
 	 * Allocate the new cells.
@@ -204,14 +209,19 @@
 	 * Insert the cell into both hash tables.
 	 */
 	down_write(&_hash_lock);
-	if (__get_name_cell(name))
+	hc = __get_name_cell(name);
+	if (hc) {
+		dm_put(hc->md);
 		goto bad;
+	}
 
 	list_add(&cell->name_list, _name_buckets + hash_str(name));
 
 	if (uuid) {
-		if (__get_uuid_cell(uuid)) {
+		hc = __get_uuid_cell(uuid);
+		if (hc) {
 			list_del(&cell->name_list);
+			dm_put(hc->md);
 			goto bad;
 		}
 		list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
@@ -251,19 +261,41 @@
 	free_cell(hc);
 }
 
-static void dm_hash_remove_all(void)
+static void dm_hash_remove_all(int keep_open_devices)
 {
-	int i;
+	int i, dev_skipped, dev_removed;
 	struct hash_cell *hc;
 	struct list_head *tmp, *n;
 
 	down_write(&_hash_lock);
+
+retry:
+	dev_skipped = dev_removed = 0;
 	for (i = 0; i < NUM_BUCKETS; i++) {
 		list_for_each_safe (tmp, n, _name_buckets + i) {
 			hc = list_entry(tmp, struct hash_cell, name_list);
+
+			if (keep_open_devices &&
+			    dm_lock_for_deletion(hc->md)) {
+				dev_skipped++;
+				continue;
+			}
 			__hash_remove(hc);
+			dev_removed = 1;
 		}
 	}
+
+	/*
+	 * Some mapped devices may be using other mapped devices, so if any
+	 * still exist, repeat until we make no further progress.
+	 */
+	if (dev_skipped) {
+		if (dev_removed)
+			goto retry;
+
+		DMWARN("remove_all left %d open device(s)", dev_skipped);
+	}
+
 	up_write(&_hash_lock);
 }
 
@@ -289,6 +321,7 @@
 	if (hc) {
 		DMWARN("asked to rename to an already existing name %s -> %s",
 		       old, new);
+		dm_put(hc->md);
 		up_write(&_hash_lock);
 		kfree(new_name);
 		return -EBUSY;
@@ -328,6 +361,7 @@
 		dm_table_put(table);
 	}
 
+	dm_put(hc->md);
 	up_write(&_hash_lock);
 	kfree(old_name);
 	return 0;
@@ -344,7 +378,7 @@
 
 static int remove_all(struct dm_ioctl *param, size_t param_size)
 {
-	dm_hash_remove_all();
+	dm_hash_remove_all(1);
 	param->data_size = 0;
 	return 0;
 }
@@ -524,7 +558,6 @@
 {
 	struct gendisk *disk = dm_disk(md);
 	struct dm_table *table;
-	struct block_device *bdev;
 
 	param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
 			  DM_ACTIVE_PRESENT_FLAG);
@@ -534,20 +567,12 @@
 
 	param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
 
-	if (!(param->flags & DM_SKIP_BDGET_FLAG)) {
-		bdev = bdget_disk(disk, 0);
-		if (!bdev)
-			return -ENXIO;
-
-		/*
-		 * Yes, this will be out of date by the time it gets back
-		 * to userland, but it is still very useful for
-		 * debugging.
-		 */
-		param->open_count = bdev->bd_openers;
-		bdput(bdev);
-	} else
-		param->open_count = -1;
+	/*
+	 * Yes, this will be out of date by the time it gets back
+	 * to userland, but it is still very useful for
+	 * debugging.
+	 */
+	param->open_count = dm_open_count(md);
 
 	if (disk->policy)
 		param->flags |= DM_READONLY_FLAG;
@@ -567,7 +592,7 @@
 
 static int dev_create(struct dm_ioctl *param, size_t param_size)
 {
-	int r;
+	int r, m = DM_ANY_MINOR;
 	struct mapped_device *md;
 
 	r = check_name(param->name);
@@ -575,10 +600,9 @@
 		return r;
 
 	if (param->flags & DM_PERSISTENT_DEV_FLAG)
-		r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md);
-	else
-		r = dm_create(&md);
+		m = MINOR(huge_decode_dev(param->dev));
 
+	r = dm_create(m, &md);
 	if (r)
 		return r;
 
@@ -611,10 +635,8 @@
 		return __get_name_cell(param->name);
 
 	md = dm_get_md(huge_decode_dev(param->dev));
-	if (md) {
+	if (md)
 		mdptr = dm_get_mdptr(md);
-		dm_put(md);
-	}
 
 	return mdptr;
 }
@@ -628,7 +650,6 @@
 	hc = __find_device_hash_cell(param);
 	if (hc) {
 		md = hc->md;
-		dm_get(md);
 
 		/*
 		 * Sneakily write in both the name and the uuid
@@ -653,6 +674,8 @@
 static int dev_remove(struct dm_ioctl *param, size_t param_size)
 {
 	struct hash_cell *hc;
+	struct mapped_device *md;
+	int r;
 
 	down_write(&_hash_lock);
 	hc = __find_device_hash_cell(param);
@@ -663,8 +686,22 @@
 		return -ENXIO;
 	}
 
+	md = hc->md;
+
+	/*
+	 * Ensure the device is not open and nothing further can open it.
+	 */
+	r = dm_lock_for_deletion(md);
+	if (r) {
+		DMWARN("unable to remove open device %s", hc->name);
+		up_write(&_hash_lock);
+		dm_put(md);
+		return r;
+	}
+
 	__hash_remove(hc);
 	up_write(&_hash_lock);
+	dm_put(md);
 	param->data_size = 0;
 	return 0;
 }
@@ -790,7 +827,6 @@
 	}
 
 	md = hc->md;
-	dm_get(md);
 
 	new_map = hc->new_map;
 	hc->new_map = NULL;
@@ -1078,6 +1114,7 @@
 {
 	int r;
 	struct hash_cell *hc;
+	struct mapped_device *md;
 
 	down_write(&_hash_lock);
 
@@ -1096,7 +1133,9 @@
 	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
 
 	r = __dev_status(hc->md, param);
+	md = hc->md;
 	up_write(&_hash_lock);
+	dm_put(md);
 	return r;
 }
 
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index daf586c..47b3c62 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -12,6 +12,8 @@
 #include <linux/bio.h>
 #include <linux/slab.h>
 
+#define DM_MSG_PREFIX "linear"
+
 /*
  * Linear: maps a linear range of a device.
  */
@@ -29,7 +31,7 @@
 	unsigned long long tmp;
 
 	if (argc != 2) {
-		ti->error = "dm-linear: Invalid argument count";
+		ti->error = "Invalid argument count";
 		return -EINVAL;
 	}
 
@@ -111,7 +113,7 @@
 	int r = dm_register_target(&linear_target);
 
 	if (r < 0)
-		DMERR("linear: register failed %d", r);
+		DMERR("register failed %d", r);
 
 	return r;
 }
@@ -121,5 +123,5 @@
 	int r = dm_unregister_target(&linear_target);
 
 	if (r < 0)
-		DMERR("linear: unregister failed %d", r);
+		DMERR("unregister failed %d", r);
 }
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index d73779a..64b764b 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -12,6 +12,8 @@
 #include "dm-log.h"
 #include "dm-io.h"
 
+#define DM_MSG_PREFIX "mirror log"
+
 static LIST_HEAD(_log_types);
 static DEFINE_SPINLOCK(_lock);
 
@@ -155,8 +157,6 @@
 
 	struct io_region header_location;
 	struct log_header *disk_header;
-
-	struct io_region bits_location;
 };
 
 /*
@@ -241,43 +241,21 @@
 }
 
 /*----------------------------------------------------------------
- * Bits IO
- *--------------------------------------------------------------*/
-static int read_bits(struct log_c *log)
-{
-	int r;
-	unsigned long ebits;
-
-	r = dm_io_sync_vm(1, &log->bits_location, READ,
-			  log->clean_bits, &ebits);
-	if (r)
-		return r;
-
-	return 0;
-}
-
-static int write_bits(struct log_c *log)
-{
-	unsigned long ebits;
-	return dm_io_sync_vm(1, &log->bits_location, WRITE,
-			     log->clean_bits, &ebits);
-}
-
-/*----------------------------------------------------------------
  * core log constructor/destructor
  *
  * argv contains region_size followed optionally by [no]sync
  *--------------------------------------------------------------*/
 #define BYTE_SHIFT 3
-static int core_ctr(struct dirty_log *log, struct dm_target *ti,
-		    unsigned int argc, char **argv)
+static int create_log_context(struct dirty_log *log, struct dm_target *ti,
+			      unsigned int argc, char **argv,
+			      struct dm_dev *dev)
 {
 	enum sync sync = DEFAULTSYNC;
 
 	struct log_c *lc;
 	uint32_t region_size;
 	unsigned int region_count;
-	size_t bitset_size;
+	size_t bitset_size, buf_size;
 
 	if (argc < 1 || argc > 2) {
 		DMWARN("wrong number of arguments to mirror log");
@@ -319,22 +297,53 @@
 	 * Work out how many "unsigned long"s we need to hold the bitset.
 	 */
 	bitset_size = dm_round_up(region_count,
-				  sizeof(unsigned long) << BYTE_SHIFT);
+				  sizeof(*lc->clean_bits) << BYTE_SHIFT);
 	bitset_size >>= BYTE_SHIFT;
 
-	lc->bitset_uint32_count = bitset_size / 4;
-	lc->clean_bits = vmalloc(bitset_size);
-	if (!lc->clean_bits) {
-		DMWARN("couldn't allocate clean bitset");
-		kfree(lc);
-		return -ENOMEM;
+	lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
+
+	/*
+	 * Disk log?
+	 */
+	if (!dev) {
+		lc->clean_bits = vmalloc(bitset_size);
+		if (!lc->clean_bits) {
+			DMWARN("couldn't allocate clean bitset");
+			kfree(lc);
+			return -ENOMEM;
+		}
+		lc->disk_header = NULL;
+	} else {
+		lc->log_dev = dev;
+		lc->header_location.bdev = lc->log_dev->bdev;
+		lc->header_location.sector = 0;
+
+		/*
+		 * Buffer holds both header and bitset.
+		 */
+		buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
+				       bitset_size, ti->limits.hardsect_size);
+		lc->header_location.count = buf_size >> SECTOR_SHIFT;
+
+		lc->disk_header = vmalloc(buf_size);
+		if (!lc->disk_header) {
+			DMWARN("couldn't allocate disk log buffer");
+			kfree(lc);
+			return -ENOMEM;
+		}
+
+		lc->clean_bits = (void *)lc->disk_header +
+				 (LOG_OFFSET << SECTOR_SHIFT);
 	}
+
 	memset(lc->clean_bits, -1, bitset_size);
 
 	lc->sync_bits = vmalloc(bitset_size);
 	if (!lc->sync_bits) {
 		DMWARN("couldn't allocate sync bitset");
-		vfree(lc->clean_bits);
+		if (!dev)
+			vfree(lc->clean_bits);
+		vfree(lc->disk_header);
 		kfree(lc);
 		return -ENOMEM;
 	}
@@ -345,23 +354,38 @@
 	if (!lc->recovering_bits) {
 		DMWARN("couldn't allocate sync bitset");
 		vfree(lc->sync_bits);
-		vfree(lc->clean_bits);
+		if (!dev)
+			vfree(lc->clean_bits);
+		vfree(lc->disk_header);
 		kfree(lc);
 		return -ENOMEM;
 	}
 	memset(lc->recovering_bits, 0, bitset_size);
 	lc->sync_search = 0;
 	log->context = lc;
+
 	return 0;
 }
 
+static int core_ctr(struct dirty_log *log, struct dm_target *ti,
+		    unsigned int argc, char **argv)
+{
+	return create_log_context(log, ti, argc, argv, NULL);
+}
+
+static void destroy_log_context(struct log_c *lc)
+{
+	vfree(lc->sync_bits);
+	vfree(lc->recovering_bits);
+	kfree(lc);
+}
+
 static void core_dtr(struct dirty_log *log)
 {
 	struct log_c *lc = (struct log_c *) log->context;
+
 	vfree(lc->clean_bits);
-	vfree(lc->sync_bits);
-	vfree(lc->recovering_bits);
-	kfree(lc);
+	destroy_log_context(lc);
 }
 
 /*----------------------------------------------------------------
@@ -373,8 +397,6 @@
 		    unsigned int argc, char **argv)
 {
 	int r;
-	size_t size;
-	struct log_c *lc;
 	struct dm_dev *dev;
 
 	if (argc < 2 || argc > 3) {
@@ -387,49 +409,22 @@
 	if (r)
 		return r;
 
-	r = core_ctr(log, ti, argc - 1, argv + 1);
+	r = create_log_context(log, ti, argc - 1, argv + 1, dev);
 	if (r) {
 		dm_put_device(ti, dev);
 		return r;
 	}
 
-	lc = (struct log_c *) log->context;
-	lc->log_dev = dev;
-
-	/* setup the disk header fields */
-	lc->header_location.bdev = lc->log_dev->bdev;
-	lc->header_location.sector = 0;
-	lc->header_location.count = 1;
-
-	/*
-	 * We can't read less than this amount, even though we'll
-	 * not be using most of this space.
-	 */
-	lc->disk_header = vmalloc(1 << SECTOR_SHIFT);
-	if (!lc->disk_header)
-		goto bad;
-
-	/* setup the disk bitset fields */
-	lc->bits_location.bdev = lc->log_dev->bdev;
-	lc->bits_location.sector = LOG_OFFSET;
-
-	size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t),
-			   1 << SECTOR_SHIFT);
-	lc->bits_location.count = size >> SECTOR_SHIFT;
 	return 0;
-
- bad:
-	dm_put_device(ti, lc->log_dev);
-	core_dtr(log);
-	return -ENOMEM;
 }
 
 static void disk_dtr(struct dirty_log *log)
 {
 	struct log_c *lc = (struct log_c *) log->context;
+
 	dm_put_device(lc->ti, lc->log_dev);
 	vfree(lc->disk_header);
-	core_dtr(log);
+	destroy_log_context(lc);
 }
 
 static int count_bits32(uint32_t *addr, unsigned size)
@@ -454,12 +449,7 @@
 	if (r)
 		return r;
 
-	/* read the bits */
-	r = read_bits(lc);
-	if (r)
-		return r;
-
-	/* set or clear any new bits */
+	/* set or clear any new bits -- device has grown */
 	if (lc->sync == NOSYNC)
 		for (i = lc->header.nr_regions; i < lc->region_count; i++)
 			/* FIXME: amazingly inefficient */
@@ -469,15 +459,14 @@
 			/* FIXME: amazingly inefficient */
 			log_clear_bit(lc, lc->clean_bits, i);
 
+	/* clear any old bits -- device has shrunk */
+	for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++)
+		log_clear_bit(lc, lc->clean_bits, i);
+
 	/* copy clean across to sync */
 	memcpy(lc->sync_bits, lc->clean_bits, size);
 	lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
 
-	/* write the bits */
-	r = write_bits(lc);
-	if (r)
-		return r;
-
 	/* set the correct number of regions in the header */
 	lc->header.nr_regions = lc->region_count;
 
@@ -518,7 +507,7 @@
 	if (!lc->touched)
 		return 0;
 
-	r = write_bits(lc);
+	r = write_header(lc);
 	if (!r)
 		lc->touched = 0;
 
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 1816f30..217615b 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -21,6 +21,7 @@
 #include <linux/workqueue.h>
 #include <asm/atomic.h>
 
+#define DM_MSG_PREFIX "multipath"
 #define MESG_STR(x) x, sizeof(x)
 
 /* Path properties */
@@ -446,8 +447,6 @@
 	char *error;
 };
 
-#define ESTR(s) ("dm-multipath: " s)
-
 static int read_param(struct param *param, char *str, unsigned *v, char **error)
 {
 	if (!str ||
@@ -495,12 +494,12 @@
 	unsigned ps_argc;
 
 	static struct param _params[] = {
-		{0, 1024, ESTR("invalid number of path selector args")},
+		{0, 1024, "invalid number of path selector args"},
 	};
 
 	pst = dm_get_path_selector(shift(as));
 	if (!pst) {
-		ti->error = ESTR("unknown path selector type");
+		ti->error = "unknown path selector type";
 		return -EINVAL;
 	}
 
@@ -511,7 +510,7 @@
 	r = pst->create(&pg->ps, ps_argc, as->argv);
 	if (r) {
 		dm_put_path_selector(pst);
-		ti->error = ESTR("path selector constructor failed");
+		ti->error = "path selector constructor failed";
 		return r;
 	}
 
@@ -529,7 +528,7 @@
 
 	/* we need at least a path arg */
 	if (as->argc < 1) {
-		ti->error = ESTR("no device given");
+		ti->error = "no device given";
 		return NULL;
 	}
 
@@ -540,7 +539,7 @@
 	r = dm_get_device(ti, shift(as), ti->begin, ti->len,
 			  dm_table_get_mode(ti->table), &p->path.dev);
 	if (r) {
-		ti->error = ESTR("error getting device");
+		ti->error = "error getting device";
 		goto bad;
 	}
 
@@ -562,8 +561,8 @@
 						   struct dm_target *ti)
 {
 	static struct param _params[] = {
-		{1, 1024, ESTR("invalid number of paths")},
-		{0, 1024, ESTR("invalid number of selector args")}
+		{1, 1024, "invalid number of paths"},
+		{0, 1024, "invalid number of selector args"}
 	};
 
 	int r;
@@ -572,13 +571,13 @@
 
 	if (as->argc < 2) {
 		as->argc = 0;
-		ti->error = ESTR("not enough priority group aruments");
+		ti->error = "not enough priority group aruments";
 		return NULL;
 	}
 
 	pg = alloc_priority_group();
 	if (!pg) {
-		ti->error = ESTR("couldn't allocate priority group");
+		ti->error = "couldn't allocate priority group";
 		return NULL;
 	}
 	pg->m = m;
@@ -633,7 +632,7 @@
 	unsigned hw_argc;
 
 	static struct param _params[] = {
-		{0, 1024, ESTR("invalid number of hardware handler args")},
+		{0, 1024, "invalid number of hardware handler args"},
 	};
 
 	r = read_param(_params, shift(as), &hw_argc, &ti->error);
@@ -645,14 +644,14 @@
 
 	hwht = dm_get_hw_handler(shift(as));
 	if (!hwht) {
-		ti->error = ESTR("unknown hardware handler type");
+		ti->error = "unknown hardware handler type";
 		return -EINVAL;
 	}
 
 	r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
 	if (r) {
 		dm_put_hw_handler(hwht);
-		ti->error = ESTR("hardware handler constructor failed");
+		ti->error = "hardware handler constructor failed";
 		return r;
 	}
 
@@ -669,7 +668,7 @@
 	unsigned argc;
 
 	static struct param _params[] = {
-		{0, 1, ESTR("invalid number of feature args")},
+		{0, 1, "invalid number of feature args"},
 	};
 
 	r = read_param(_params, shift(as), &argc, &ti->error);
@@ -692,8 +691,8 @@
 {
 	/* target parameters */
 	static struct param _params[] = {
-		{1, 1024, ESTR("invalid number of priority groups")},
-		{1, 1024, ESTR("invalid initial priority group number")},
+		{1, 1024, "invalid number of priority groups"},
+		{1, 1024, "invalid initial priority group number"},
 	};
 
 	int r;
@@ -707,7 +706,7 @@
 
 	m = alloc_multipath();
 	if (!m) {
-		ti->error = ESTR("can't allocate multipath");
+		ti->error = "can't allocate multipath";
 		return -EINVAL;
 	}
 
@@ -746,7 +745,7 @@
 	}
 
 	if (pg_count != m->nr_priority_groups) {
-		ti->error = ESTR("priority group count mismatch");
+		ti->error = "priority group count mismatch";
 		r = -EINVAL;
 		goto bad;
 	}
@@ -807,7 +806,7 @@
 	if (!pgpath->path.is_active)
 		goto out;
 
-	DMWARN("dm-multipath: Failing path %s.", pgpath->path.dev->name);
+	DMWARN("Failing path %s.", pgpath->path.dev->name);
 
 	pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path);
 	pgpath->path.is_active = 0;
@@ -1250,7 +1249,7 @@
 	r = dm_get_device(ti, argv[1], ti->begin, ti->len,
 			  dm_table_get_mode(ti->table), &dev);
 	if (r) {
-		DMWARN("dm-multipath message: error getting device %s",
+		DMWARN("message: error getting device %s",
 		       argv[1]);
 		return -EINVAL;
 	}
@@ -1309,7 +1308,7 @@
 		return -ENOMEM;
 	}
 
-	DMINFO("dm-multipath version %u.%u.%u loaded",
+	DMINFO("version %u.%u.%u loaded",
 	       multipath_target.version[0], multipath_target.version[1],
 	       multipath_target.version[2]);
 
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index d12cf3e..be48ced 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -20,6 +20,8 @@
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
 
+#define DM_MSG_PREFIX "raid1"
+
 static struct workqueue_struct *_kmirrord_wq;
 static struct work_struct _kmirrord_work;
 
@@ -106,12 +108,42 @@
 	struct bio_list delayed_bios;
 };
 
+
+/*-----------------------------------------------------------------
+ * Mirror set structures.
+ *---------------------------------------------------------------*/
+struct mirror {
+	atomic_t error_count;
+	struct dm_dev *dev;
+	sector_t offset;
+};
+
+struct mirror_set {
+	struct dm_target *ti;
+	struct list_head list;
+	struct region_hash rh;
+	struct kcopyd_client *kcopyd_client;
+
+	spinlock_t lock;	/* protects the next two lists */
+	struct bio_list reads;
+	struct bio_list writes;
+
+	/* recovery */
+	region_t nr_regions;
+	int in_sync;
+
+	struct mirror *default_mirror;	/* Default mirror */
+
+	unsigned int nr_mirrors;
+	struct mirror mirror[0];
+};
+
 /*
  * Conversion fns
  */
 static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio)
 {
-	return bio->bi_sector >> rh->region_shift;
+	return (bio->bi_sector - rh->ms->ti->begin) >> rh->region_shift;
 }
 
 static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
@@ -458,11 +490,9 @@
 	/* Already quiesced ? */
 	if (atomic_read(&reg->pending))
 		list_del_init(&reg->list);
+	else
+		list_move(&reg->list, &rh->quiesced_regions);
 
-	else {
-		list_del_init(&reg->list);
-		list_add(&reg->list, &rh->quiesced_regions);
-	}
 	spin_unlock_irq(&rh->region_lock);
 
 	return 1;
@@ -541,35 +571,6 @@
 	wake();
 }
 
-/*-----------------------------------------------------------------
- * Mirror set structures.
- *---------------------------------------------------------------*/
-struct mirror {
-	atomic_t error_count;
-	struct dm_dev *dev;
-	sector_t offset;
-};
-
-struct mirror_set {
-	struct dm_target *ti;
-	struct list_head list;
-	struct region_hash rh;
-	struct kcopyd_client *kcopyd_client;
-
-	spinlock_t lock;	/* protects the next two lists */
-	struct bio_list reads;
-	struct bio_list writes;
-
-	/* recovery */
-	region_t nr_regions;
-	int in_sync;
-
-	struct mirror *default_mirror;	/* Default mirror */
-
-	unsigned int nr_mirrors;
-	struct mirror mirror[0];
-};
-
 /*
  * Every mirror should look like this one.
  */
@@ -603,7 +604,7 @@
 	struct region *reg = (struct region *) context;
 
 	/* FIXME: better error handling */
-	rh_recovery_end(reg, read_err || write_err);
+	rh_recovery_end(reg, !(read_err || write_err));
 }
 
 static int recover(struct mirror_set *ms, struct region *reg)
@@ -893,7 +894,7 @@
 
 	ms = kmalloc(len, GFP_KERNEL);
 	if (!ms) {
-		ti->error = "dm-mirror: Cannot allocate mirror context";
+		ti->error = "Cannot allocate mirror context";
 		return NULL;
 	}
 
@@ -907,7 +908,7 @@
 	ms->default_mirror = &ms->mirror[DEFAULT_MIRROR];
 
 	if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
-		ti->error = "dm-mirror: Error creating dirty region hash";
+		ti->error = "Error creating dirty region hash";
 		kfree(ms);
 		return NULL;
 	}
@@ -937,14 +938,14 @@
 	unsigned long long offset;
 
 	if (sscanf(argv[1], "%llu", &offset) != 1) {
-		ti->error = "dm-mirror: Invalid offset";
+		ti->error = "Invalid offset";
 		return -EINVAL;
 	}
 
 	if (dm_get_device(ti, argv[0], offset, ti->len,
 			  dm_table_get_mode(ti->table),
 			  &ms->mirror[mirror].dev)) {
-		ti->error = "dm-mirror: Device lookup failure";
+		ti->error = "Device lookup failure";
 		return -ENXIO;
 	}
 
@@ -981,30 +982,30 @@
 	struct dirty_log *dl;
 
 	if (argc < 2) {
-		ti->error = "dm-mirror: Insufficient mirror log arguments";
+		ti->error = "Insufficient mirror log arguments";
 		return NULL;
 	}
 
 	if (sscanf(argv[1], "%u", &param_count) != 1) {
-		ti->error = "dm-mirror: Invalid mirror log argument count";
+		ti->error = "Invalid mirror log argument count";
 		return NULL;
 	}
 
 	*args_used = 2 + param_count;
 
 	if (argc < *args_used) {
-		ti->error = "dm-mirror: Insufficient mirror log arguments";
+		ti->error = "Insufficient mirror log arguments";
 		return NULL;
 	}
 
 	dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2);
 	if (!dl) {
-		ti->error = "dm-mirror: Error creating mirror dirty log";
+		ti->error = "Error creating mirror dirty log";
 		return NULL;
 	}
 
 	if (!_check_region_size(ti, dl->type->get_region_size(dl))) {
-		ti->error = "dm-mirror: Invalid region size";
+		ti->error = "Invalid region size";
 		dm_destroy_dirty_log(dl);
 		return NULL;
 	}
@@ -1038,7 +1039,7 @@
 
 	if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
 	    nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) {
-		ti->error = "dm-mirror: Invalid number of mirrors";
+		ti->error = "Invalid number of mirrors";
 		dm_destroy_dirty_log(dl);
 		return -EINVAL;
 	}
@@ -1046,7 +1047,7 @@
 	argv++, argc--;
 
 	if (argc != nr_mirrors * 2) {
-		ti->error = "dm-mirror: Wrong number of mirror arguments";
+		ti->error = "Wrong number of mirror arguments";
 		dm_destroy_dirty_log(dl);
 		return -EINVAL;
 	}
@@ -1115,7 +1116,7 @@
 	struct mirror *m;
 	struct mirror_set *ms = ti->private;
 
-	map_context->ll = bio->bi_sector >> ms->rh.region_shift;
+	map_context->ll = bio_to_region(&ms->rh, bio);
 
 	if (rw == WRITE) {
 		queue_bio(ms, bio, rw);
@@ -1221,7 +1222,7 @@
 
 static struct target_type mirror_target = {
 	.name	 = "mirror",
-	.version = {1, 0, 1},
+	.version = {1, 0, 2},
 	.module	 = THIS_MODULE,
 	.ctr	 = mirror_ctr,
 	.dtr	 = mirror_dtr,
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index d002486..c5a16c5 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -14,6 +14,8 @@
 
 #include <linux/slab.h>
 
+#define DM_MSG_PREFIX "multipath round-robin"
+
 /*-----------------------------------------------------------------
  * Path-handling code, paths are held in lists
  *---------------------------------------------------------------*/
@@ -191,9 +193,9 @@
 	int r = dm_register_path_selector(&rr_ps);
 
 	if (r < 0)
-		DMERR("round-robin: register failed %d", r);
+		DMERR("register failed %d", r);
 
-	DMINFO("dm-round-robin version 1.0.0 loaded");
+	DMINFO("version 1.0.0 loaded");
 
 	return r;
 }
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 08312b4..8eea0ddb 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -23,6 +23,8 @@
 #include "dm-bio-list.h"
 #include "kcopyd.h"
 
+#define DM_MSG_PREFIX "snapshots"
+
 /*
  * The percentage increment we will wake up users at
  */
@@ -117,7 +119,7 @@
 	_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
 			   GFP_KERNEL);
 	if (!_origins) {
-		DMERR("Device mapper: Snapshot: unable to allocate memory");
+		DMERR("unable to allocate memory");
 		return -ENOMEM;
 	}
 
@@ -412,7 +414,7 @@
 	int blocksize;
 
 	if (argc < 4) {
-		ti->error = "dm-snapshot: requires exactly 4 arguments";
+		ti->error = "requires exactly 4 arguments";
 		r = -EINVAL;
 		goto bad1;
 	}
@@ -530,7 +532,7 @@
 	}
 
 	ti->private = s;
-	ti->split_io = chunk_size;
+	ti->split_io = s->chunk_size;
 
 	return 0;
 
@@ -1127,7 +1129,7 @@
 	struct dm_dev *dev;
 
 	if (argc != 1) {
-		ti->error = "dm-origin: incorrect number of arguments";
+		ti->error = "origin: incorrect number of arguments";
 		return -EINVAL;
 	}
 
@@ -1204,7 +1206,7 @@
 
 static struct target_type origin_target = {
 	.name    = "snapshot-origin",
-	.version = {1, 1, 0},
+	.version = {1, 4, 0},
 	.module  = THIS_MODULE,
 	.ctr     = origin_ctr,
 	.dtr     = origin_dtr,
@@ -1215,7 +1217,7 @@
 
 static struct target_type snapshot_target = {
 	.name    = "snapshot",
-	.version = {1, 1, 0},
+	.version = {1, 4, 0},
 	.module  = THIS_MODULE,
 	.ctr     = snapshot_ctr,
 	.dtr     = snapshot_dtr,
@@ -1236,7 +1238,7 @@
 
 	r = dm_register_target(&origin_target);
 	if (r < 0) {
-		DMERR("Device mapper: Origin: register failed %d\n", r);
+		DMERR("Origin target register failed %d", r);
 		goto bad1;
 	}
 
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 08328a8..6c29fce 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -12,6 +12,8 @@
 #include <linux/bio.h>
 #include <linux/slab.h>
 
+#define DM_MSG_PREFIX "striped"
+
 struct stripe {
 	struct dm_dev *dev;
 	sector_t physical_start;
@@ -78,19 +80,19 @@
 	unsigned int i;
 
 	if (argc < 2) {
-		ti->error = "dm-stripe: Not enough arguments";
+		ti->error = "Not enough arguments";
 		return -EINVAL;
 	}
 
 	stripes = simple_strtoul(argv[0], &end, 10);
 	if (*end) {
-		ti->error = "dm-stripe: Invalid stripe count";
+		ti->error = "Invalid stripe count";
 		return -EINVAL;
 	}
 
 	chunk_size = simple_strtoul(argv[1], &end, 10);
 	if (*end) {
-		ti->error = "dm-stripe: Invalid chunk_size";
+		ti->error = "Invalid chunk_size";
 		return -EINVAL;
 	}
 
@@ -99,19 +101,19 @@
 	 */
 	if (!chunk_size || (chunk_size & (chunk_size - 1)) ||
 	    (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
-		ti->error = "dm-stripe: Invalid chunk size";
+		ti->error = "Invalid chunk size";
 		return -EINVAL;
 	}
 
 	if (ti->len & (chunk_size - 1)) {
-		ti->error = "dm-stripe: Target length not divisible by "
+		ti->error = "Target length not divisible by "
 		    "chunk size";
 		return -EINVAL;
 	}
 
 	width = ti->len;
 	if (sector_div(width, stripes)) {
-		ti->error = "dm-stripe: Target length not divisible by "
+		ti->error = "Target length not divisible by "
 		    "number of stripes";
 		return -EINVAL;
 	}
@@ -120,14 +122,14 @@
 	 * Do we have enough arguments for that many stripes ?
 	 */
 	if (argc != (2 + 2 * stripes)) {
-		ti->error = "dm-stripe: Not enough destinations "
+		ti->error = "Not enough destinations "
 			"specified";
 		return -EINVAL;
 	}
 
 	sc = alloc_context(stripes);
 	if (!sc) {
-		ti->error = "dm-stripe: Memory allocation for striped context "
+		ti->error = "Memory allocation for striped context "
 		    "failed";
 		return -ENOMEM;
 	}
@@ -149,8 +151,7 @@
 
 		r = get_stripe(ti, sc, i, argv);
 		if (r < 0) {
-			ti->error = "dm-stripe: Couldn't parse stripe "
-				"destination";
+			ti->error = "Couldn't parse stripe destination";
 			while (i--)
 				dm_put_device(ti, sc->stripe[i].dev);
 			kfree(sc);
@@ -227,7 +228,7 @@
 
 	r = dm_register_target(&stripe_target);
 	if (r < 0)
-		DMWARN("striped target registration failed");
+		DMWARN("target registration failed");
 
 	return r;
 }
@@ -235,7 +236,7 @@
 void dm_stripe_exit(void)
 {
 	if (dm_unregister_target(&stripe_target))
-		DMWARN("striped target unregistration failed");
+		DMWARN("target unregistration failed");
 
 	return;
 }
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 8f56a54..75fe949 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -17,6 +17,8 @@
 #include <linux/mutex.h>
 #include <asm/atomic.h>
 
+#define DM_MSG_PREFIX "table"
+
 #define MAX_DEPTH 16
 #define NODE_SIZE L1_CACHE_BYTES
 #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
@@ -237,6 +239,44 @@
 	return 0;
 }
 
+int dm_create_error_table(struct dm_table **result, struct mapped_device *md)
+{
+	struct dm_table *t;
+	sector_t dev_size = 1;
+	int r;
+
+	/*
+	 * Find current size of device.
+	 * Default to 1 sector if inactive.
+	 */
+	t = dm_get_table(md);
+	if (t) {
+		dev_size = dm_table_get_size(t);
+		dm_table_put(t);
+	}
+
+	r = dm_table_create(&t, FMODE_READ, 1, md);
+	if (r)
+		return r;
+
+	r = dm_table_add_target(t, "error", 0, dev_size, NULL);
+	if (r)
+		goto out;
+
+	r = dm_table_complete(t);
+	if (r)
+		goto out;
+
+	*result = t;
+
+out:
+	if (r)
+		dm_table_put(t);
+
+	return r;
+}
+EXPORT_SYMBOL_GPL(dm_create_error_table);
+
 static void free_devices(struct list_head *devices)
 {
 	struct list_head *tmp, *next;
@@ -590,6 +630,12 @@
 	unsigned array_size = 0;
 
 	*argc = 0;
+
+	if (!input) {
+		*argvp = NULL;
+		return 0;
+	}
+
 	argv = realloc_argv(&array_size, argv);
 	if (!argv)
 		return -ENOMEM;
@@ -671,15 +717,14 @@
 	memset(tgt, 0, sizeof(*tgt));
 
 	if (!len) {
-		tgt->error = "zero-length target";
-		DMERR("%s", tgt->error);
+		DMERR("%s: zero-length target", dm_device_name(t->md));
 		return -EINVAL;
 	}
 
 	tgt->type = dm_get_target_type(type);
 	if (!tgt->type) {
-		tgt->error = "unknown target type";
-		DMERR("%s", tgt->error);
+		DMERR("%s: %s: unknown target type", dm_device_name(t->md),
+		      type);
 		return -EINVAL;
 	}
 
@@ -716,7 +761,7 @@
 	return 0;
 
  bad:
-	DMERR("%s", tgt->error);
+	DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error);
 	dm_put_target_type(tgt->type);
 	return r;
 }
@@ -802,7 +847,7 @@
 
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index)
 {
-	if (index > t->num_targets)
+	if (index >= t->num_targets)
 		return NULL;
 
 	return t->targets + index;
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 64fd8e7..477a041 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -12,6 +12,8 @@
 #include <linux/bio.h>
 #include <linux/slab.h>
 
+#define DM_MSG_PREFIX "target"
+
 struct tt_internal {
 	struct target_type tt;
 
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index 51c0639..ea569f7 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -10,13 +10,15 @@
 #include <linux/init.h>
 #include <linux/bio.h>
 
+#define DM_MSG_PREFIX "zero"
+
 /*
  * Construct a dummy mapping that only returns zeros
  */
 static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
 	if (argc != 0) {
-		ti->error = "dm-zero: No arguments required";
+		ti->error = "No arguments required";
 		return -EINVAL;
 	}
 
@@ -60,7 +62,7 @@
 	int r = dm_register_target(&zero_target);
 
 	if (r < 0)
-		DMERR("zero: register failed %d", r);
+		DMERR("register failed %d", r);
 
 	return r;
 }
@@ -70,7 +72,7 @@
 	int r = dm_unregister_target(&zero_target);
 
 	if (r < 0)
-		DMERR("zero: unregister failed %d", r);
+		DMERR("unregister failed %d", r);
 }
 
 module_init(dm_zero_init)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 4d710b7..3ed2e53 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the GPL.
  */
@@ -21,11 +21,14 @@
 #include <linux/hdreg.h>
 #include <linux/blktrace_api.h>
 
+#define DM_MSG_PREFIX "core"
+
 static const char *_name = DM_NAME;
 
 static unsigned int major = 0;
 static unsigned int _major = 0;
 
+static DEFINE_SPINLOCK(_minor_lock);
 /*
  * One of these is allocated per bio.
  */
@@ -49,23 +52,28 @@
 
 union map_info *dm_get_mapinfo(struct bio *bio)
 {
-        if (bio && bio->bi_private)
-                return &((struct target_io *)bio->bi_private)->info;
-        return NULL;
+	if (bio && bio->bi_private)
+		return &((struct target_io *)bio->bi_private)->info;
+	return NULL;
 }
 
+#define MINOR_ALLOCED ((void *)-1)
+
 /*
  * Bits for the md->flags field.
  */
 #define DMF_BLOCK_IO 0
 #define DMF_SUSPENDED 1
 #define DMF_FROZEN 2
+#define DMF_FREEING 3
+#define DMF_DELETING 4
 
 struct mapped_device {
 	struct rw_semaphore io_lock;
 	struct semaphore suspend_lock;
 	rwlock_t map_lock;
 	atomic_t holders;
+	atomic_t open_count;
 
 	unsigned long flags;
 
@@ -218,9 +226,25 @@
 {
 	struct mapped_device *md;
 
+	spin_lock(&_minor_lock);
+
 	md = inode->i_bdev->bd_disk->private_data;
+	if (!md)
+		goto out;
+
+	if (test_bit(DMF_FREEING, &md->flags) ||
+	    test_bit(DMF_DELETING, &md->flags)) {
+		md = NULL;
+		goto out;
+	}
+
 	dm_get(md);
-	return 0;
+	atomic_inc(&md->open_count);
+
+out:
+	spin_unlock(&_minor_lock);
+
+	return md ? 0 : -ENXIO;
 }
 
 static int dm_blk_close(struct inode *inode, struct file *file)
@@ -228,10 +252,35 @@
 	struct mapped_device *md;
 
 	md = inode->i_bdev->bd_disk->private_data;
+	atomic_dec(&md->open_count);
 	dm_put(md);
 	return 0;
 }
 
+int dm_open_count(struct mapped_device *md)
+{
+	return atomic_read(&md->open_count);
+}
+
+/*
+ * Guarantees nothing is using the device before it's deleted.
+ */
+int dm_lock_for_deletion(struct mapped_device *md)
+{
+	int r = 0;
+
+	spin_lock(&_minor_lock);
+
+	if (dm_open_count(md))
+		r = -EBUSY;
+	else
+		set_bit(DMF_DELETING, &md->flags);
+
+	spin_unlock(&_minor_lock);
+
+	return r;
+}
+
 static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
 	struct mapped_device *md = bdev->bd_disk->private_data;
@@ -456,8 +505,8 @@
 	if (r > 0) {
 		/* the bio has been remapped so dispatch it */
 
-		blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, 
-				    tio->io->bio->bi_bdev->bd_dev, sector, 
+		blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
+				    tio->io->bio->bi_bdev->bd_dev, sector,
 				    clone->bi_sector);
 
 		generic_make_request(clone);
@@ -744,43 +793,39 @@
 /*-----------------------------------------------------------------
  * An IDR is used to keep track of allocated minor numbers.
  *---------------------------------------------------------------*/
-static DEFINE_MUTEX(_minor_lock);
 static DEFINE_IDR(_minor_idr);
 
-static void free_minor(unsigned int minor)
+static void free_minor(int minor)
 {
-	mutex_lock(&_minor_lock);
+	spin_lock(&_minor_lock);
 	idr_remove(&_minor_idr, minor);
-	mutex_unlock(&_minor_lock);
+	spin_unlock(&_minor_lock);
 }
 
 /*
  * See if the device with a specific minor # is free.
  */
-static int specific_minor(struct mapped_device *md, unsigned int minor)
+static int specific_minor(struct mapped_device *md, int minor)
 {
 	int r, m;
 
 	if (minor >= (1 << MINORBITS))
 		return -EINVAL;
 
-	mutex_lock(&_minor_lock);
+	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
+	if (!r)
+		return -ENOMEM;
+
+	spin_lock(&_minor_lock);
 
 	if (idr_find(&_minor_idr, minor)) {
 		r = -EBUSY;
 		goto out;
 	}
 
-	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
-	if (!r) {
-		r = -ENOMEM;
+	r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m);
+	if (r)
 		goto out;
-	}
-
-	r = idr_get_new_above(&_minor_idr, md, minor, &m);
-	if (r) {
-		goto out;
-	}
 
 	if (m != minor) {
 		idr_remove(&_minor_idr, m);
@@ -789,24 +834,21 @@
 	}
 
 out:
-	mutex_unlock(&_minor_lock);
+	spin_unlock(&_minor_lock);
 	return r;
 }
 
-static int next_free_minor(struct mapped_device *md, unsigned int *minor)
+static int next_free_minor(struct mapped_device *md, int *minor)
 {
-	int r;
-	unsigned int m;
-
-	mutex_lock(&_minor_lock);
+	int r, m;
 
 	r = idr_pre_get(&_minor_idr, GFP_KERNEL);
-	if (!r) {
-		r = -ENOMEM;
-		goto out;
-	}
+	if (!r)
+		return -ENOMEM;
 
-	r = idr_get_new(&_minor_idr, md, &m);
+	spin_lock(&_minor_lock);
+
+	r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m);
 	if (r) {
 		goto out;
 	}
@@ -820,7 +862,7 @@
 	*minor = m;
 
 out:
-	mutex_unlock(&_minor_lock);
+	spin_unlock(&_minor_lock);
 	return r;
 }
 
@@ -829,18 +871,25 @@
 /*
  * Allocate and initialise a blank device with a given minor.
  */
-static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
+static struct mapped_device *alloc_dev(int minor)
 {
 	int r;
 	struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
+	void *old_md;
 
 	if (!md) {
 		DMWARN("unable to allocate device, out of memory.");
 		return NULL;
 	}
 
+	if (!try_module_get(THIS_MODULE))
+		goto bad0;
+
 	/* get a minor number for the dev */
-	r = persistent ? specific_minor(md, minor) : next_free_minor(md, &minor);
+	if (minor == DM_ANY_MINOR)
+		r = next_free_minor(md, &minor);
+	else
+		r = specific_minor(md, minor);
 	if (r < 0)
 		goto bad1;
 
@@ -849,6 +898,7 @@
 	init_MUTEX(&md->suspend_lock);
 	rwlock_init(&md->map_lock);
 	atomic_set(&md->holders, 1);
+	atomic_set(&md->open_count, 0);
 	atomic_set(&md->event_nr, 0);
 
 	md->queue = blk_alloc_queue(GFP_KERNEL);
@@ -875,6 +925,10 @@
 	if (!md->disk)
 		goto bad4;
 
+	atomic_set(&md->pending, 0);
+	init_waitqueue_head(&md->wait);
+	init_waitqueue_head(&md->eventq);
+
 	md->disk->major = _major;
 	md->disk->first_minor = minor;
 	md->disk->fops = &dm_blk_dops;
@@ -884,9 +938,12 @@
 	add_disk(md->disk);
 	format_dev_t(md->name, MKDEV(_major, minor));
 
-	atomic_set(&md->pending, 0);
-	init_waitqueue_head(&md->wait);
-	init_waitqueue_head(&md->eventq);
+	/* Populate the mapping, nobody knows we exist yet */
+	spin_lock(&_minor_lock);
+	old_md = idr_replace(&_minor_idr, md, minor);
+	spin_unlock(&_minor_lock);
+
+	BUG_ON(old_md != MINOR_ALLOCED);
 
 	return md;
 
@@ -898,13 +955,15 @@
 	blk_cleanup_queue(md->queue);
 	free_minor(minor);
  bad1:
+	module_put(THIS_MODULE);
+ bad0:
 	kfree(md);
 	return NULL;
 }
 
 static void free_dev(struct mapped_device *md)
 {
-	unsigned int minor = md->disk->first_minor;
+	int minor = md->disk->first_minor;
 
 	if (md->suspended_bdev) {
 		thaw_bdev(md->suspended_bdev, NULL);
@@ -914,8 +973,14 @@
 	mempool_destroy(md->io_pool);
 	del_gendisk(md->disk);
 	free_minor(minor);
+
+	spin_lock(&_minor_lock);
+	md->disk->private_data = NULL;
+	spin_unlock(&_minor_lock);
+
 	put_disk(md->disk);
 	blk_cleanup_queue(md->queue);
+	module_put(THIS_MODULE);
 	kfree(md);
 }
 
@@ -984,12 +1049,11 @@
 /*
  * Constructor for a new device.
  */
-static int create_aux(unsigned int minor, int persistent,
-		      struct mapped_device **result)
+int dm_create(int minor, struct mapped_device **result)
 {
 	struct mapped_device *md;
 
-	md = alloc_dev(minor, persistent);
+	md = alloc_dev(minor);
 	if (!md)
 		return -ENXIO;
 
@@ -997,16 +1061,6 @@
 	return 0;
 }
 
-int dm_create(struct mapped_device **result)
-{
-	return create_aux(0, 0, result);
-}
-
-int dm_create_with_minor(unsigned int minor, struct mapped_device **result)
-{
-	return create_aux(minor, 1, result);
-}
-
 static struct mapped_device *dm_find_md(dev_t dev)
 {
 	struct mapped_device *md;
@@ -1015,13 +1069,18 @@
 	if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
 		return NULL;
 
-	mutex_lock(&_minor_lock);
+	spin_lock(&_minor_lock);
 
 	md = idr_find(&_minor_idr, minor);
-	if (!md || (dm_disk(md)->first_minor != minor))
+	if (md && (md == MINOR_ALLOCED ||
+		   (dm_disk(md)->first_minor != minor) ||
+		   test_bit(DMF_FREEING, &md->flags))) {
 		md = NULL;
+		goto out;
+	}
 
-	mutex_unlock(&_minor_lock);
+out:
+	spin_unlock(&_minor_lock);
 
 	return md;
 }
@@ -1051,12 +1110,23 @@
 	atomic_inc(&md->holders);
 }
 
+const char *dm_device_name(struct mapped_device *md)
+{
+	return md->name;
+}
+EXPORT_SYMBOL_GPL(dm_device_name);
+
 void dm_put(struct mapped_device *md)
 {
 	struct dm_table *map;
 
-	if (atomic_dec_and_test(&md->holders)) {
+	BUG_ON(test_bit(DMF_FREEING, &md->flags));
+
+	if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {
 		map = dm_get_table(md);
+		idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor);
+		set_bit(DMF_FREEING, &md->flags);
+		spin_unlock(&_minor_lock);
 		if (!dm_suspended(md)) {
 			dm_table_presuspend_targets(map);
 			dm_table_postsuspend_targets(map);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index fd90bc8..3c03c0e 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -2,7 +2,7 @@
  * Internal header file for device mapper
  *
  * Copyright (C) 2001, 2002 Sistina Software
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the LGPL.
  */
@@ -17,9 +17,10 @@
 #include <linux/hdreg.h>
 
 #define DM_NAME "device-mapper"
-#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
-#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
-#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
+
+#define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
 
 #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
 			  0 : scnprintf(result + sz, maxlen - sz, x))
@@ -39,83 +40,16 @@
 };
 
 struct dm_table;
-struct mapped_device;
 
 /*-----------------------------------------------------------------
- * Functions for manipulating a struct mapped_device.
- * Drop the reference with dm_put when you finish with the object.
+ * Internal table functions.
  *---------------------------------------------------------------*/
-int dm_create(struct mapped_device **md);
-int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
-void dm_set_mdptr(struct mapped_device *md, void *ptr);
-void *dm_get_mdptr(struct mapped_device *md);
-struct mapped_device *dm_get_md(dev_t dev);
-
-/*
- * Reference counting for md.
- */
-void dm_get(struct mapped_device *md);
-void dm_put(struct mapped_device *md);
-
-/*
- * A device can still be used while suspended, but I/O is deferred.
- */
-int dm_suspend(struct mapped_device *md, int with_lockfs);
-int dm_resume(struct mapped_device *md);
-
-/*
- * The device must be suspended before calling this method.
- */
-int dm_swap_table(struct mapped_device *md, struct dm_table *t);
-
-/*
- * Drop a reference on the table when you've finished with the
- * result.
- */
-struct dm_table *dm_get_table(struct mapped_device *md);
-
-/*
- * Event functions.
- */
-uint32_t dm_get_event_nr(struct mapped_device *md);
-int dm_wait_event(struct mapped_device *md, int event_nr);
-
-/*
- * Info functions.
- */
-struct gendisk *dm_disk(struct mapped_device *md);
-int dm_suspended(struct mapped_device *md);
-
-/*
- * Geometry functions.
- */
-int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
-int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
-
-/*-----------------------------------------------------------------
- * Functions for manipulating a table.  Tables are also reference
- * counted.
- *---------------------------------------------------------------*/
-int dm_table_create(struct dm_table **result, int mode,
-		    unsigned num_targets, struct mapped_device *md);
-
-void dm_table_get(struct dm_table *t);
-void dm_table_put(struct dm_table *t);
-
-int dm_table_add_target(struct dm_table *t, const char *type,
-			sector_t start,	sector_t len, char *params);
-int dm_table_complete(struct dm_table *t);
 void dm_table_event_callback(struct dm_table *t,
 			     void (*fn)(void *), void *context);
-void dm_table_event(struct dm_table *t);
-sector_t dm_table_get_size(struct dm_table *t);
 struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
-unsigned int dm_table_get_num_targets(struct dm_table *t);
 struct list_head *dm_table_get_devices(struct dm_table *t);
-int dm_table_get_mode(struct dm_table *t);
-struct mapped_device *dm_table_get_md(struct dm_table *t);
 void dm_table_presuspend_targets(struct dm_table *t);
 void dm_table_postsuspend_targets(struct dm_table *t);
 void dm_table_resume_targets(struct dm_table *t);
@@ -133,7 +67,6 @@
 int dm_target_iterate(void (*iter_func)(struct target_type *tt,
 					void *param), void *param);
 
-
 /*-----------------------------------------------------------------
  * Useful inlines.
  *---------------------------------------------------------------*/
@@ -191,5 +124,7 @@
 
 void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
 union map_info *dm_get_mapinfo(struct bio *bio);
+int dm_open_count(struct mapped_device *md);
+int dm_lock_for_deletion(struct mapped_device *md);
 
 #endif
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index 72480a4..73ab875 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -314,7 +314,7 @@
 
 	if (error) {
 		if (job->rw == WRITE)
-			job->write_err &= error;
+			job->write_err |= error;
 		else
 			job->read_err = 1;
 
@@ -460,7 +460,7 @@
 		job->read_err = 1;
 
 	if (write_err)
-		job->write_err &= write_err;
+		job->write_err |= write_err;
 
 	/*
 	 * Only dispatch more work if there hasn't been an error.
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 77758545..ff83c9b 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -111,7 +111,7 @@
 	return ret;
 }
 
-static int linear_run (mddev_t *mddev)
+static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
 {
 	linear_conf_t *conf;
 	dev_info_t **table;
@@ -121,20 +121,21 @@
 	sector_t curr_offset;
 	struct list_head *tmp;
 
-	conf = kzalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t),
+	conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t),
 			GFP_KERNEL);
 	if (!conf)
-		goto out;
+		return NULL;
+
 	mddev->private = conf;
 
 	cnt = 0;
-	mddev->array_size = 0;
+	conf->array_size = 0;
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		int j = rdev->raid_disk;
 		dev_info_t *disk = conf->disks + j;
 
-		if (j < 0 || j > mddev->raid_disks || disk->rdev) {
+		if (j < 0 || j > raid_disks || disk->rdev) {
 			printk("linear: disk numbering problem. Aborting!\n");
 			goto out;
 		}
@@ -152,11 +153,11 @@
 			blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
 		disk->size = rdev->size;
-		mddev->array_size += rdev->size;
+		conf->array_size += rdev->size;
 
 		cnt++;
 	}
-	if (cnt != mddev->raid_disks) {
+	if (cnt != raid_disks) {
 		printk("linear: not enough drives present. Aborting!\n");
 		goto out;
 	}
@@ -200,7 +201,7 @@
 		unsigned round;
 		unsigned long base;
 
-		sz = mddev->array_size >> conf->preshift;
+		sz = conf->array_size >> conf->preshift;
 		sz += 1; /* force round-up */
 		base = conf->hash_spacing >> conf->preshift;
 		round = sector_div(sz, base);
@@ -247,14 +248,56 @@
 
 	BUG_ON(table - conf->hash_table > nb_zone);
 
+	return conf;
+
+out:
+	kfree(conf);
+	return NULL;
+}
+
+static int linear_run (mddev_t *mddev)
+{
+	linear_conf_t *conf;
+
+	conf = linear_conf(mddev, mddev->raid_disks);
+
+	if (!conf)
+		return 1;
+	mddev->private = conf;
+	mddev->array_size = conf->array_size;
+
 	blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
 	mddev->queue->unplug_fn = linear_unplug;
 	mddev->queue->issue_flush_fn = linear_issue_flush;
 	return 0;
+}
 
-out:
-	kfree(conf);
-	return 1;
+static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+	/* Adding a drive to a linear array allows the array to grow.
+	 * It is permitted if the new drive has a matching superblock
+	 * already on it, with raid_disk equal to raid_disks.
+	 * It is achieved by creating a new linear_private_data structure
+	 * and swapping it in in-place of the current one.
+	 * The current one is never freed until the array is stopped.
+	 * This avoids races.
+	 */
+	linear_conf_t *newconf;
+
+	if (rdev->raid_disk != mddev->raid_disks)
+		return -EINVAL;
+
+	newconf = linear_conf(mddev,mddev->raid_disks+1);
+
+	if (!newconf)
+		return -ENOMEM;
+
+	newconf->prev = mddev_to_conf(mddev);
+	mddev->private = newconf;
+	mddev->raid_disks++;
+	mddev->array_size = newconf->array_size;
+	set_capacity(mddev->gendisk, mddev->array_size << 1);
+	return 0;
 }
 
 static int linear_stop (mddev_t *mddev)
@@ -262,8 +305,12 @@
 	linear_conf_t *conf = mddev_to_conf(mddev);
   
 	blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
-	kfree(conf->hash_table);
-	kfree(conf);
+	do {
+		linear_conf_t *t = conf->prev;
+		kfree(conf->hash_table);
+		kfree(conf);
+		conf = t;
+	} while (conf);
 
 	return 0;
 }
@@ -360,6 +407,7 @@
 	.run		= linear_run,
 	.stop		= linear_stop,
 	.status		= linear_status,
+	.hot_add_disk	= linear_add,
 };
 
 static int __init linear_init (void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index f19b874..306268e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -44,6 +44,7 @@
 #include <linux/suspend.h>
 #include <linux/poll.h>
 #include <linux/mutex.h>
+#include <linux/ctype.h>
 
 #include <linux/init.h>
 
@@ -72,6 +73,10 @@
 static LIST_HEAD(pers_list);
 static DEFINE_SPINLOCK(pers_lock);
 
+static void md_print_devices(void);
+
+#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
+
 /*
  * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit'
  * is 1000 KB/sec, so the extra system load does not show up that much.
@@ -170,7 +175,7 @@
 /* Alternate version that can be called from interrupts
  * when calling sysfs_notify isn't needed.
  */
-void md_new_event_inintr(mddev_t *mddev)
+static void md_new_event_inintr(mddev_t *mddev)
 {
 	atomic_inc(&md_event_count);
 	wake_up(&md_event_waiters);
@@ -732,6 +737,7 @@
 {
 	mdp_disk_t *desc;
 	mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);
+	__u64 ev1 = md_event(sb);
 
 	rdev->raid_disk = -1;
 	rdev->flags = 0;
@@ -748,7 +754,7 @@
 		mddev->layout = sb->layout;
 		mddev->raid_disks = sb->raid_disks;
 		mddev->size = sb->size;
-		mddev->events = md_event(sb);
+		mddev->events = ev1;
 		mddev->bitmap_offset = 0;
 		mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
 
@@ -797,7 +803,6 @@
 
 	} else if (mddev->pers == NULL) {
 		/* Insist on good event counter while assembling */
-		__u64 ev1 = md_event(sb);
 		++ev1;
 		if (ev1 < mddev->events) 
 			return -EINVAL;
@@ -805,19 +810,21 @@
 		/* if adding to array with a bitmap, then we can accept an
 		 * older device ... but not too old.
 		 */
-		__u64 ev1 = md_event(sb);
 		if (ev1 < mddev->bitmap->events_cleared)
 			return 0;
-	} else /* just a hot-add of a new device, leave raid_disk at -1 */
-		return 0;
+	} else {
+		if (ev1 < mddev->events)
+			/* just a hot-add of a new device, leave raid_disk at -1 */
+			return 0;
+	}
 
 	if (mddev->level != LEVEL_MULTIPATH) {
 		desc = sb->disks + rdev->desc_nr;
 
 		if (desc->state & (1<<MD_DISK_FAULTY))
 			set_bit(Faulty, &rdev->flags);
-		else if (desc->state & (1<<MD_DISK_SYNC) &&
-			 desc->raid_disk < mddev->raid_disks) {
+		else if (desc->state & (1<<MD_DISK_SYNC) /* &&
+			    desc->raid_disk < mddev->raid_disks */) {
 			set_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = desc->raid_disk;
 		}
@@ -1100,6 +1107,7 @@
 static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
+	__u64 ev1 = le64_to_cpu(sb->events);
 
 	rdev->raid_disk = -1;
 	rdev->flags = 0;
@@ -1115,7 +1123,7 @@
 		mddev->layout = le32_to_cpu(sb->layout);
 		mddev->raid_disks = le32_to_cpu(sb->raid_disks);
 		mddev->size = le64_to_cpu(sb->size)/2;
-		mddev->events = le64_to_cpu(sb->events);
+		mddev->events = ev1;
 		mddev->bitmap_offset = 0;
 		mddev->default_bitmap_offset = 1024 >> 9;
 		
@@ -1149,7 +1157,6 @@
 
 	} else if (mddev->pers == NULL) {
 		/* Insist of good event counter while assembling */
-		__u64 ev1 = le64_to_cpu(sb->events);
 		++ev1;
 		if (ev1 < mddev->events)
 			return -EINVAL;
@@ -1157,12 +1164,13 @@
 		/* If adding to array with a bitmap, then we can accept an
 		 * older device, but not too old.
 		 */
-		__u64 ev1 = le64_to_cpu(sb->events);
 		if (ev1 < mddev->bitmap->events_cleared)
 			return 0;
-	} else /* just a hot-add of a new device, leave raid_disk at -1 */
-		return 0;
-
+	} else {
+		if (ev1 < mddev->events)
+			/* just a hot-add of a new device, leave raid_disk at -1 */
+			return 0;
+	}
 	if (mddev->level != LEVEL_MULTIPATH) {
 		int role;
 		rdev->desc_nr = le32_to_cpu(sb->dev_number);
@@ -1174,7 +1182,11 @@
 			set_bit(Faulty, &rdev->flags);
 			break;
 		default:
-			set_bit(In_sync, &rdev->flags);
+			if ((le32_to_cpu(sb->feature_map) &
+			     MD_FEATURE_RECOVERY_OFFSET))
+				rdev->recovery_offset = le64_to_cpu(sb->recovery_offset);
+			else
+				set_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = role;
 			break;
 		}
@@ -1198,6 +1210,7 @@
 
 	sb->feature_map = 0;
 	sb->pad0 = 0;
+	sb->recovery_offset = cpu_to_le64(0);
 	memset(sb->pad1, 0, sizeof(sb->pad1));
 	memset(sb->pad2, 0, sizeof(sb->pad2));
 	memset(sb->pad3, 0, sizeof(sb->pad3));
@@ -1218,6 +1231,14 @@
 		sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
 		sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
 	}
+
+	if (rdev->raid_disk >= 0 &&
+	    !test_bit(In_sync, &rdev->flags) &&
+	    rdev->recovery_offset > 0) {
+		sb->feature_map |= cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
+		sb->recovery_offset = cpu_to_le64(rdev->recovery_offset);
+	}
+
 	if (mddev->reshape_position != MaxSector) {
 		sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE);
 		sb->reshape_position = cpu_to_le64(mddev->reshape_position);
@@ -1242,11 +1263,12 @@
 			sb->dev_roles[i] = cpu_to_le16(0xfffe);
 		else if (test_bit(In_sync, &rdev2->flags))
 			sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
+		else if (rdev2->raid_disk >= 0 && rdev2->recovery_offset > 0)
+			sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
 		else
 			sb->dev_roles[i] = cpu_to_le16(0xffff);
 	}
 
-	sb->recovery_offset = cpu_to_le64(0); /* not supported yet */
 	sb->sb_csum = calc_sb_1_csum(sb);
 }
 
@@ -1507,7 +1529,7 @@
 		printk(KERN_INFO "md: no rdev superblock!\n");
 }
 
-void md_print_devices(void)
+static void md_print_devices(void)
 {
 	struct list_head *tmp, *tmp2;
 	mdk_rdev_t *rdev;
@@ -1536,15 +1558,30 @@
 }
 
 
-static void sync_sbs(mddev_t * mddev)
+static void sync_sbs(mddev_t * mddev, int nospares)
 {
+	/* Update each superblock (in-memory image), but
+	 * if we are allowed to, skip spares which already
+	 * have the right event counter, or have one earlier
+	 * (which would mean they aren't being marked as dirty
+	 * with the rest of the array)
+	 */
 	mdk_rdev_t *rdev;
 	struct list_head *tmp;
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		super_types[mddev->major_version].
-			sync_super(mddev, rdev);
-		rdev->sb_loaded = 1;
+		if (rdev->sb_events == mddev->events ||
+		    (nospares &&
+		     rdev->raid_disk < 0 &&
+		     (rdev->sb_events&1)==0 &&
+		     rdev->sb_events+1 == mddev->events)) {
+			/* Don't update this superblock */
+			rdev->sb_loaded = 2;
+		} else {
+			super_types[mddev->major_version].
+				sync_super(mddev, rdev);
+			rdev->sb_loaded = 1;
+		}
 	}
 }
 
@@ -1554,12 +1591,42 @@
 	struct list_head *tmp;
 	mdk_rdev_t *rdev;
 	int sync_req;
+	int nospares = 0;
 
 repeat:
 	spin_lock_irq(&mddev->write_lock);
 	sync_req = mddev->in_sync;
 	mddev->utime = get_seconds();
-	mddev->events ++;
+	if (mddev->sb_dirty == 3)
+		/* just a clean<-> dirty transition, possibly leave spares alone,
+		 * though if events isn't the right even/odd, we will have to do
+		 * spares after all
+		 */
+		nospares = 1;
+
+	/* If this is just a dirty<->clean transition, and the array is clean
+	 * and 'events' is odd, we can roll back to the previous clean state */
+	if (mddev->sb_dirty == 3
+	    && (mddev->in_sync && mddev->recovery_cp == MaxSector)
+	    && (mddev->events & 1))
+		mddev->events--;
+	else {
+		/* otherwise we have to go forward and ... */
+		mddev->events ++;
+		if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */
+			/* .. if the array isn't clean, insist on an odd 'events' */
+			if ((mddev->events&1)==0) {
+				mddev->events++;
+				nospares = 0;
+			}
+		} else {
+			/* otherwise insist on an even 'events' (for clean states) */
+			if ((mddev->events&1)) {
+				mddev->events++;
+				nospares = 0;
+			}
+		}
+	}
 
 	if (!mddev->events) {
 		/*
@@ -1571,7 +1638,7 @@
 		mddev->events --;
 	}
 	mddev->sb_dirty = 2;
-	sync_sbs(mddev);
+	sync_sbs(mddev, nospares);
 
 	/*
 	 * do not write anything to disk if using
@@ -1593,6 +1660,8 @@
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		char b[BDEVNAME_SIZE];
 		dprintk(KERN_INFO "md: ");
+		if (rdev->sb_loaded != 1)
+			continue; /* no noise on spare devices */
 		if (test_bit(Faulty, &rdev->flags))
 			dprintk("(skipping faulty ");
 
@@ -1604,6 +1673,7 @@
 			dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
 				bdevname(rdev->bdev,b),
 				(unsigned long long)rdev->sb_offset);
+			rdev->sb_events = mddev->events;
 
 		} else
 			dprintk(")\n");
@@ -1667,6 +1737,10 @@
 		len += sprintf(page+len, "%sin_sync",sep);
 		sep = ",";
 	}
+	if (test_bit(WriteMostly, &rdev->flags)) {
+		len += sprintf(page+len, "%swrite_mostly",sep);
+		sep = ",";
+	}
 	if (!test_bit(Faulty, &rdev->flags) &&
 	    !test_bit(In_sync, &rdev->flags)) {
 		len += sprintf(page+len, "%sspare", sep);
@@ -1675,8 +1749,40 @@
 	return len+sprintf(page+len, "\n");
 }
 
+static ssize_t
+state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
+{
+	/* can write
+	 *  faulty  - simulates and error
+	 *  remove  - disconnects the device
+	 *  writemostly - sets write_mostly
+	 *  -writemostly - clears write_mostly
+	 */
+	int err = -EINVAL;
+	if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
+		md_error(rdev->mddev, rdev);
+		err = 0;
+	} else if (cmd_match(buf, "remove")) {
+		if (rdev->raid_disk >= 0)
+			err = -EBUSY;
+		else {
+			mddev_t *mddev = rdev->mddev;
+			kick_rdev_from_array(rdev);
+			md_update_sb(mddev);
+			md_new_event(mddev);
+			err = 0;
+		}
+	} else if (cmd_match(buf, "writemostly")) {
+		set_bit(WriteMostly, &rdev->flags);
+		err = 0;
+	} else if (cmd_match(buf, "-writemostly")) {
+		clear_bit(WriteMostly, &rdev->flags);
+		err = 0;
+	}
+	return err ? err : len;
+}
 static struct rdev_sysfs_entry
-rdev_state = __ATTR_RO(state);
+rdev_state = __ATTR(state, 0644, state_show, state_store);
 
 static ssize_t
 super_show(mdk_rdev_t *rdev, char *page)
@@ -1873,6 +1979,7 @@
 	rdev->desc_nr = -1;
 	rdev->flags = 0;
 	rdev->data_offset = 0;
+	rdev->sb_events = 0;
 	atomic_set(&rdev->nr_pending, 0);
 	atomic_set(&rdev->read_errors, 0);
 	atomic_set(&rdev->corrected_errors, 0);
@@ -1978,6 +2085,54 @@
 }
 
 static ssize_t
+safe_delay_show(mddev_t *mddev, char *page)
+{
+	int msec = (mddev->safemode_delay*1000)/HZ;
+	return sprintf(page, "%d.%03d\n", msec/1000, msec%1000);
+}
+static ssize_t
+safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len)
+{
+	int scale=1;
+	int dot=0;
+	int i;
+	unsigned long msec;
+	char buf[30];
+	char *e;
+	/* remove a period, and count digits after it */
+	if (len >= sizeof(buf))
+		return -EINVAL;
+	strlcpy(buf, cbuf, len);
+	buf[len] = 0;
+	for (i=0; i<len; i++) {
+		if (dot) {
+			if (isdigit(buf[i])) {
+				buf[i-1] = buf[i];
+				scale *= 10;
+			}
+			buf[i] = 0;
+		} else if (buf[i] == '.') {
+			dot=1;
+			buf[i] = 0;
+		}
+	}
+	msec = simple_strtoul(buf, &e, 10);
+	if (e == buf || (*e && *e != '\n'))
+		return -EINVAL;
+	msec = (msec * 1000) / scale;
+	if (msec == 0)
+		mddev->safemode_delay = 0;
+	else {
+		mddev->safemode_delay = (msec*HZ)/1000;
+		if (mddev->safemode_delay == 0)
+			mddev->safemode_delay = 1;
+	}
+	return len;
+}
+static struct md_sysfs_entry md_safe_delay =
+__ATTR(safe_mode_delay, 0644,safe_delay_show, safe_delay_store);
+
+static ssize_t
 level_show(mddev_t *mddev, char *page)
 {
 	struct mdk_personality *p = mddev->pers;
@@ -2012,6 +2167,32 @@
 static struct md_sysfs_entry md_level =
 __ATTR(level, 0644, level_show, level_store);
 
+
+static ssize_t
+layout_show(mddev_t *mddev, char *page)
+{
+	/* just a number, not meaningful for all levels */
+	return sprintf(page, "%d\n", mddev->layout);
+}
+
+static ssize_t
+layout_store(mddev_t *mddev, const char *buf, size_t len)
+{
+	char *e;
+	unsigned long n = simple_strtoul(buf, &e, 10);
+	if (mddev->pers)
+		return -EBUSY;
+
+	if (!*buf || (*e && *e != '\n'))
+		return -EINVAL;
+
+	mddev->layout = n;
+	return len;
+}
+static struct md_sysfs_entry md_layout =
+__ATTR(layout, 0655, layout_show, layout_store);
+
+
 static ssize_t
 raid_disks_show(mddev_t *mddev, char *page)
 {
@@ -2067,6 +2248,200 @@
 __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store);
 
 static ssize_t
+resync_start_show(mddev_t *mddev, char *page)
+{
+	return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp);
+}
+
+static ssize_t
+resync_start_store(mddev_t *mddev, const char *buf, size_t len)
+{
+	/* can only set chunk_size if array is not yet active */
+	char *e;
+	unsigned long long n = simple_strtoull(buf, &e, 10);
+
+	if (mddev->pers)
+		return -EBUSY;
+	if (!*buf || (*e && *e != '\n'))
+		return -EINVAL;
+
+	mddev->recovery_cp = n;
+	return len;
+}
+static struct md_sysfs_entry md_resync_start =
+__ATTR(resync_start, 0644, resync_start_show, resync_start_store);
+
+/*
+ * The array state can be:
+ *
+ * clear
+ *     No devices, no size, no level
+ *     Equivalent to STOP_ARRAY ioctl
+ * inactive
+ *     May have some settings, but array is not active
+ *        all IO results in error
+ *     When written, doesn't tear down array, but just stops it
+ * suspended (not supported yet)
+ *     All IO requests will block. The array can be reconfigured.
+ *     Writing this, if accepted, will block until array is quiessent
+ * readonly
+ *     no resync can happen.  no superblocks get written.
+ *     write requests fail
+ * read-auto
+ *     like readonly, but behaves like 'clean' on a write request.
+ *
+ * clean - no pending writes, but otherwise active.
+ *     When written to inactive array, starts without resync
+ *     If a write request arrives then
+ *       if metadata is known, mark 'dirty' and switch to 'active'.
+ *       if not known, block and switch to write-pending
+ *     If written to an active array that has pending writes, then fails.
+ * active
+ *     fully active: IO and resync can be happening.
+ *     When written to inactive array, starts with resync
+ *
+ * write-pending
+ *     clean, but writes are blocked waiting for 'active' to be written.
+ *
+ * active-idle
+ *     like active, but no writes have been seen for a while (100msec).
+ *
+ */
+enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active,
+		   write_pending, active_idle, bad_word};
+static char *array_states[] = {
+	"clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active",
+	"write-pending", "active-idle", NULL };
+
+static int match_word(const char *word, char **list)
+{
+	int n;
+	for (n=0; list[n]; n++)
+		if (cmd_match(word, list[n]))
+			break;
+	return n;
+}
+
+static ssize_t
+array_state_show(mddev_t *mddev, char *page)
+{
+	enum array_state st = inactive;
+
+	if (mddev->pers)
+		switch(mddev->ro) {
+		case 1:
+			st = readonly;
+			break;
+		case 2:
+			st = read_auto;
+			break;
+		case 0:
+			if (mddev->in_sync)
+				st = clean;
+			else if (mddev->safemode)
+				st = active_idle;
+			else
+				st = active;
+		}
+	else {
+		if (list_empty(&mddev->disks) &&
+		    mddev->raid_disks == 0 &&
+		    mddev->size == 0)
+			st = clear;
+		else
+			st = inactive;
+	}
+	return sprintf(page, "%s\n", array_states[st]);
+}
+
+static int do_md_stop(mddev_t * mddev, int ro);
+static int do_md_run(mddev_t * mddev);
+static int restart_array(mddev_t *mddev);
+
+static ssize_t
+array_state_store(mddev_t *mddev, const char *buf, size_t len)
+{
+	int err = -EINVAL;
+	enum array_state st = match_word(buf, array_states);
+	switch(st) {
+	case bad_word:
+		break;
+	case clear:
+		/* stopping an active array */
+		if (mddev->pers) {
+			if (atomic_read(&mddev->active) > 1)
+				return -EBUSY;
+			err = do_md_stop(mddev, 0);
+		}
+		break;
+	case inactive:
+		/* stopping an active array */
+		if (mddev->pers) {
+			if (atomic_read(&mddev->active) > 1)
+				return -EBUSY;
+			err = do_md_stop(mddev, 2);
+		}
+		break;
+	case suspended:
+		break; /* not supported yet */
+	case readonly:
+		if (mddev->pers)
+			err = do_md_stop(mddev, 1);
+		else {
+			mddev->ro = 1;
+			err = do_md_run(mddev);
+		}
+		break;
+	case read_auto:
+		/* stopping an active array */
+		if (mddev->pers) {
+			err = do_md_stop(mddev, 1);
+			if (err == 0)
+				mddev->ro = 2; /* FIXME mark devices writable */
+		} else {
+			mddev->ro = 2;
+			err = do_md_run(mddev);
+		}
+		break;
+	case clean:
+		if (mddev->pers) {
+			restart_array(mddev);
+			spin_lock_irq(&mddev->write_lock);
+			if (atomic_read(&mddev->writes_pending) == 0) {
+				mddev->in_sync = 1;
+				mddev->sb_dirty = 1;
+			}
+			spin_unlock_irq(&mddev->write_lock);
+		} else {
+			mddev->ro = 0;
+			mddev->recovery_cp = MaxSector;
+			err = do_md_run(mddev);
+		}
+		break;
+	case active:
+		if (mddev->pers) {
+			restart_array(mddev);
+			mddev->sb_dirty = 0;
+			wake_up(&mddev->sb_wait);
+			err = 0;
+		} else {
+			mddev->ro = 0;
+			err = do_md_run(mddev);
+		}
+		break;
+	case write_pending:
+	case active_idle:
+		/* these cannot be set */
+		break;
+	}
+	if (err)
+		return err;
+	else
+		return len;
+}
+static struct md_sysfs_entry md_array_state = __ATTR(array_state, 0644, array_state_show, array_state_store);
+
+static ssize_t
 null_show(mddev_t *mddev, char *page)
 {
 	return -EINVAL;
@@ -2428,11 +2803,15 @@
 
 static struct attribute *md_default_attrs[] = {
 	&md_level.attr,
+	&md_layout.attr,
 	&md_raid_disks.attr,
 	&md_chunk_size.attr,
 	&md_size.attr,
+	&md_resync_start.attr,
 	&md_metadata.attr,
 	&md_new_device.attr,
+	&md_safe_delay.attr,
+	&md_array_state.attr,
 	NULL,
 };
 
@@ -2553,8 +2932,6 @@
 	return NULL;
 }
 
-void md_wakeup_thread(mdk_thread_t *thread);
-
 static void md_safemode_timeout(unsigned long data)
 {
 	mddev_t *mddev = (mddev_t *) data;
@@ -2708,7 +3085,7 @@
 	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->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
 	mddev->in_sync = 1;
 
 	ITERATE_RDEV(mddev,rdev,tmp)
@@ -2736,6 +3113,36 @@
 	mddev->queue->queuedata = mddev;
 	mddev->queue->make_request_fn = mddev->pers->make_request;
 
+	/* If there is a partially-recovered drive we need to
+	 * start recovery here.  If we leave it to md_check_recovery,
+	 * it will remove the drives and not do the right thing
+	 */
+	if (mddev->degraded) {
+		struct list_head *rtmp;
+		int spares = 0;
+		ITERATE_RDEV(mddev,rdev,rtmp)
+			if (rdev->raid_disk >= 0 &&
+			    !test_bit(In_sync, &rdev->flags) &&
+			    !test_bit(Faulty, &rdev->flags))
+				/* complete an interrupted recovery */
+				spares++;
+		if (spares && mddev->pers->sync_request) {
+			mddev->recovery = 0;
+			set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+			mddev->sync_thread = md_register_thread(md_do_sync,
+								mddev,
+								"%s_resync");
+			if (!mddev->sync_thread) {
+				printk(KERN_ERR "%s: could not start resync"
+				       " thread...\n",
+				       mdname(mddev));
+				/* leave the spares where they are, it shouldn't hurt */
+				mddev->recovery = 0;
+			} else
+				md_wakeup_thread(mddev->sync_thread);
+		}
+	}
+
 	mddev->changed = 1;
 	md_new_event(mddev);
 	return 0;
@@ -2769,18 +3176,47 @@
 		 */
 		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 		md_wakeup_thread(mddev->thread);
+		md_wakeup_thread(mddev->sync_thread);
 		err = 0;
-	} else {
-		printk(KERN_ERR "md: %s has no personality assigned.\n",
-			mdname(mddev));
+	} else
 		err = -EINVAL;
-	}
 
 out:
 	return err;
 }
 
-static int do_md_stop(mddev_t * mddev, int ro)
+/* similar to deny_write_access, but accounts for our holding a reference
+ * to the file ourselves */
+static int deny_bitmap_write_access(struct file * file)
+{
+	struct inode *inode = file->f_mapping->host;
+
+	spin_lock(&inode->i_lock);
+	if (atomic_read(&inode->i_writecount) > 1) {
+		spin_unlock(&inode->i_lock);
+		return -ETXTBSY;
+	}
+	atomic_set(&inode->i_writecount, -1);
+	spin_unlock(&inode->i_lock);
+
+	return 0;
+}
+
+static void restore_bitmap_write_access(struct file *file)
+{
+	struct inode *inode = file->f_mapping->host;
+
+	spin_lock(&inode->i_lock);
+	atomic_set(&inode->i_writecount, 1);
+	spin_unlock(&inode->i_lock);
+}
+
+/* mode:
+ *   0 - completely stop and dis-assemble array
+ *   1 - switch to readonly
+ *   2 - stop but do not disassemble array
+ */
+static int do_md_stop(mddev_t * mddev, int mode)
 {
 	int err = 0;
 	struct gendisk *disk = mddev->gendisk;
@@ -2792,6 +3228,7 @@
 		}
 
 		if (mddev->sync_thread) {
+			set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 			md_unregister_thread(mddev->sync_thread);
 			mddev->sync_thread = NULL;
@@ -2801,12 +3238,15 @@
 
 		invalidate_partition(disk, 0);
 
-		if (ro) {
+		switch(mode) {
+		case 1: /* readonly */
 			err  = -ENXIO;
 			if (mddev->ro==1)
 				goto out;
 			mddev->ro = 1;
-		} else {
+			break;
+		case 0: /* disassemble */
+		case 2: /* stop */
 			bitmap_flush(mddev);
 			md_super_wait(mddev);
 			if (mddev->ro)
@@ -2821,19 +3261,20 @@
 			if (mddev->ro)
 				mddev->ro = 0;
 		}
-		if (!mddev->in_sync) {
+		if (!mddev->in_sync || mddev->sb_dirty) {
 			/* mark array as shutdown cleanly */
 			mddev->in_sync = 1;
 			md_update_sb(mddev);
 		}
-		if (ro)
+		if (mode == 1)
 			set_disk_ro(disk, 1);
+		clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 	}
 
 	/*
 	 * Free resources if final stop
 	 */
-	if (!ro) {
+	if (mode == 0) {
 		mdk_rdev_t *rdev;
 		struct list_head *tmp;
 		struct gendisk *disk;
@@ -2841,7 +3282,7 @@
 
 		bitmap_destroy(mddev);
 		if (mddev->bitmap_file) {
-			atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
+			restore_bitmap_write_access(mddev->bitmap_file);
 			fput(mddev->bitmap_file);
 			mddev->bitmap_file = NULL;
 		}
@@ -2857,11 +3298,15 @@
 		export_array(mddev);
 
 		mddev->array_size = 0;
+		mddev->size = 0;
+		mddev->raid_disks = 0;
+		mddev->recovery_cp = 0;
+
 		disk = mddev->gendisk;
 		if (disk)
 			set_capacity(disk, 0);
 		mddev->changed = 1;
-	} else
+	} else if (mddev->pers)
 		printk(KERN_INFO "md: %s switched to read-only mode.\n",
 			mdname(mddev));
 	err = 0;
@@ -3264,6 +3709,17 @@
 
 		rdev->raid_disk = -1;
 		err = bind_rdev_to_array(rdev, mddev);
+		if (!err && !mddev->pers->hot_remove_disk) {
+			/* If there is hot_add_disk but no hot_remove_disk
+			 * then added disks for geometry changes,
+			 * and should be added immediately.
+			 */
+			super_types[mddev->major_version].
+				validate_super(mddev, rdev);
+			err = mddev->pers->hot_add_disk(mddev, rdev);
+			if (err)
+				unbind_rdev_from_array(rdev);
+		}
 		if (err)
 			export_rdev(rdev);
 
@@ -3434,23 +3890,6 @@
 	return err;
 }
 
-/* similar to deny_write_access, but accounts for our holding a reference
- * to the file ourselves */
-static int deny_bitmap_write_access(struct file * file)
-{
-	struct inode *inode = file->f_mapping->host;
-
-	spin_lock(&inode->i_lock);
-	if (atomic_read(&inode->i_writecount) > 1) {
-		spin_unlock(&inode->i_lock);
-		return -ETXTBSY;
-	}
-	atomic_set(&inode->i_writecount, -1);
-	spin_unlock(&inode->i_lock);
-
-	return 0;
-}
-
 static int set_bitmap_file(mddev_t *mddev, int fd)
 {
 	int err;
@@ -3491,12 +3930,17 @@
 		mddev->pers->quiesce(mddev, 1);
 		if (fd >= 0)
 			err = bitmap_create(mddev);
-		if (fd < 0 || err)
+		if (fd < 0 || err) {
 			bitmap_destroy(mddev);
+			fd = -1; /* make sure to put the file */
+		}
 		mddev->pers->quiesce(mddev, 0);
-	} else if (fd < 0) {
-		if (mddev->bitmap_file)
+	}
+	if (fd < 0) {
+		if (mddev->bitmap_file) {
+			restore_bitmap_write_access(mddev->bitmap_file);
 			fput(mddev->bitmap_file);
+		}
 		mddev->bitmap_file = NULL;
 	}
 
@@ -3977,11 +4421,6 @@
 			goto done_unlock;
 
 		default:
-			if (_IOC_TYPE(cmd) == MD_MAJOR)
-				printk(KERN_WARNING "md: %s(pid %d) used"
-					" obsolete MD ioctl, upgrade your"
-					" software to use new ictls.\n",
-					current->comm, current->pid);
 			err = -EINVAL;
 			goto abort_unlock;
 	}
@@ -4586,7 +5025,7 @@
 		spin_lock_irq(&mddev->write_lock);
 		if (mddev->in_sync) {
 			mddev->in_sync = 0;
-			mddev->sb_dirty = 1;
+			mddev->sb_dirty = 3;
 			md_wakeup_thread(mddev->thread);
 		}
 		spin_unlock_irq(&mddev->write_lock);
@@ -4599,7 +5038,7 @@
 	if (atomic_dec_and_test(&mddev->writes_pending)) {
 		if (mddev->safemode == 2)
 			md_wakeup_thread(mddev->thread);
-		else
+		else if (mddev->safemode_delay)
 			mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay);
 	}
 }
@@ -4620,10 +5059,14 @@
 	struct list_head *tmp;
 	sector_t last_check;
 	int skipped = 0;
+	struct list_head *rtmp;
+	mdk_rdev_t *rdev;
 
 	/* just incase thread restarts... */
 	if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
 		return;
+	if (mddev->ro) /* never try to sync a read-only array */
+		return;
 
 	/* we overload curr_resync somewhat here.
 	 * 0 == not engaged in resync at all
@@ -4682,17 +5125,30 @@
 		}
 	} while (mddev->curr_resync < 2);
 
+	j = 0;
 	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;
 		mddev->resync_mismatches = 0;
+		/* we don't use the checkpoint if there's a bitmap */
+		if (!mddev->bitmap &&
+		    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+			j = mddev->recovery_cp;
 	} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
 		max_sectors = mddev->size << 1;
-	else
+	else {
 		/* recovery follows the physical size of devices */
 		max_sectors = mddev->size << 1;
+		j = MaxSector;
+		ITERATE_RDEV(mddev,rdev,rtmp)
+			if (rdev->raid_disk >= 0 &&
+			    !test_bit(Faulty, &rdev->flags) &&
+			    !test_bit(In_sync, &rdev->flags) &&
+			    rdev->recovery_offset < j)
+				j = rdev->recovery_offset;
+	}
 
 	printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
 	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
@@ -4702,12 +5158,7 @@
 	       speed_max(mddev));
 
 	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
-	    && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
-		j = mddev->recovery_cp;
-	else
-		j = 0;
+
 	io_sectors = 0;
 	for (m = 0; m < SYNC_MARKS; m++) {
 		mark[m] = jiffies;
@@ -4828,15 +5279,28 @@
 	if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
 	    test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
 	    !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
-	    mddev->curr_resync > 2 &&
-	    mddev->curr_resync >= mddev->recovery_cp) {
-		if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
-			printk(KERN_INFO 
-				"md: checkpointing recovery of %s.\n",
-				mdname(mddev));
-			mddev->recovery_cp = mddev->curr_resync;
-		} else
-			mddev->recovery_cp = MaxSector;
+	    mddev->curr_resync > 2) {
+		if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+			if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+				if (mddev->curr_resync >= mddev->recovery_cp) {
+					printk(KERN_INFO
+					       "md: checkpointing recovery of %s.\n",
+					       mdname(mddev));
+					mddev->recovery_cp = mddev->curr_resync;
+				}
+			} else
+				mddev->recovery_cp = MaxSector;
+		} else {
+			if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+				mddev->curr_resync = MaxSector;
+			ITERATE_RDEV(mddev,rdev,rtmp)
+				if (rdev->raid_disk >= 0 &&
+				    !test_bit(Faulty, &rdev->flags) &&
+				    !test_bit(In_sync, &rdev->flags) &&
+				    rdev->recovery_offset < mddev->curr_resync)
+					rdev->recovery_offset = mddev->curr_resync;
+			mddev->sb_dirty = 1;
+		}
 	}
 
  skip:
@@ -4908,7 +5372,7 @@
 		if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
 		    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
 			mddev->in_sync = 1;
-			mddev->sb_dirty = 1;
+			mddev->sb_dirty = 3;
 		}
 		if (mddev->safemode == 1)
 			mddev->safemode = 0;
@@ -4957,6 +5421,8 @@
 		clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
 		clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
 
+		if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
+			goto unlock;
 		/* no recovery is running.
 		 * remove any failed drives, then
 		 * add spares if possible.
@@ -4979,6 +5445,7 @@
 			ITERATE_RDEV(mddev,rdev,rtmp)
 				if (rdev->raid_disk < 0
 				    && !test_bit(Faulty, &rdev->flags)) {
+					rdev->recovery_offset = 0;
 					if (mddev->pers->hot_add_disk(mddev,rdev)) {
 						char nm[20];
 						sprintf(nm, "rd%d", rdev->raid_disk);
@@ -5216,7 +5683,6 @@
 EXPORT_SYMBOL(md_register_thread);
 EXPORT_SYMBOL(md_unregister_thread);
 EXPORT_SYMBOL(md_wakeup_thread);
-EXPORT_SYMBOL(md_print_devices);
 EXPORT_SYMBOL(md_check_recovery);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("md");
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 4070eff..cead918 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -374,26 +374,26 @@
 	 * already.
 	 */
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
-		if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+		if (test_bit(R1BIO_BarrierRetry, &r1_bio->state))
 			reschedule_retry(r1_bio);
-			goto out;
+		else {
+			/* it really is the end of this request */
+			if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
+				/* free extra copy of the data pages */
+				int i = bio->bi_vcnt;
+				while (i--)
+					safe_put_page(bio->bi_io_vec[i].bv_page);
+			}
+			/* clear the bitmap if all writes complete successfully */
+			bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
+					r1_bio->sectors,
+					!test_bit(R1BIO_Degraded, &r1_bio->state),
+					behind);
+			md_write_end(r1_bio->mddev);
+			raid_end_bio_io(r1_bio);
 		}
-		/* it really is the end of this request */
-		if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
-			/* free extra copy of the data pages */
-			int i = bio->bi_vcnt;
-			while (i--)
-				safe_put_page(bio->bi_io_vec[i].bv_page);
-		}
-		/* clear the bitmap if all writes complete successfully */
-		bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
-				r1_bio->sectors,
-				!test_bit(R1BIO_Degraded, &r1_bio->state),
-				behind);
-		md_write_end(r1_bio->mddev);
-		raid_end_bio_io(r1_bio);
 	}
- out:
+
 	if (to_put)
 		bio_put(to_put);
 
@@ -1625,6 +1625,12 @@
 	/* before building a request, check if we can skip these blocks..
 	 * This call the bitmap_start_sync doesn't actually record anything
 	 */
+	if (mddev->bitmap == NULL &&
+	    mddev->recovery_cp == MaxSector &&
+	    conf->fullsync == 0) {
+		*skipped = 1;
+		return max_sector - sector_nr;
+	}
 	if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
 	    !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
 		/* We can skip this block, and probably several more */
@@ -1888,7 +1894,8 @@
 
 		disk = conf->mirrors + i;
 
-		if (!disk->rdev) {
+		if (!disk->rdev ||
+		    !test_bit(In_sync, &disk->rdev->flags)) {
 			disk->head_position = 0;
 			mddev->degraded++;
 		}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1440935..7f63628 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -29,6 +29,7 @@
  *    raid_disks
  *    near_copies (stored in low byte of layout)
  *    far_copies (stored in second byte of layout)
+ *    far_offset (stored in bit 16 of layout )
  *
  * The data to be stored is divided into chunks using chunksize.
  * Each device is divided into far_copies sections.
@@ -36,10 +37,14 @@
  * near_copies copies of each chunk is stored (each on a different drive).
  * The starting device for each section is offset near_copies from the starting
  * device of the previous section.
- * Thus there are (near_copies*far_copies) of each chunk, and each is on a different
+ * Thus they are (near_copies*far_copies) of each chunk, and each is on a different
  * drive.
  * near_copies and far_copies must be at least one, and their product is at most
  * raid_disks.
+ *
+ * If far_offset is true, then the far_copies are handled a bit differently.
+ * The copies are still in different stripes, but instead of be very far apart
+ * on disk, there are adjacent stripes.
  */
 
 /*
@@ -357,8 +362,7 @@
  * With this layout, and block is never stored twice on the one device.
  *
  * raid10_find_phys finds the sector offset of a given virtual sector
- * on each device that it is on. If a block isn't on a device,
- * that entry in the array is set to MaxSector.
+ * on each device that it is on.
  *
  * raid10_find_virt does the reverse mapping, from a device and a
  * sector offset to a virtual address
@@ -381,6 +385,8 @@
 	chunk *= conf->near_copies;
 	stripe = chunk;
 	dev = sector_div(stripe, conf->raid_disks);
+	if (conf->far_offset)
+		stripe *= conf->far_copies;
 
 	sector += stripe << conf->chunk_shift;
 
@@ -414,16 +420,24 @@
 {
 	sector_t offset, chunk, vchunk;
 
-	while (sector > conf->stride) {
-		sector -= conf->stride;
-		if (dev < conf->near_copies)
-			dev += conf->raid_disks - conf->near_copies;
-		else
-			dev -= conf->near_copies;
-	}
-
 	offset = sector & conf->chunk_mask;
-	chunk = sector >> conf->chunk_shift;
+	if (conf->far_offset) {
+		int fc;
+		chunk = sector >> conf->chunk_shift;
+		fc = sector_div(chunk, conf->far_copies);
+		dev -= fc * conf->near_copies;
+		if (dev < 0)
+			dev += conf->raid_disks;
+	} else {
+		while (sector > conf->stride) {
+			sector -= conf->stride;
+			if (dev < conf->near_copies)
+				dev += conf->raid_disks - conf->near_copies;
+			else
+				dev -= conf->near_copies;
+		}
+		chunk = sector >> conf->chunk_shift;
+	}
 	vchunk = chunk * conf->raid_disks + dev;
 	sector_div(vchunk, conf->near_copies);
 	return (vchunk << conf->chunk_shift) + offset;
@@ -900,9 +914,12 @@
 		seq_printf(seq, " %dK chunks", mddev->chunk_size/1024);
 	if (conf->near_copies > 1)
 		seq_printf(seq, " %d near-copies", conf->near_copies);
-	if (conf->far_copies > 1)
-		seq_printf(seq, " %d far-copies", conf->far_copies);
-
+	if (conf->far_copies > 1) {
+		if (conf->far_offset)
+			seq_printf(seq, " %d offset-copies", conf->far_copies);
+		else
+			seq_printf(seq, " %d far-copies", conf->far_copies);
+	}
 	seq_printf(seq, " [%d/%d] [", conf->raid_disks,
 						conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
@@ -1915,7 +1932,7 @@
 	mirror_info_t *disk;
 	mdk_rdev_t *rdev;
 	struct list_head *tmp;
-	int nc, fc;
+	int nc, fc, fo;
 	sector_t stride, size;
 
 	if (mddev->chunk_size == 0) {
@@ -1925,8 +1942,9 @@
 
 	nc = mddev->layout & 255;
 	fc = (mddev->layout >> 8) & 255;
+	fo = mddev->layout & (1<<16);
 	if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
-	    (mddev->layout >> 16)) {
+	    (mddev->layout >> 17)) {
 		printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n",
 		       mdname(mddev), mddev->layout);
 		goto out;
@@ -1958,12 +1976,16 @@
 	conf->near_copies = nc;
 	conf->far_copies = fc;
 	conf->copies = nc*fc;
+	conf->far_offset = fo;
 	conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
 	conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
-	stride = mddev->size >> (conf->chunk_shift-1);
-	sector_div(stride, fc);
-	conf->stride = stride << conf->chunk_shift;
-
+	if (fo)
+		conf->stride = 1 << conf->chunk_shift;
+	else {
+		stride = mddev->size >> (conf->chunk_shift-1);
+		sector_div(stride, fc);
+		conf->stride = stride << conf->chunk_shift;
+	}
 	conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
 						r10bio_pool_free, conf);
 	if (!conf->r10bio_pool) {
@@ -2015,7 +2037,8 @@
 
 		disk = conf->mirrors + i;
 
-		if (!disk->rdev) {
+		if (!disk->rdev ||
+		    !test_bit(In_sync, &rdev->flags)) {
 			disk->head_position = 0;
 			mddev->degraded++;
 		}
@@ -2037,7 +2060,13 @@
 	/*
 	 * Ok, everything is just fine now
 	 */
-	size = conf->stride * conf->raid_disks;
+	if (conf->far_offset) {
+		size = mddev->size >> (conf->chunk_shift-1);
+		size *= conf->raid_disks;
+		size <<= conf->chunk_shift;
+		sector_div(size, conf->far_copies);
+	} else
+		size = conf->stride * conf->raid_disks;
 	sector_div(size, conf->near_copies);
 	mddev->array_size = size/2;
 	mddev->resync_max_sectors = size;
@@ -2050,7 +2079,7 @@
 	 * maybe...
 	 */
 	{
-		int stripe = conf->raid_disks * mddev->chunk_size / PAGE_SIZE;
+		int stripe = conf->raid_disks * (mddev->chunk_size / PAGE_SIZE);
 		stripe /= conf->near_copies;
 		if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
 			mddev->queue->backing_dev_info.ra_pages = 2* stripe;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 3184360..f920e50 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2,8 +2,11 @@
  * raid5.c : Multiple Devices driver for Linux
  *	   Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman
  *	   Copyright (C) 1999, 2000 Ingo Molnar
+ *	   Copyright (C) 2002, 2003 H. Peter Anvin
  *
- * RAID-5 management functions.
+ * RAID-4/5/6 management functions.
+ * Thanks to Penguin Computing for making the RAID-6 development possible
+ * by donating a test server!
  *
  * 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
@@ -19,11 +22,11 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/raid/raid5.h>
 #include <linux/highmem.h>
 #include <linux/bitops.h>
 #include <linux/kthread.h>
 #include <asm/atomic.h>
+#include "raid6.h"
 
 #include <linux/raid/bitmap.h>
 
@@ -68,6 +71,16 @@
 #define __inline__
 #endif
 
+#if !RAID6_USE_EMPTY_ZERO_PAGE
+/* In .bss so it's zeroed */
+const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
+#endif
+
+static inline int raid6_next_disk(int disk, int raid_disks)
+{
+	disk++;
+	return (disk < raid_disks) ? disk : 0;
+}
 static void print_raid5_conf (raid5_conf_t *conf);
 
 static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
@@ -104,7 +117,7 @@
 {
 	raid5_conf_t *conf = sh->raid_conf;
 	unsigned long flags;
-	
+
 	spin_lock_irqsave(&conf->device_lock, flags);
 	__release_stripe(conf, sh);
 	spin_unlock_irqrestore(&conf->device_lock, flags);
@@ -117,7 +130,7 @@
 	hlist_del_init(&sh->hash);
 }
 
-static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
+static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
 {
 	struct hlist_head *hp = stripe_hash(conf, sh->sector);
 
@@ -190,7 +203,7 @@
 		(unsigned long long)sh->sector);
 
 	remove_hash(sh);
-	
+
 	sh->sector = sector;
 	sh->pd_idx = pd_idx;
 	sh->state = 0;
@@ -269,8 +282,9 @@
 			} else {
 				if (!test_bit(STRIPE_HANDLE, &sh->state))
 					atomic_inc(&conf->active_stripes);
-				if (!list_empty(&sh->lru))
-					list_del_init(&sh->lru);
+				if (list_empty(&sh->lru))
+					BUG();
+				list_del_init(&sh->lru);
 			}
 		}
 	} while (sh == NULL);
@@ -321,10 +335,9 @@
 		return 1;
 	conf->slab_cache = sc;
 	conf->pool_size = devs;
-	while (num--) {
+	while (num--)
 		if (!grow_one_stripe(conf))
 			return 1;
-	}
 	return 0;
 }
 
@@ -631,8 +644,7 @@
 	dev->req.bi_private = sh;
 
 	dev->flags = 0;
-	if (i != sh->pd_idx)
-		dev->sector = compute_blocknr(sh, i);
+	dev->sector = compute_blocknr(sh, i);
 }
 
 static void error(mddev_t *mddev, mdk_rdev_t *rdev)
@@ -659,7 +671,7 @@
 			" Operation continuing on %d devices\n",
 			bdevname(rdev->bdev,b), conf->working_disks);
 	}
-}	
+}
 
 /*
  * Input: a 'big' sector number,
@@ -697,9 +709,12 @@
 	/*
 	 * Select the parity disk based on the user selected algorithm.
 	 */
-	if (conf->level == 4)
+	switch(conf->level) {
+	case 4:
 		*pd_idx = data_disks;
-	else switch (conf->algorithm) {
+		break;
+	case 5:
+		switch (conf->algorithm) {
 		case ALGORITHM_LEFT_ASYMMETRIC:
 			*pd_idx = data_disks - stripe % raid_disks;
 			if (*dd_idx >= *pd_idx)
@@ -721,6 +736,39 @@
 		default:
 			printk(KERN_ERR "raid5: unsupported algorithm %d\n",
 				conf->algorithm);
+		}
+		break;
+	case 6:
+
+		/**** FIX THIS ****/
+		switch (conf->algorithm) {
+		case ALGORITHM_LEFT_ASYMMETRIC:
+			*pd_idx = raid_disks - 1 - (stripe % raid_disks);
+			if (*pd_idx == raid_disks-1)
+				(*dd_idx)++; 	/* Q D D D P */
+			else if (*dd_idx >= *pd_idx)
+				(*dd_idx) += 2; /* D D P Q D */
+			break;
+		case ALGORITHM_RIGHT_ASYMMETRIC:
+			*pd_idx = stripe % raid_disks;
+			if (*pd_idx == raid_disks-1)
+				(*dd_idx)++; 	/* Q D D D P */
+			else if (*dd_idx >= *pd_idx)
+				(*dd_idx) += 2; /* D D P Q D */
+			break;
+		case ALGORITHM_LEFT_SYMMETRIC:
+			*pd_idx = raid_disks - 1 - (stripe % raid_disks);
+			*dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
+			break;
+		case ALGORITHM_RIGHT_SYMMETRIC:
+			*pd_idx = stripe % raid_disks;
+			*dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
+			break;
+		default:
+			printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
+				conf->algorithm);
+		}
+		break;
 	}
 
 	/*
@@ -742,12 +790,17 @@
 	int chunk_number, dummy1, dummy2, dd_idx = i;
 	sector_t r_sector;
 
+
 	chunk_offset = sector_div(new_sector, sectors_per_chunk);
 	stripe = new_sector;
 	BUG_ON(new_sector != stripe);
 
-	
-	switch (conf->algorithm) {
+	if (i == sh->pd_idx)
+		return 0;
+	switch(conf->level) {
+	case 4: break;
+	case 5:
+		switch (conf->algorithm) {
 		case ALGORITHM_LEFT_ASYMMETRIC:
 		case ALGORITHM_RIGHT_ASYMMETRIC:
 			if (i > sh->pd_idx)
@@ -761,7 +814,37 @@
 			break;
 		default:
 			printk(KERN_ERR "raid5: unsupported algorithm %d\n",
+			       conf->algorithm);
+		}
+		break;
+	case 6:
+		data_disks = raid_disks - 2;
+		if (i == raid6_next_disk(sh->pd_idx, raid_disks))
+			return 0; /* It is the Q disk */
+		switch (conf->algorithm) {
+		case ALGORITHM_LEFT_ASYMMETRIC:
+		case ALGORITHM_RIGHT_ASYMMETRIC:
+		  	if (sh->pd_idx == raid_disks-1)
+				i--; 	/* Q D D D P */
+			else if (i > sh->pd_idx)
+				i -= 2; /* D D P Q D */
+			break;
+		case ALGORITHM_LEFT_SYMMETRIC:
+		case ALGORITHM_RIGHT_SYMMETRIC:
+			if (sh->pd_idx == raid_disks-1)
+				i--; /* Q D D D P */
+			else {
+				/* D D P Q D */
+				if (i < sh->pd_idx)
+					i += raid_disks;
+				i -= (sh->pd_idx + 2);
+			}
+			break;
+		default:
+			printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
 				conf->algorithm);
+		}
+		break;
 	}
 
 	chunk_number = stripe * data_disks + i;
@@ -778,10 +861,11 @@
 
 
 /*
- * Copy data between a page in the stripe cache, and a bio.
- * There are no alignment or size guarantees between the page or the
- * bio except that there is some overlap.
- * All iovecs in the bio must be considered.
+ * Copy data between a page in the stripe cache, and one or more bion
+ * The page could align with the middle of the bio, or there could be
+ * several bion, each with several bio_vecs, which cover part of the page
+ * Multiple bion are linked together on bi_next.  There may be extras
+ * at the end of this list.  We ignore them.
  */
 static void copy_data(int frombio, struct bio *bio,
 		     struct page *page,
@@ -810,7 +894,7 @@
 		if (len > 0 && page_offset + len > STRIPE_SIZE)
 			clen = STRIPE_SIZE - page_offset;
 		else clen = len;
-			
+
 		if (clen > 0) {
 			char *ba = __bio_kmap_atomic(bio, i, KM_USER0);
 			if (frombio)
@@ -862,14 +946,14 @@
 	set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
 }
 
-static void compute_parity(struct stripe_head *sh, int method)
+static void compute_parity5(struct stripe_head *sh, int method)
 {
 	raid5_conf_t *conf = sh->raid_conf;
 	int i, pd_idx = sh->pd_idx, disks = sh->disks, count;
 	void *ptr[MAX_XOR_BLOCKS];
 	struct bio *chosen;
 
-	PRINTK("compute_parity, stripe %llu, method %d\n",
+	PRINTK("compute_parity5, stripe %llu, method %d\n",
 		(unsigned long long)sh->sector, method);
 
 	count = 1;
@@ -956,9 +1040,195 @@
 		clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
 }
 
+static void compute_parity6(struct stripe_head *sh, int method)
+{
+	raid6_conf_t *conf = sh->raid_conf;
+	int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count;
+	struct bio *chosen;
+	/**** FIX THIS: This could be very bad if disks is close to 256 ****/
+	void *ptrs[disks];
+
+	qd_idx = raid6_next_disk(pd_idx, disks);
+	d0_idx = raid6_next_disk(qd_idx, disks);
+
+	PRINTK("compute_parity, stripe %llu, method %d\n",
+		(unsigned long long)sh->sector, method);
+
+	switch(method) {
+	case READ_MODIFY_WRITE:
+		BUG();		/* READ_MODIFY_WRITE N/A for RAID-6 */
+	case RECONSTRUCT_WRITE:
+		for (i= disks; i-- ;)
+			if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) {
+				chosen = sh->dev[i].towrite;
+				sh->dev[i].towrite = NULL;
+
+				if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+					wake_up(&conf->wait_for_overlap);
+
+				if (sh->dev[i].written) BUG();
+				sh->dev[i].written = chosen;
+			}
+		break;
+	case CHECK_PARITY:
+		BUG();		/* Not implemented yet */
+	}
+
+	for (i = disks; i--;)
+		if (sh->dev[i].written) {
+			sector_t sector = sh->dev[i].sector;
+			struct bio *wbi = sh->dev[i].written;
+			while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) {
+				copy_data(1, wbi, sh->dev[i].page, sector);
+				wbi = r5_next_bio(wbi, sector);
+			}
+
+			set_bit(R5_LOCKED, &sh->dev[i].flags);
+			set_bit(R5_UPTODATE, &sh->dev[i].flags);
+		}
+
+//	switch(method) {
+//	case RECONSTRUCT_WRITE:
+//	case CHECK_PARITY:
+//	case UPDATE_PARITY:
+		/* Note that unlike RAID-5, the ordering of the disks matters greatly. */
+		/* FIX: Is this ordering of drives even remotely optimal? */
+		count = 0;
+		i = d0_idx;
+		do {
+			ptrs[count++] = page_address(sh->dev[i].page);
+			if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags))
+				printk("block %d/%d not uptodate on parity calc\n", i,count);
+			i = raid6_next_disk(i, disks);
+		} while ( i != d0_idx );
+//		break;
+//	}
+
+	raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs);
+
+	switch(method) {
+	case RECONSTRUCT_WRITE:
+		set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
+		set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
+		set_bit(R5_LOCKED,   &sh->dev[pd_idx].flags);
+		set_bit(R5_LOCKED,   &sh->dev[qd_idx].flags);
+		break;
+	case UPDATE_PARITY:
+		set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
+		set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
+		break;
+	}
+}
+
+
+/* Compute one missing block */
+static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
+{
+	raid6_conf_t *conf = sh->raid_conf;
+	int i, count, disks = conf->raid_disks;
+	void *ptr[MAX_XOR_BLOCKS], *p;
+	int pd_idx = sh->pd_idx;
+	int qd_idx = raid6_next_disk(pd_idx, disks);
+
+	PRINTK("compute_block_1, stripe %llu, idx %d\n",
+		(unsigned long long)sh->sector, dd_idx);
+
+	if ( dd_idx == qd_idx ) {
+		/* We're actually computing the Q drive */
+		compute_parity6(sh, UPDATE_PARITY);
+	} else {
+		ptr[0] = page_address(sh->dev[dd_idx].page);
+		if (!nozero) memset(ptr[0], 0, STRIPE_SIZE);
+		count = 1;
+		for (i = disks ; i--; ) {
+			if (i == dd_idx || i == qd_idx)
+				continue;
+			p = page_address(sh->dev[i].page);
+			if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
+				ptr[count++] = p;
+			else
+				printk("compute_block() %d, stripe %llu, %d"
+				       " not present\n", dd_idx,
+				       (unsigned long long)sh->sector, i);
+
+			check_xor();
+		}
+		if (count != 1)
+			xor_block(count, STRIPE_SIZE, ptr);
+		if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
+		else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
+	}
+}
+
+/* Compute two missing blocks */
+static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
+{
+	raid6_conf_t *conf = sh->raid_conf;
+	int i, count, disks = conf->raid_disks;
+	int pd_idx = sh->pd_idx;
+	int qd_idx = raid6_next_disk(pd_idx, disks);
+	int d0_idx = raid6_next_disk(qd_idx, disks);
+	int faila, failb;
+
+	/* faila and failb are disk numbers relative to d0_idx */
+	/* pd_idx become disks-2 and qd_idx become disks-1 */
+	faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx;
+	failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx;
+
+	BUG_ON(faila == failb);
+	if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; }
+
+	PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
+	       (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb);
+
+	if ( failb == disks-1 ) {
+		/* Q disk is one of the missing disks */
+		if ( faila == disks-2 ) {
+			/* Missing P+Q, just recompute */
+			compute_parity6(sh, UPDATE_PARITY);
+			return;
+		} else {
+			/* We're missing D+Q; recompute D from P */
+			compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0);
+			compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */
+			return;
+		}
+	}
+
+	/* We're missing D+P or D+D; build pointer table */
+	{
+		/**** FIX THIS: This could be very bad if disks is close to 256 ****/
+		void *ptrs[disks];
+
+		count = 0;
+		i = d0_idx;
+		do {
+			ptrs[count++] = page_address(sh->dev[i].page);
+			i = raid6_next_disk(i, disks);
+			if (i != dd_idx1 && i != dd_idx2 &&
+			    !test_bit(R5_UPTODATE, &sh->dev[i].flags))
+				printk("compute_2 with missing block %d/%d\n", count, i);
+		} while ( i != d0_idx );
+
+		if ( failb == disks-2 ) {
+			/* We're missing D+P. */
+			raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs);
+		} else {
+			/* We're missing D+D. */
+			raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs);
+		}
+
+		/* Both the above update both missing blocks */
+		set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags);
+		set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags);
+	}
+}
+
+
+
 /*
  * Each stripe/dev can have one or more bion attached.
- * toread/towrite point to the first in a chain. 
+ * toread/towrite point to the first in a chain.
  * The bi_next chain must be in order.
  */
 static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite)
@@ -1031,6 +1301,13 @@
 
 static void end_reshape(raid5_conf_t *conf);
 
+static int page_is_zero(struct page *p)
+{
+	char *a = page_address(p);
+	return ((*(u32*)a) == 0 &&
+		memcmp(a, a+4, STRIPE_SIZE-4)==0);
+}
+
 static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
 {
 	int sectors_per_chunk = conf->chunk_size >> 9;
@@ -1062,7 +1339,7 @@
  *
  */
  
-static void handle_stripe(struct stripe_head *sh)
+static void handle_stripe5(struct stripe_head *sh)
 {
 	raid5_conf_t *conf = sh->raid_conf;
 	int disks = sh->disks;
@@ -1394,7 +1671,7 @@
 		if (locked == 0 && (rcw == 0 ||rmw == 0) &&
 		    !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
 			PRINTK("Computing parity...\n");
-			compute_parity(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE);
+			compute_parity5(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE);
 			/* now every locked buffer is ready to be written */
 			for (i=disks; i--;)
 				if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
@@ -1421,13 +1698,10 @@
 	    !test_bit(STRIPE_INSYNC, &sh->state)) {
 		set_bit(STRIPE_HANDLE, &sh->state);
 		if (failed == 0) {
-			char *pagea;
 			BUG_ON(uptodate != disks);
-			compute_parity(sh, CHECK_PARITY);
+			compute_parity5(sh, CHECK_PARITY);
 			uptodate--;
-			pagea = page_address(sh->dev[sh->pd_idx].page);
-			if ((*(u32*)pagea) == 0 &&
-			    !memcmp(pagea, pagea+4, STRIPE_SIZE-4)) {
+			if (page_is_zero(sh->dev[sh->pd_idx].page)) {
 				/* parity is correct (on disc, not in buffer any more) */
 				set_bit(STRIPE_INSYNC, &sh->state);
 			} else {
@@ -1487,7 +1761,7 @@
 		/* Need to write out all blocks after computing parity */
 		sh->disks = conf->raid_disks;
 		sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks);
-		compute_parity(sh, RECONSTRUCT_WRITE);
+		compute_parity5(sh, RECONSTRUCT_WRITE);
 		for (i= conf->raid_disks; i--;) {
 			set_bit(R5_LOCKED, &sh->dev[i].flags);
 			locked++;
@@ -1615,6 +1889,569 @@
 	}
 }
 
+static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
+{
+	raid6_conf_t *conf = sh->raid_conf;
+	int disks = conf->raid_disks;
+	struct bio *return_bi= NULL;
+	struct bio *bi;
+	int i;
+	int syncing;
+	int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
+	int non_overwrite = 0;
+	int failed_num[2] = {0, 0};
+	struct r5dev *dev, *pdev, *qdev;
+	int pd_idx = sh->pd_idx;
+	int qd_idx = raid6_next_disk(pd_idx, disks);
+	int p_failed, q_failed;
+
+	PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n",
+	       (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count),
+	       pd_idx, qd_idx);
+
+	spin_lock(&sh->lock);
+	clear_bit(STRIPE_HANDLE, &sh->state);
+	clear_bit(STRIPE_DELAYED, &sh->state);
+
+	syncing = test_bit(STRIPE_SYNCING, &sh->state);
+	/* Now to look around and see what can be done */
+
+	rcu_read_lock();
+	for (i=disks; i--; ) {
+		mdk_rdev_t *rdev;
+		dev = &sh->dev[i];
+		clear_bit(R5_Insync, &dev->flags);
+
+		PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
+			i, dev->flags, dev->toread, dev->towrite, dev->written);
+		/* maybe we can reply to a read */
+		if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) {
+			struct bio *rbi, *rbi2;
+			PRINTK("Return read for disc %d\n", i);
+			spin_lock_irq(&conf->device_lock);
+			rbi = dev->toread;
+			dev->toread = NULL;
+			if (test_and_clear_bit(R5_Overlap, &dev->flags))
+				wake_up(&conf->wait_for_overlap);
+			spin_unlock_irq(&conf->device_lock);
+			while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) {
+				copy_data(0, rbi, dev->page, dev->sector);
+				rbi2 = r5_next_bio(rbi, dev->sector);
+				spin_lock_irq(&conf->device_lock);
+				if (--rbi->bi_phys_segments == 0) {
+					rbi->bi_next = return_bi;
+					return_bi = rbi;
+				}
+				spin_unlock_irq(&conf->device_lock);
+				rbi = rbi2;
+			}
+		}
+
+		/* now count some things */
+		if (test_bit(R5_LOCKED, &dev->flags)) locked++;
+		if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++;
+
+
+		if (dev->toread) to_read++;
+		if (dev->towrite) {
+			to_write++;
+			if (!test_bit(R5_OVERWRITE, &dev->flags))
+				non_overwrite++;
+		}
+		if (dev->written) written++;
+		rdev = rcu_dereference(conf->disks[i].rdev);
+		if (!rdev || !test_bit(In_sync, &rdev->flags)) {
+			/* The ReadError flag will 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)) {
+			if ( failed < 2 )
+				failed_num[failed] = i;
+			failed++;
+		} else
+			set_bit(R5_Insync, &dev->flags);
+	}
+	rcu_read_unlock();
+	PRINTK("locked=%d uptodate=%d to_read=%d"
+	       " to_write=%d failed=%d failed_num=%d,%d\n",
+	       locked, uptodate, to_read, to_write, failed,
+	       failed_num[0], failed_num[1]);
+	/* check if the array has lost >2 devices and, if so, some requests might
+	 * need to be failed
+	 */
+	if (failed > 2 && 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;
+				rcu_read_lock();
+				rdev = rcu_dereference(conf->disks[i].rdev);
+				if (rdev && test_bit(In_sync, &rdev->flags))
+					/* multiple read failures in one stripe */
+					md_error(conf->mddev, rdev);
+				rcu_read_unlock();
+			}
+
+			spin_lock_irq(&conf->device_lock);
+			/* fail all writes first */
+			bi = sh->dev[i].towrite;
+			sh->dev[i].towrite = NULL;
+			if (bi) { to_write--; bitmap_end = 1; }
+
+			if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+				wake_up(&conf->wait_for_overlap);
+
+			while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
+				struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
+				clear_bit(BIO_UPTODATE, &bi->bi_flags);
+				if (--bi->bi_phys_segments == 0) {
+					md_write_end(conf->mddev);
+					bi->bi_next = return_bi;
+					return_bi = bi;
+				}
+				bi = nextbi;
+			}
+			/* and fail all 'written' */
+			bi = sh->dev[i].written;
+			sh->dev[i].written = NULL;
+			if (bi) bitmap_end = 1;
+			while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) {
+				struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
+				clear_bit(BIO_UPTODATE, &bi->bi_flags);
+				if (--bi->bi_phys_segments == 0) {
+					md_write_end(conf->mddev);
+					bi->bi_next = return_bi;
+					return_bi = bi;
+				}
+				bi = bi2;
+			}
+
+			/* fail any reads if this device is non-operational */
+			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))
+					wake_up(&conf->wait_for_overlap);
+				if (bi) to_read--;
+				while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
+					struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
+					clear_bit(BIO_UPTODATE, &bi->bi_flags);
+					if (--bi->bi_phys_segments == 0) {
+						bi->bi_next = return_bi;
+						return_bi = bi;
+					}
+					bi = nextbi;
+				}
+			}
+			spin_unlock_irq(&conf->device_lock);
+			if (bitmap_end)
+				bitmap_endwrite(conf->mddev->bitmap, sh->sector,
+						STRIPE_SECTORS, 0, 0);
+		}
+	}
+	if (failed > 2 && syncing) {
+		md_done_sync(conf->mddev, STRIPE_SECTORS,0);
+		clear_bit(STRIPE_SYNCING, &sh->state);
+		syncing = 0;
+	}
+
+	/*
+	 * might be able to return some write requests if the parity blocks
+	 * are safe, or on a failed drive
+	 */
+	pdev = &sh->dev[pd_idx];
+	p_failed = (failed >= 1 && failed_num[0] == pd_idx)
+		|| (failed >= 2 && failed_num[1] == pd_idx);
+	qdev = &sh->dev[qd_idx];
+	q_failed = (failed >= 1 && failed_num[0] == qd_idx)
+		|| (failed >= 2 && failed_num[1] == qd_idx);
+
+	if ( written &&
+	     ( p_failed || ((test_bit(R5_Insync, &pdev->flags)
+			     && !test_bit(R5_LOCKED, &pdev->flags)
+			     && test_bit(R5_UPTODATE, &pdev->flags))) ) &&
+	     ( q_failed || ((test_bit(R5_Insync, &qdev->flags)
+			     && !test_bit(R5_LOCKED, &qdev->flags)
+			     && test_bit(R5_UPTODATE, &qdev->flags))) ) ) {
+		/* any written block on an uptodate or failed drive can be
+		 * returned.  Note that if we 'wrote' to a failed drive,
+		 * it will be UPTODATE, but never LOCKED, so we don't need
+		 * to test 'failed' directly.
+		 */
+		for (i=disks; i--; )
+			if (sh->dev[i].written) {
+				dev = &sh->dev[i];
+				if (!test_bit(R5_LOCKED, &dev->flags) &&
+				    test_bit(R5_UPTODATE, &dev->flags) ) {
+					/* We can return any write requests */
+					int bitmap_end = 0;
+					struct bio *wbi, *wbi2;
+					PRINTK("Return write for stripe %llu disc %d\n",
+					       (unsigned long long)sh->sector, i);
+					spin_lock_irq(&conf->device_lock);
+					wbi = dev->written;
+					dev->written = NULL;
+					while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {
+						wbi2 = r5_next_bio(wbi, dev->sector);
+						if (--wbi->bi_phys_segments == 0) {
+							md_write_end(conf->mddev);
+							wbi->bi_next = return_bi;
+							return_bi = wbi;
+						}
+						wbi = wbi2;
+					}
+					if (dev->towrite == NULL)
+						bitmap_end = 1;
+					spin_unlock_irq(&conf->device_lock);
+					if (bitmap_end)
+						bitmap_endwrite(conf->mddev->bitmap, sh->sector,
+								STRIPE_SECTORS,
+								!test_bit(STRIPE_DEGRADED, &sh->state), 0);
+				}
+			}
+	}
+
+	/* Now we might consider reading some blocks, either to check/generate
+	 * parity, or to satisfy requests
+	 * or to load a block that is being partially written.
+	 */
+	if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) {
+		for (i=disks; i--;) {
+			dev = &sh->dev[i];
+			if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
+			    (dev->toread ||
+			     (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
+			     syncing ||
+			     (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
+			     (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
+				    )
+				) {
+				/* we would like to get this block, possibly
+				 * by computing it, but we might not be able to
+				 */
+				if (uptodate == disks-1) {
+					PRINTK("Computing stripe %llu block %d\n",
+					       (unsigned long long)sh->sector, i);
+					compute_block_1(sh, i, 0);
+					uptodate++;
+				} else if ( uptodate == disks-2 && failed >= 2 ) {
+					/* Computing 2-failure is *very* expensive; only do it if failed >= 2 */
+					int other;
+					for (other=disks; other--;) {
+						if ( other == i )
+							continue;
+						if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) )
+							break;
+					}
+					BUG_ON(other < 0);
+					PRINTK("Computing stripe %llu blocks %d,%d\n",
+					       (unsigned long long)sh->sector, i, other);
+					compute_block_2(sh, i, other);
+					uptodate += 2;
+				} else if (test_bit(R5_Insync, &dev->flags)) {
+					set_bit(R5_LOCKED, &dev->flags);
+					set_bit(R5_Wantread, &dev->flags);
+#if 0
+					/* if I am just reading this block and we don't have
+					   a failed drive, or any pending writes then sidestep the cache */
+					if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
+					    ! syncing && !failed && !to_write) {
+						sh->bh_cache[i]->b_page =  sh->bh_read[i]->b_page;
+						sh->bh_cache[i]->b_data =  sh->bh_read[i]->b_data;
+					}
+#endif
+					locked++;
+					PRINTK("Reading block %d (sync=%d)\n",
+						i, syncing);
+				}
+			}
+		}
+		set_bit(STRIPE_HANDLE, &sh->state);
+	}
+
+	/* now to consider writing and what else, if anything should be read */
+	if (to_write) {
+		int rcw=0, must_compute=0;
+		for (i=disks ; i--;) {
+			dev = &sh->dev[i];
+			/* Would I have to read this buffer for reconstruct_write */
+			if (!test_bit(R5_OVERWRITE, &dev->flags)
+			    && i != pd_idx && i != qd_idx
+			    && (!test_bit(R5_LOCKED, &dev->flags)
+#if 0
+				|| sh->bh_page[i] != bh->b_page
+#endif
+				    ) &&
+			    !test_bit(R5_UPTODATE, &dev->flags)) {
+				if (test_bit(R5_Insync, &dev->flags)) rcw++;
+				else {
+					PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags);
+					must_compute++;
+				}
+			}
+		}
+		PRINTK("for sector %llu, rcw=%d, must_compute=%d\n",
+		       (unsigned long long)sh->sector, rcw, must_compute);
+		set_bit(STRIPE_HANDLE, &sh->state);
+
+		if (rcw > 0)
+			/* want reconstruct write, but need to get some data */
+			for (i=disks; i--;) {
+				dev = &sh->dev[i];
+				if (!test_bit(R5_OVERWRITE, &dev->flags)
+				    && !(failed == 0 && (i == pd_idx || i == qd_idx))
+				    && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
+				    test_bit(R5_Insync, &dev->flags)) {
+					if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+					{
+						PRINTK("Read_old stripe %llu block %d for Reconstruct\n",
+						       (unsigned long long)sh->sector, i);
+						set_bit(R5_LOCKED, &dev->flags);
+						set_bit(R5_Wantread, &dev->flags);
+						locked++;
+					} else {
+						PRINTK("Request delayed stripe %llu block %d for Reconstruct\n",
+						       (unsigned long long)sh->sector, i);
+						set_bit(STRIPE_DELAYED, &sh->state);
+						set_bit(STRIPE_HANDLE, &sh->state);
+					}
+				}
+			}
+		/* now if nothing is locked, and if we have enough data, we can start a write request */
+		if (locked == 0 && rcw == 0 &&
+		    !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
+			if ( must_compute > 0 ) {
+				/* We have failed blocks and need to compute them */
+				switch ( failed ) {
+				case 0:	BUG();
+				case 1: compute_block_1(sh, failed_num[0], 0); break;
+				case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break;
+				default: BUG();	/* This request should have been failed? */
+				}
+			}
+
+			PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector);
+			compute_parity6(sh, RECONSTRUCT_WRITE);
+			/* now every locked buffer is ready to be written */
+			for (i=disks; i--;)
+				if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
+					PRINTK("Writing stripe %llu block %d\n",
+					       (unsigned long long)sh->sector, i);
+					locked++;
+					set_bit(R5_Wantwrite, &sh->dev[i].flags);
+				}
+			/* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
+			set_bit(STRIPE_INSYNC, &sh->state);
+
+			if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+				atomic_dec(&conf->preread_active_stripes);
+				if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
+					md_wakeup_thread(conf->mddev->thread);
+			}
+		}
+	}
+
+	/* maybe we need to check and possibly fix the parity for this stripe
+	 * Any reads will already have been scheduled, so we just see if enough data
+	 * is available
+	 */
+	if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) {
+		int update_p = 0, update_q = 0;
+		struct r5dev *dev;
+
+		set_bit(STRIPE_HANDLE, &sh->state);
+
+		BUG_ON(failed>2);
+		BUG_ON(uptodate < disks);
+		/* Want to check and possibly repair P and Q.
+		 * However there could be one 'failed' device, in which
+		 * case we can only check one of them, possibly using the
+		 * other to generate missing data
+		 */
+
+		/* If !tmp_page, we cannot do the calculations,
+		 * but as we have set STRIPE_HANDLE, we will soon be called
+		 * by stripe_handle with a tmp_page - just wait until then.
+		 */
+		if (tmp_page) {
+			if (failed == q_failed) {
+				/* The only possible failed device holds 'Q', so it makes
+				 * sense to check P (If anything else were failed, we would
+				 * have used P to recreate it).
+				 */
+				compute_block_1(sh, pd_idx, 1);
+				if (!page_is_zero(sh->dev[pd_idx].page)) {
+					compute_block_1(sh,pd_idx,0);
+					update_p = 1;
+				}
+			}
+			if (!q_failed && failed < 2) {
+				/* q is not failed, and we didn't use it to generate
+				 * anything, so it makes sense to check it
+				 */
+				memcpy(page_address(tmp_page),
+				       page_address(sh->dev[qd_idx].page),
+				       STRIPE_SIZE);
+				compute_parity6(sh, UPDATE_PARITY);
+				if (memcmp(page_address(tmp_page),
+					   page_address(sh->dev[qd_idx].page),
+					   STRIPE_SIZE)!= 0) {
+					clear_bit(STRIPE_INSYNC, &sh->state);
+					update_q = 1;
+				}
+			}
+			if (update_p || update_q) {
+				conf->mddev->resync_mismatches += STRIPE_SECTORS;
+				if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
+					/* don't try to repair!! */
+					update_p = update_q = 0;
+			}
+
+			/* now write out any block on a failed drive,
+			 * or P or Q if they need it
+			 */
+
+			if (failed == 2) {
+				dev = &sh->dev[failed_num[1]];
+				locked++;
+				set_bit(R5_LOCKED, &dev->flags);
+				set_bit(R5_Wantwrite, &dev->flags);
+			}
+			if (failed >= 1) {
+				dev = &sh->dev[failed_num[0]];
+				locked++;
+				set_bit(R5_LOCKED, &dev->flags);
+				set_bit(R5_Wantwrite, &dev->flags);
+			}
+
+			if (update_p) {
+				dev = &sh->dev[pd_idx];
+				locked ++;
+				set_bit(R5_LOCKED, &dev->flags);
+				set_bit(R5_Wantwrite, &dev->flags);
+			}
+			if (update_q) {
+				dev = &sh->dev[qd_idx];
+				locked++;
+				set_bit(R5_LOCKED, &dev->flags);
+				set_bit(R5_Wantwrite, &dev->flags);
+			}
+			clear_bit(STRIPE_DEGRADED, &sh->state);
+
+			set_bit(STRIPE_INSYNC, &sh->state);
+		}
+	}
+
+	if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
+		md_done_sync(conf->mddev, STRIPE_SECTORS,1);
+		clear_bit(STRIPE_SYNCING, &sh->state);
+	}
+
+	/* If the failed drives are just a ReadError, then we might need
+	 * to progress the repair/check process
+	 */
+	if (failed <= 2 && ! conf->mddev->ro)
+		for (i=0; i<failed;i++) {
+			dev = &sh->dev[failed_num[i]];
+			if (test_bit(R5_ReadError, &dev->flags)
+			    && !test_bit(R5_LOCKED, &dev->flags)
+			    && test_bit(R5_UPTODATE, &dev->flags)
+				) {
+				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)) {
+		int bytes = bi->bi_size;
+
+		return_bi = bi->bi_next;
+		bi->bi_next = NULL;
+		bi->bi_size = 0;
+		bi->bi_end_io(bi, bytes, 0);
+	}
+	for (i=disks; i-- ;) {
+		int rw;
+		struct bio *bi;
+		mdk_rdev_t *rdev;
+		if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
+			rw = 1;
+		else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
+			rw = 0;
+		else
+			continue;
+
+		bi = &sh->dev[i].req;
+
+		bi->bi_rw = rw;
+		if (rw)
+			bi->bi_end_io = raid5_end_write_request;
+		else
+			bi->bi_end_io = raid5_end_read_request;
+
+		rcu_read_lock();
+		rdev = rcu_dereference(conf->disks[i].rdev);
+		if (rdev && test_bit(Faulty, &rdev->flags))
+			rdev = NULL;
+		if (rdev)
+			atomic_inc(&rdev->nr_pending);
+		rcu_read_unlock();
+
+		if (rdev) {
+			if (syncing)
+				md_sync_acct(rdev->bdev, STRIPE_SECTORS);
+
+			bi->bi_bdev = rdev->bdev;
+			PRINTK("for %llu schedule op %ld on disc %d\n",
+				(unsigned long long)sh->sector, bi->bi_rw, i);
+			atomic_inc(&sh->count);
+			bi->bi_sector = sh->sector + rdev->data_offset;
+			bi->bi_flags = 1 << BIO_UPTODATE;
+			bi->bi_vcnt = 1;
+			bi->bi_max_vecs = 1;
+			bi->bi_idx = 0;
+			bi->bi_io_vec = &sh->dev[i].vec;
+			bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
+			bi->bi_io_vec[0].bv_offset = 0;
+			bi->bi_size = STRIPE_SIZE;
+			bi->bi_next = NULL;
+			if (rw == WRITE &&
+			    test_bit(R5_ReWrite, &sh->dev[i].flags))
+				atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
+			generic_make_request(bi);
+		} else {
+			if (rw == 1)
+				set_bit(STRIPE_DEGRADED, &sh->state);
+			PRINTK("skip op %ld on disc %d for sector %llu\n",
+				bi->bi_rw, i, (unsigned long long)sh->sector);
+			clear_bit(R5_LOCKED, &sh->dev[i].flags);
+			set_bit(STRIPE_HANDLE, &sh->state);
+		}
+	}
+}
+
+static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
+{
+	if (sh->raid_conf->level == 6)
+		handle_stripe6(sh, tmp_page);
+	else
+		handle_stripe5(sh);
+}
+
+
+
 static void raid5_activate_delayed(raid5_conf_t *conf)
 {
 	if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
@@ -1753,7 +2590,7 @@
 
 	for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
 		DEFINE_WAIT(w);
-		int disks;
+		int disks, data_disks;
 
 	retry:
 		prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
@@ -1781,7 +2618,9 @@
 			}
 			spin_unlock_irq(&conf->device_lock);
 		}
- 		new_sector = raid5_compute_sector(logical_sector, disks, disks - 1,
+		data_disks = disks - conf->max_degraded;
+
+ 		new_sector = raid5_compute_sector(logical_sector, disks, data_disks,
 						  &dd_idx, &pd_idx, conf);
 		PRINTK("raid5: make_request, sector %llu logical %llu\n",
 			(unsigned long long)new_sector, 
@@ -1833,7 +2672,7 @@
 			}
 			finish_wait(&conf->wait_for_overlap, &w);
 			raid5_plug_device(conf);
-			handle_stripe(sh);
+			handle_stripe(sh, NULL);
 			release_stripe(sh);
 		} else {
 			/* cannot get stripe for read-ahead, just give-up */
@@ -1849,7 +2688,7 @@
 	if (remaining == 0) {
 		int bytes = bi->bi_size;
 
-		if ( bio_data_dir(bi) == WRITE )
+		if ( rw == WRITE )
 			md_write_end(mddev);
 		bi->bi_size = 0;
 		bi->bi_end_io(bi, bytes, 0);
@@ -1857,17 +2696,142 @@
 	return 0;
 }
 
-/* FIXME go_faster isn't used */
-static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
+static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped)
 {
+	/* reshaping is quite different to recovery/resync so it is
+	 * handled quite separately ... here.
+	 *
+	 * On each call to sync_request, we gather one chunk worth of
+	 * destination stripes and flag them as expanding.
+	 * Then we find all the source stripes and request reads.
+	 * As the reads complete, handle_stripe will copy the data
+	 * into the destination stripe and release that stripe.
+	 */
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	struct stripe_head *sh;
 	int pd_idx;
 	sector_t first_sector, last_sector;
+	int raid_disks;
+	int data_disks;
+	int i;
+	int dd_idx;
+	sector_t writepos, safepos, gap;
+
+	if (sector_nr == 0 &&
+	    conf->expand_progress != 0) {
+		/* restarting in the middle, skip the initial sectors */
+		sector_nr = conf->expand_progress;
+		sector_div(sector_nr, conf->raid_disks-1);
+		*skipped = 1;
+		return sector_nr;
+	}
+
+	/* we update the metadata when there is more than 3Meg
+	 * in the block range (that is rather arbitrary, should
+	 * probably be time based) or when the data about to be
+	 * copied would over-write the source of the data at
+	 * the front of the range.
+	 * i.e. one new_stripe forward from expand_progress new_maps
+	 * to after where expand_lo old_maps to
+	 */
+	writepos = conf->expand_progress +
+		conf->chunk_size/512*(conf->raid_disks-1);
+	sector_div(writepos, conf->raid_disks-1);
+	safepos = conf->expand_lo;
+	sector_div(safepos, conf->previous_raid_disks-1);
+	gap = conf->expand_progress - conf->expand_lo;
+
+	if (writepos >= safepos ||
+	    gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) {
+		/* Cannot proceed until we've updated the superblock... */
+		wait_event(conf->wait_for_overlap,
+			   atomic_read(&conf->reshape_stripes)==0);
+		mddev->reshape_position = conf->expand_progress;
+		mddev->sb_dirty = 1;
+		md_wakeup_thread(mddev->thread);
+		wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
+			   kthread_should_stop());
+		spin_lock_irq(&conf->device_lock);
+		conf->expand_lo = mddev->reshape_position;
+		spin_unlock_irq(&conf->device_lock);
+		wake_up(&conf->wait_for_overlap);
+	}
+
+	for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
+		int j;
+		int skipped = 0;
+		pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks);
+		sh = get_active_stripe(conf, sector_nr+i,
+				       conf->raid_disks, pd_idx, 0);
+		set_bit(STRIPE_EXPANDING, &sh->state);
+		atomic_inc(&conf->reshape_stripes);
+		/* If any of this stripe is beyond the end of the old
+		 * array, then we need to zero those blocks
+		 */
+		for (j=sh->disks; j--;) {
+			sector_t s;
+			if (j == sh->pd_idx)
+				continue;
+			s = compute_blocknr(sh, j);
+			if (s < (mddev->array_size<<1)) {
+				skipped = 1;
+				continue;
+			}
+			memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE);
+			set_bit(R5_Expanded, &sh->dev[j].flags);
+			set_bit(R5_UPTODATE, &sh->dev[j].flags);
+		}
+		if (!skipped) {
+			set_bit(STRIPE_EXPAND_READY, &sh->state);
+			set_bit(STRIPE_HANDLE, &sh->state);
+		}
+		release_stripe(sh);
+	}
+	spin_lock_irq(&conf->device_lock);
+	conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1);
+	spin_unlock_irq(&conf->device_lock);
+	/* Ok, those stripe are ready. We can start scheduling
+	 * reads on the source stripes.
+	 * The source stripes are determined by mapping the first and last
+	 * block on the destination stripes.
+	 */
+	raid_disks = conf->previous_raid_disks;
+	data_disks = raid_disks - 1;
+	first_sector =
+		raid5_compute_sector(sector_nr*(conf->raid_disks-1),
+				     raid_disks, data_disks,
+				     &dd_idx, &pd_idx, conf);
+	last_sector =
+		raid5_compute_sector((sector_nr+conf->chunk_size/512)
+				     *(conf->raid_disks-1) -1,
+				     raid_disks, data_disks,
+				     &dd_idx, &pd_idx, conf);
+	if (last_sector >= (mddev->size<<1))
+		last_sector = (mddev->size<<1)-1;
+	while (first_sector <= last_sector) {
+		pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks);
+		sh = get_active_stripe(conf, first_sector,
+				       conf->previous_raid_disks, pd_idx, 0);
+		set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+		set_bit(STRIPE_HANDLE, &sh->state);
+		release_stripe(sh);
+		first_sector += STRIPE_SECTORS;
+	}
+	return conf->chunk_size>>9;
+}
+
+/* FIXME go_faster isn't used */
+static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
+{
+	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+	struct stripe_head *sh;
+	int pd_idx;
 	int raid_disks = conf->raid_disks;
-	int data_disks = raid_disks-1;
+	int data_disks = raid_disks - conf->max_degraded;
 	sector_t max_sector = mddev->size << 1;
 	int sync_blocks;
+	int still_degraded = 0;
+	int i;
 
 	if (sector_nr >= max_sector) {
 		/* just being told to finish up .. nothing much to do */
@@ -1880,134 +2844,22 @@
 		if (mddev->curr_resync < max_sector) /* aborted */
 			bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
 					&sync_blocks, 1);
-		else /* compelted sync */
+		else /* completed sync */
 			conf->fullsync = 0;
 		bitmap_close_sync(mddev->bitmap);
 
 		return 0;
 	}
 
-	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
-		/* reshaping is quite different to recovery/resync so it is
-		 * handled quite separately ... here.
-		 *
-		 * On each call to sync_request, we gather one chunk worth of
-		 * destination stripes and flag them as expanding.
-		 * Then we find all the source stripes and request reads.
-		 * As the reads complete, handle_stripe will copy the data
-		 * into the destination stripe and release that stripe.
-		 */
-		int i;
-		int dd_idx;
-		sector_t writepos, safepos, gap;
+	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+		return reshape_request(mddev, sector_nr, skipped);
 
-		if (sector_nr == 0 &&
-		    conf->expand_progress != 0) {
-			/* restarting in the middle, skip the initial sectors */
-			sector_nr = conf->expand_progress;
-			sector_div(sector_nr, conf->raid_disks-1);
-			*skipped = 1;
-			return sector_nr;
-		}
-
-		/* we update the metadata when there is more than 3Meg
-		 * in the block range (that is rather arbitrary, should
-		 * probably be time based) or when the data about to be
-		 * copied would over-write the source of the data at
-		 * the front of the range.
-		 * i.e. one new_stripe forward from expand_progress new_maps
-		 * to after where expand_lo old_maps to
-		 */
-		writepos = conf->expand_progress +
-			conf->chunk_size/512*(conf->raid_disks-1);
-		sector_div(writepos, conf->raid_disks-1);
-		safepos = conf->expand_lo;
-		sector_div(safepos, conf->previous_raid_disks-1);
-		gap = conf->expand_progress - conf->expand_lo;
-
-		if (writepos >= safepos ||
-		    gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) {
-			/* Cannot proceed until we've updated the superblock... */
-			wait_event(conf->wait_for_overlap,
-				   atomic_read(&conf->reshape_stripes)==0);
-			mddev->reshape_position = conf->expand_progress;
-			mddev->sb_dirty = 1;
-			md_wakeup_thread(mddev->thread);
-			wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
-				   kthread_should_stop());
-			spin_lock_irq(&conf->device_lock);
-			conf->expand_lo = mddev->reshape_position;
-			spin_unlock_irq(&conf->device_lock);
-			wake_up(&conf->wait_for_overlap);
-		}
-
-		for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
-			int j;
-			int skipped = 0;
-			pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks);
-			sh = get_active_stripe(conf, sector_nr+i,
-					       conf->raid_disks, pd_idx, 0);
-			set_bit(STRIPE_EXPANDING, &sh->state);
-			atomic_inc(&conf->reshape_stripes);
-			/* If any of this stripe is beyond the end of the old
-			 * array, then we need to zero those blocks
-			 */
-			for (j=sh->disks; j--;) {
-				sector_t s;
-				if (j == sh->pd_idx)
-					continue;
-				s = compute_blocknr(sh, j);
-				if (s < (mddev->array_size<<1)) {
-					skipped = 1;
-					continue;
-				}
-				memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE);
-				set_bit(R5_Expanded, &sh->dev[j].flags);
-				set_bit(R5_UPTODATE, &sh->dev[j].flags);
-			}
-			if (!skipped) {
-				set_bit(STRIPE_EXPAND_READY, &sh->state);
-				set_bit(STRIPE_HANDLE, &sh->state);
-			}
-			release_stripe(sh);
-		}
-		spin_lock_irq(&conf->device_lock);
-		conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1);
-		spin_unlock_irq(&conf->device_lock);
-		/* Ok, those stripe are ready. We can start scheduling
-		 * reads on the source stripes.
-		 * The source stripes are determined by mapping the first and last
-		 * block on the destination stripes.
-		 */
-		raid_disks = conf->previous_raid_disks;
-		data_disks = raid_disks - 1;
-		first_sector =
-			raid5_compute_sector(sector_nr*(conf->raid_disks-1),
-					     raid_disks, data_disks,
-					     &dd_idx, &pd_idx, conf);
-		last_sector =
-			raid5_compute_sector((sector_nr+conf->chunk_size/512)
-					       *(conf->raid_disks-1) -1,
-					     raid_disks, data_disks,
-					     &dd_idx, &pd_idx, conf);
-		if (last_sector >= (mddev->size<<1))
-			last_sector = (mddev->size<<1)-1;
-		while (first_sector <= last_sector) {
-			pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks);
-			sh = get_active_stripe(conf, first_sector,
-					       conf->previous_raid_disks, pd_idx, 0);
-			set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
-			set_bit(STRIPE_HANDLE, &sh->state);
-			release_stripe(sh);
-			first_sector += STRIPE_SECTORS;
-		}
-		return conf->chunk_size>>9;
-	}
-	/* if there is 1 or more failed drives and we are trying
+	/* if there is too many failed drives and we are trying
 	 * to resync, then assert that we are finished, because there is
 	 * nothing we can do.
 	 */
-	if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+	if (mddev->degraded >= conf->max_degraded &&
+	    test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
 		sector_t rv = (mddev->size << 1) - sector_nr;
 		*skipped = 1;
 		return rv;
@@ -2026,17 +2878,26 @@
 	if (sh == NULL) {
 		sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0);
 		/* make sure we don't swamp the stripe cache if someone else
-		 * is trying to get access 
+		 * is trying to get access
 		 */
 		schedule_timeout_uninterruptible(1);
 	}
-	bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0);
-	spin_lock(&sh->lock);	
+	/* Need to check if array will still be degraded after recovery/resync
+	 * We don't need to check the 'failed' flag as when that gets set,
+	 * recovery aborts.
+	 */
+	for (i=0; i<mddev->raid_disks; i++)
+		if (conf->disks[i].rdev == NULL)
+			still_degraded = 1;
+
+	bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
+
+	spin_lock(&sh->lock);
 	set_bit(STRIPE_SYNCING, &sh->state);
 	clear_bit(STRIPE_INSYNC, &sh->state);
 	spin_unlock(&sh->lock);
 
-	handle_stripe(sh);
+	handle_stripe(sh, NULL);
 	release_stripe(sh);
 
 	return STRIPE_SECTORS;
@@ -2091,7 +2952,7 @@
 		spin_unlock_irq(&conf->device_lock);
 		
 		handled++;
-		handle_stripe(sh);
+		handle_stripe(sh, conf->spare_page);
 		release_stripe(sh);
 
 		spin_lock_irq(&conf->device_lock);
@@ -2181,8 +3042,8 @@
 	struct disk_info *disk;
 	struct list_head *tmp;
 
-	if (mddev->level != 5 && mddev->level != 4) {
-		printk(KERN_ERR "raid5: %s: raid level not set to 4/5 (%d)\n",
+	if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) {
+		printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n",
 		       mdname(mddev), mddev->level);
 		return -EIO;
 	}
@@ -2251,6 +3112,11 @@
 	if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
 		goto abort;
 
+	if (mddev->level == 6) {
+		conf->spare_page = alloc_page(GFP_KERNEL);
+		if (!conf->spare_page)
+			goto abort;
+	}
 	spin_lock_init(&conf->device_lock);
 	init_waitqueue_head(&conf->wait_for_stripe);
 	init_waitqueue_head(&conf->wait_for_overlap);
@@ -2282,12 +3148,16 @@
 	}
 
 	/*
-	 * 0 for a fully functional array, 1 for a degraded array.
+	 * 0 for a fully functional array, 1 or 2 for a degraded array.
 	 */
 	mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks;
 	conf->mddev = mddev;
 	conf->chunk_size = mddev->chunk_size;
 	conf->level = mddev->level;
+	if (conf->level == 6)
+		conf->max_degraded = 2;
+	else
+		conf->max_degraded = 1;
 	conf->algorithm = mddev->layout;
 	conf->max_nr_stripes = NR_STRIPES;
 	conf->expand_progress = mddev->reshape_position;
@@ -2296,6 +3166,11 @@
 	mddev->size &= ~(mddev->chunk_size/1024 -1);
 	mddev->resync_max_sectors = mddev->size << 1;
 
+	if (conf->level == 6 && conf->raid_disks < 4) {
+		printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
+		       mdname(mddev), conf->raid_disks);
+		goto abort;
+	}
 	if (!conf->chunk_size || conf->chunk_size % 4) {
 		printk(KERN_ERR "raid5: invalid chunk size %d for %s\n",
 			conf->chunk_size, mdname(mddev));
@@ -2307,14 +3182,14 @@
 			conf->algorithm, mdname(mddev));
 		goto abort;
 	}
-	if (mddev->degraded > 1) {
+	if (mddev->degraded > conf->max_degraded) {
 		printk(KERN_ERR "raid5: not enough operational devices for %s"
 			" (%d/%d failed)\n",
 			mdname(mddev), conf->failed_disks, conf->raid_disks);
 		goto abort;
 	}
 
-	if (mddev->degraded == 1 &&
+	if (mddev->degraded > 0 &&
 	    mddev->recovery_cp != MaxSector) {
 		if (mddev->ok_start_degraded)
 			printk(KERN_WARNING
@@ -2379,11 +3254,12 @@
 	}
 
 	/* read-ahead size must cover two whole stripes, which is
-	 * 2 * (n-1) * chunksize where 'n' is the number of raid devices
+	 * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
 	 */
 	{
-		int stripe = (mddev->raid_disks-1) * mddev->chunk_size
-			/ PAGE_SIZE;
+		int data_disks = conf->previous_raid_disks - conf->max_degraded;
+		int stripe = data_disks *
+			(mddev->chunk_size / PAGE_SIZE);
 		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
 			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
 	}
@@ -2393,12 +3269,14 @@
 
 	mddev->queue->unplug_fn = raid5_unplug_device;
 	mddev->queue->issue_flush_fn = raid5_issue_flush;
-	mddev->array_size =  mddev->size * (conf->previous_raid_disks - 1);
+	mddev->array_size =  mddev->size * (conf->previous_raid_disks -
+					    conf->max_degraded);
 
 	return 0;
 abort:
 	if (conf) {
 		print_raid5_conf(conf);
+		safe_put_page(conf->spare_page);
 		kfree(conf->disks);
 		kfree(conf->stripe_hashtbl);
 		kfree(conf);
@@ -2427,23 +3305,23 @@
 }
 
 #if RAID5_DEBUG
-static void print_sh (struct stripe_head *sh)
+static void print_sh (struct seq_file *seq, struct stripe_head *sh)
 {
 	int i;
 
-	printk("sh %llu, pd_idx %d, state %ld.\n",
-		(unsigned long long)sh->sector, sh->pd_idx, sh->state);
-	printk("sh %llu,  count %d.\n",
-		(unsigned long long)sh->sector, atomic_read(&sh->count));
-	printk("sh %llu, ", (unsigned long long)sh->sector);
+	seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n",
+		   (unsigned long long)sh->sector, sh->pd_idx, sh->state);
+	seq_printf(seq, "sh %llu,  count %d.\n",
+		   (unsigned long long)sh->sector, atomic_read(&sh->count));
+	seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector);
 	for (i = 0; i < sh->disks; i++) {
-		printk("(cache%d: %p %ld) ", 
-			i, sh->dev[i].page, sh->dev[i].flags);
+		seq_printf(seq, "(cache%d: %p %ld) ",
+			   i, sh->dev[i].page, sh->dev[i].flags);
 	}
-	printk("\n");
+	seq_printf(seq, "\n");
 }
 
-static void printall (raid5_conf_t *conf)
+static void printall (struct seq_file *seq, raid5_conf_t *conf)
 {
 	struct stripe_head *sh;
 	struct hlist_node *hn;
@@ -2454,7 +3332,7 @@
 		hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) {
 			if (sh->raid_conf != conf)
 				continue;
-			print_sh(sh);
+			print_sh(seq, sh);
 		}
 	}
 	spin_unlock_irq(&conf->device_lock);
@@ -2474,9 +3352,8 @@
 			       test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
 	seq_printf (seq, "]");
 #if RAID5_DEBUG
-#define D(x) \
-	seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x))
-	printall(conf);
+	seq_printf (seq, "\n");
+	printall(seq, conf);
 #endif
 }
 
@@ -2560,14 +3437,20 @@
 	int disk;
 	struct disk_info *p;
 
-	if (mddev->degraded > 1)
+	if (mddev->degraded > conf->max_degraded)
 		/* no point adding a device */
 		return 0;
 
 	/*
-	 * find the disk ...
+	 * find the disk ... but prefer rdev->saved_raid_disk
+	 * if possible.
 	 */
-	for (disk=0; disk < conf->raid_disks; disk++)
+	if (rdev->saved_raid_disk >= 0 &&
+	    conf->disks[rdev->saved_raid_disk].rdev == NULL)
+		disk = rdev->saved_raid_disk;
+	else
+		disk = 0;
+	for ( ; disk < conf->raid_disks; disk++)
 		if ((p=conf->disks + disk)->rdev == NULL) {
 			clear_bit(In_sync, &rdev->flags);
 			rdev->raid_disk = disk;
@@ -2590,8 +3473,10 @@
 	 * any io in the removed space completes, but it hardly seems
 	 * worth it.
 	 */
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+
 	sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
-	mddev->array_size = (sectors * (mddev->raid_disks-1))>>1;
+	mddev->array_size = (sectors * (mddev->raid_disks-conf->max_degraded))>>1;
 	set_capacity(mddev->gendisk, mddev->array_size << 1);
 	mddev->changed = 1;
 	if (sectors/2  > mddev->size && mddev->recovery_cp == MaxSector) {
@@ -2680,6 +3565,7 @@
 				set_bit(In_sync, &rdev->flags);
 				conf->working_disks++;
 				added_devices++;
+				rdev->recovery_offset = 0;
 				sprintf(nm, "rd%d", rdev->raid_disk);
 				sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
 			} else
@@ -2731,6 +3617,17 @@
 		conf->expand_progress = MaxSector;
 		spin_unlock_irq(&conf->device_lock);
 		conf->mddev->reshape_position = MaxSector;
+
+		/* read-ahead size must cover two whole stripes, which is
+		 * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
+		 */
+		{
+			int data_disks = conf->previous_raid_disks - conf->max_degraded;
+			int stripe = data_disks *
+				(conf->mddev->chunk_size / PAGE_SIZE);
+			if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+				conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+		}
 	}
 }
 
@@ -2762,6 +3659,23 @@
 	}
 }
 
+static struct mdk_personality raid6_personality =
+{
+	.name		= "raid6",
+	.level		= 6,
+	.owner		= THIS_MODULE,
+	.make_request	= make_request,
+	.run		= run,
+	.stop		= stop,
+	.status		= status,
+	.error_handler	= error,
+	.hot_add_disk	= raid5_add_disk,
+	.hot_remove_disk= raid5_remove_disk,
+	.spare_active	= raid5_spare_active,
+	.sync_request	= sync_request,
+	.resize		= raid5_resize,
+	.quiesce	= raid5_quiesce,
+};
 static struct mdk_personality raid5_personality =
 {
 	.name		= "raid5",
@@ -2804,6 +3718,12 @@
 
 static int __init raid5_init(void)
 {
+	int e;
+
+	e = raid6_select_algo();
+	if ( e )
+		return e;
+	register_md_personality(&raid6_personality);
 	register_md_personality(&raid5_personality);
 	register_md_personality(&raid4_personality);
 	return 0;
@@ -2811,6 +3731,7 @@
 
 static void raid5_exit(void)
 {
+	unregister_md_personality(&raid6_personality);
 	unregister_md_personality(&raid5_personality);
 	unregister_md_personality(&raid4_personality);
 }
@@ -2823,3 +3744,10 @@
 MODULE_ALIAS("md-raid4");
 MODULE_ALIAS("md-level-5");
 MODULE_ALIAS("md-level-4");
+MODULE_ALIAS("md-personality-8"); /* RAID6 */
+MODULE_ALIAS("md-raid6");
+MODULE_ALIAS("md-level-6");
+
+/* This used to be two separate modules, they were: */
+MODULE_ALIAS("raid5");
+MODULE_ALIAS("raid6");
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
deleted file mode 100644
index bc69355..0000000
--- a/drivers/md/raid6main.c
+++ /dev/null
@@ -1,2427 +0,0 @@
-/*
- * raid6main.c : Multiple Devices driver for Linux
- *	   Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman
- *	   Copyright (C) 1999, 2000 Ingo Molnar
- *	   Copyright (C) 2002, 2003 H. Peter Anvin
- *
- * RAID-6 management functions.  This code is derived from raid5.c.
- * Last merge from raid5.c bkcvs version 1.79 (kernel 2.6.1).
- *
- * Thanks to Penguin Computing for making the RAID-6 development possible
- * by donating a test server!
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/highmem.h>
-#include <linux/bitops.h>
-#include <asm/atomic.h>
-#include "raid6.h"
-
-#include <linux/raid/bitmap.h>
-
-/*
- * Stripe cache
- */
-
-#define NR_STRIPES		256
-#define STRIPE_SIZE		PAGE_SIZE
-#define STRIPE_SHIFT		(PAGE_SHIFT - 9)
-#define STRIPE_SECTORS		(STRIPE_SIZE>>9)
-#define	IO_THRESHOLD		1
-#define NR_HASH			(PAGE_SIZE / sizeof(struct hlist_head))
-#define HASH_MASK		(NR_HASH - 1)
-
-#define stripe_hash(conf, sect)	(&((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK]))
-
-/* bio's attached to a stripe+device for I/O are linked together in bi_sector
- * order without overlap.  There may be several bio's per stripe+device, and
- * a bio could span several devices.
- * When walking this list for a particular stripe+device, we must never proceed
- * beyond a bio that extends past this device, as the next bio might no longer
- * be valid.
- * This macro is used to determine the 'next' bio in the list, given the sector
- * of the current stripe+device
- */
-#define r5_next_bio(bio, sect) ( ( (bio)->bi_sector + ((bio)->bi_size>>9) < sect + STRIPE_SECTORS) ? (bio)->bi_next : NULL)
-/*
- * The following can be used to debug the driver
- */
-#define RAID6_DEBUG	0	/* Extremely verbose printk */
-#define RAID6_PARANOIA	1	/* Check spinlocks */
-#define RAID6_DUMPSTATE 0	/* Include stripe cache state in /proc/mdstat */
-#if RAID6_PARANOIA && defined(CONFIG_SMP)
-# define CHECK_DEVLOCK() assert_spin_locked(&conf->device_lock)
-#else
-# define CHECK_DEVLOCK()
-#endif
-
-#define PRINTK(x...) ((void)(RAID6_DEBUG && printk(KERN_DEBUG x)))
-#if RAID6_DEBUG
-#undef inline
-#undef __inline__
-#define inline
-#define __inline__
-#endif
-
-#if !RAID6_USE_EMPTY_ZERO_PAGE
-/* In .bss so it's zeroed */
-const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
-#endif
-
-static inline int raid6_next_disk(int disk, int raid_disks)
-{
-	disk++;
-	return (disk < raid_disks) ? disk : 0;
-}
-
-static void print_raid6_conf (raid6_conf_t *conf);
-
-static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
-{
-	if (atomic_dec_and_test(&sh->count)) {
-		BUG_ON(!list_empty(&sh->lru));
-		BUG_ON(atomic_read(&conf->active_stripes)==0);
-		if (test_bit(STRIPE_HANDLE, &sh->state)) {
-			if (test_bit(STRIPE_DELAYED, &sh->state))
-				list_add_tail(&sh->lru, &conf->delayed_list);
-			else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
-				 conf->seq_write == sh->bm_seq)
-				list_add_tail(&sh->lru, &conf->bitmap_list);
-			else {
-				clear_bit(STRIPE_BIT_DELAY, &sh->state);
-				list_add_tail(&sh->lru, &conf->handle_list);
-			}
-			md_wakeup_thread(conf->mddev->thread);
-		} else {
-			if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
-				atomic_dec(&conf->preread_active_stripes);
-				if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
-					md_wakeup_thread(conf->mddev->thread);
-			}
-			list_add_tail(&sh->lru, &conf->inactive_list);
-			atomic_dec(&conf->active_stripes);
-			if (!conf->inactive_blocked ||
-			    atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
-				wake_up(&conf->wait_for_stripe);
-		}
-	}
-}
-static void release_stripe(struct stripe_head *sh)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	unsigned long flags;
-
-	spin_lock_irqsave(&conf->device_lock, flags);
-	__release_stripe(conf, sh);
-	spin_unlock_irqrestore(&conf->device_lock, flags);
-}
-
-static inline void remove_hash(struct stripe_head *sh)
-{
-	PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector);
-
-	hlist_del_init(&sh->hash);
-}
-
-static inline void insert_hash(raid6_conf_t *conf, struct stripe_head *sh)
-{
-	struct hlist_head *hp = stripe_hash(conf, sh->sector);
-
-	PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector);
-
-	CHECK_DEVLOCK();
-	hlist_add_head(&sh->hash, hp);
-}
-
-
-/* find an idle stripe, make sure it is unhashed, and return it. */
-static struct stripe_head *get_free_stripe(raid6_conf_t *conf)
-{
-	struct stripe_head *sh = NULL;
-	struct list_head *first;
-
-	CHECK_DEVLOCK();
-	if (list_empty(&conf->inactive_list))
-		goto out;
-	first = conf->inactive_list.next;
-	sh = list_entry(first, struct stripe_head, lru);
-	list_del_init(first);
-	remove_hash(sh);
-	atomic_inc(&conf->active_stripes);
-out:
-	return sh;
-}
-
-static void shrink_buffers(struct stripe_head *sh, int num)
-{
-	struct page *p;
-	int i;
-
-	for (i=0; i<num ; i++) {
-		p = sh->dev[i].page;
-		if (!p)
-			continue;
-		sh->dev[i].page = NULL;
-		put_page(p);
-	}
-}
-
-static int grow_buffers(struct stripe_head *sh, int num)
-{
-	int i;
-
-	for (i=0; i<num; i++) {
-		struct page *page;
-
-		if (!(page = alloc_page(GFP_KERNEL))) {
-			return 1;
-		}
-		sh->dev[i].page = page;
-	}
-	return 0;
-}
-
-static void raid6_build_block (struct stripe_head *sh, int i);
-
-static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks, i;
-
-	BUG_ON(atomic_read(&sh->count) != 0);
-	BUG_ON(test_bit(STRIPE_HANDLE, &sh->state));
-
-	CHECK_DEVLOCK();
-	PRINTK("init_stripe called, stripe %llu\n",
-		(unsigned long long)sh->sector);
-
-	remove_hash(sh);
-
-	sh->sector = sector;
-	sh->pd_idx = pd_idx;
-	sh->state = 0;
-
-	for (i=disks; i--; ) {
-		struct r5dev *dev = &sh->dev[i];
-
-		if (dev->toread || dev->towrite || dev->written ||
-		    test_bit(R5_LOCKED, &dev->flags)) {
-			PRINTK("sector=%llx i=%d %p %p %p %d\n",
-			       (unsigned long long)sh->sector, i, dev->toread,
-			       dev->towrite, dev->written,
-			       test_bit(R5_LOCKED, &dev->flags));
-			BUG();
-		}
-		dev->flags = 0;
-		raid6_build_block(sh, i);
-	}
-	insert_hash(conf, sh);
-}
-
-static struct stripe_head *__find_stripe(raid6_conf_t *conf, sector_t sector)
-{
-	struct stripe_head *sh;
-	struct hlist_node *hn;
-
-	CHECK_DEVLOCK();
-	PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
-	hlist_for_each_entry (sh, hn,  stripe_hash(conf, sector), hash)
-		if (sh->sector == sector)
-			return sh;
-	PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
-	return NULL;
-}
-
-static void unplug_slaves(mddev_t *mddev);
-
-static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector,
-					     int pd_idx, int noblock)
-{
-	struct stripe_head *sh;
-
-	PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector);
-
-	spin_lock_irq(&conf->device_lock);
-
-	do {
-		wait_event_lock_irq(conf->wait_for_stripe,
-				    conf->quiesce == 0,
-				    conf->device_lock, /* nothing */);
-		sh = __find_stripe(conf, sector);
-		if (!sh) {
-			if (!conf->inactive_blocked)
-				sh = get_free_stripe(conf);
-			if (noblock && sh == NULL)
-				break;
-			if (!sh) {
-				conf->inactive_blocked = 1;
-				wait_event_lock_irq(conf->wait_for_stripe,
-						    !list_empty(&conf->inactive_list) &&
-						    (atomic_read(&conf->active_stripes)
-						     < (conf->max_nr_stripes *3/4)
-						     || !conf->inactive_blocked),
-						    conf->device_lock,
-						    unplug_slaves(conf->mddev);
-					);
-				conf->inactive_blocked = 0;
-			} else
-				init_stripe(sh, sector, pd_idx);
-		} else {
-			if (atomic_read(&sh->count)) {
-				BUG_ON(!list_empty(&sh->lru));
-			} else {
-				if (!test_bit(STRIPE_HANDLE, &sh->state))
-					atomic_inc(&conf->active_stripes);
-				BUG_ON(list_empty(&sh->lru));
-				list_del_init(&sh->lru);
-			}
-		}
-	} while (sh == NULL);
-
-	if (sh)
-		atomic_inc(&sh->count);
-
-	spin_unlock_irq(&conf->device_lock);
-	return sh;
-}
-
-static int grow_one_stripe(raid6_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(raid6_conf_t *conf, int num)
-{
-	kmem_cache_t *sc;
-	int devs = conf->raid_disks;
-
-	sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev));
-
-	sc = kmem_cache_create(conf->cache_name[0],
-			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
-			       0, 0, NULL, NULL);
-	if (!sc)
-		return 1;
-	conf->slab_cache = sc;
-	while (num--)
-		if (!grow_one_stripe(conf))
-			return 1;
-	return 0;
-}
-
-static int drop_one_stripe(raid6_conf_t *conf)
-{
-	struct stripe_head *sh;
-	spin_lock_irq(&conf->device_lock);
-	sh = get_free_stripe(conf);
-	spin_unlock_irq(&conf->device_lock);
-	if (!sh)
-		return 0;
-	BUG_ON(atomic_read(&sh->count));
-	shrink_buffers(sh, conf->raid_disks);
-	kmem_cache_free(conf->slab_cache, sh);
-	atomic_dec(&conf->active_stripes);
-	return 1;
-}
-
-static void shrink_stripes(raid6_conf_t *conf)
-{
-	while (drop_one_stripe(conf))
-		;
-
-	if (conf->slab_cache)
-		kmem_cache_destroy(conf->slab_cache);
-	conf->slab_cache = NULL;
-}
-
-static int raid6_end_read_request(struct bio * bi, unsigned int bytes_done,
-				  int error)
-{
- 	struct stripe_head *sh = bi->bi_private;
-	raid6_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks, i;
-	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
-
-	if (bi->bi_size)
-		return 1;
-
-	for (i=0 ; i<disks; i++)
-		if (bi == &sh->dev[i].req)
-			break;
-
-	PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n",
-		(unsigned long long)sh->sector, i, atomic_read(&sh->count),
-		uptodate);
-	if (i == disks) {
-		BUG();
-		return 0;
-	}
-
-	if (uptodate) {
-#if 0
-		struct bio *bio;
-		unsigned long flags;
-		spin_lock_irqsave(&conf->device_lock, flags);
-		/* we can return a buffer if we bypassed the cache or
-		 * if the top buffer is not in highmem.  If there are
-		 * multiple buffers, leave the extra work to
-		 * handle_stripe
-		 */
-		buffer = sh->bh_read[i];
-		if (buffer &&
-		    (!PageHighMem(buffer->b_page)
-		     || buffer->b_page == bh->b_page )
-			) {
-			sh->bh_read[i] = buffer->b_reqnext;
-			buffer->b_reqnext = NULL;
-		} else
-			buffer = NULL;
-		spin_unlock_irqrestore(&conf->device_lock, flags);
-		if (sh->bh_page[i]==bh->b_page)
-			set_buffer_uptodate(bh);
-		if (buffer) {
-			if (buffer->b_page != bh->b_page)
-				memcpy(buffer->b_data, bh->b_data, bh->b_size);
-			buffer->b_end_io(buffer, 1);
-		}
-#else
-		set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif
-		if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
-			printk(KERN_INFO "raid6: 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 {
-		int retry = 0;
-		clear_bit(R5_UPTODATE, &sh->dev[i].flags);
-		atomic_inc(&conf->disks[i].rdev->read_errors);
-		if (conf->mddev->degraded)
-			printk(KERN_WARNING "raid6: read error not correctable.\n");
-		else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
-			/* Oh, no!!! */
-			printk(KERN_WARNING "raid6: read error NOT corrected!!\n");
-		else if (atomic_read(&conf->disks[i].rdev->read_errors)
-			 > conf->max_nr_stripes)
-			printk(KERN_WARNING
-			       "raid6: 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
-	/* must restore b_page before unlocking buffer... */
-	if (sh->bh_page[i] != bh->b_page) {
-		bh->b_page = sh->bh_page[i];
-		bh->b_data = page_address(bh->b_page);
-		clear_buffer_uptodate(bh);
-	}
-#endif
-	clear_bit(R5_LOCKED, &sh->dev[i].flags);
-	set_bit(STRIPE_HANDLE, &sh->state);
-	release_stripe(sh);
-	return 0;
-}
-
-static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done,
-				    int error)
-{
- 	struct stripe_head *sh = bi->bi_private;
-	raid6_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks, i;
-	unsigned long flags;
-	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
-
-	if (bi->bi_size)
-		return 1;
-
-	for (i=0 ; i<disks; i++)
-		if (bi == &sh->dev[i].req)
-			break;
-
-	PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n",
-		(unsigned long long)sh->sector, i, atomic_read(&sh->count),
-		uptodate);
-	if (i == disks) {
-		BUG();
-		return 0;
-	}
-
-	spin_lock_irqsave(&conf->device_lock, flags);
-	if (!uptodate)
-		md_error(conf->mddev, conf->disks[i].rdev);
-
-	rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
-
-	clear_bit(R5_LOCKED, &sh->dev[i].flags);
-	set_bit(STRIPE_HANDLE, &sh->state);
-	__release_stripe(conf, sh);
-	spin_unlock_irqrestore(&conf->device_lock, flags);
-	return 0;
-}
-
-
-static sector_t compute_blocknr(struct stripe_head *sh, int i);
-
-static void raid6_build_block (struct stripe_head *sh, int i)
-{
-	struct r5dev *dev = &sh->dev[i];
-	int pd_idx = sh->pd_idx;
-	int qd_idx = raid6_next_disk(pd_idx, sh->raid_conf->raid_disks);
-
-	bio_init(&dev->req);
-	dev->req.bi_io_vec = &dev->vec;
-	dev->req.bi_vcnt++;
-	dev->req.bi_max_vecs++;
-	dev->vec.bv_page = dev->page;
-	dev->vec.bv_len = STRIPE_SIZE;
-	dev->vec.bv_offset = 0;
-
-	dev->req.bi_sector = sh->sector;
-	dev->req.bi_private = sh;
-
-	dev->flags = 0;
-	if (i != pd_idx && i != qd_idx)
-		dev->sector = compute_blocknr(sh, i);
-}
-
-static void error(mddev_t *mddev, mdk_rdev_t *rdev)
-{
-	char b[BDEVNAME_SIZE];
-	raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
-	PRINTK("raid6: error called\n");
-
-	if (!test_bit(Faulty, &rdev->flags)) {
-		mddev->sb_dirty = 1;
-		if (test_bit(In_sync, &rdev->flags)) {
-			conf->working_disks--;
-			mddev->degraded++;
-			conf->failed_disks++;
-			clear_bit(In_sync, &rdev->flags);
-			/*
-			 * if recovery was running, make sure it aborts.
-			 */
-			set_bit(MD_RECOVERY_ERR, &mddev->recovery);
-		}
-		set_bit(Faulty, &rdev->flags);
-		printk (KERN_ALERT
-			"raid6: Disk failure on %s, disabling device."
-			" Operation continuing on %d devices\n",
-			bdevname(rdev->bdev,b), conf->working_disks);
-	}
-}
-
-/*
- * Input: a 'big' sector number,
- * Output: index of the data and parity disk, and the sector # in them.
- */
-static sector_t raid6_compute_sector(sector_t r_sector, unsigned int raid_disks,
-			unsigned int data_disks, unsigned int * dd_idx,
-			unsigned int * pd_idx, raid6_conf_t *conf)
-{
-	long stripe;
-	unsigned long chunk_number;
-	unsigned int chunk_offset;
-	sector_t new_sector;
-	int sectors_per_chunk = conf->chunk_size >> 9;
-
-	/* First compute the information on this sector */
-
-	/*
-	 * Compute the chunk number and the sector offset inside the chunk
-	 */
-	chunk_offset = sector_div(r_sector, sectors_per_chunk);
-	chunk_number = r_sector;
-	if ( r_sector != chunk_number ) {
-		printk(KERN_CRIT "raid6: ERROR: r_sector = %llu, chunk_number = %lu\n",
-		       (unsigned long long)r_sector, (unsigned long)chunk_number);
-		BUG();
-	}
-
-	/*
-	 * Compute the stripe number
-	 */
-	stripe = chunk_number / data_disks;
-
-	/*
-	 * Compute the data disk and parity disk indexes inside the stripe
-	 */
-	*dd_idx = chunk_number % data_disks;
-
-	/*
-	 * Select the parity disk based on the user selected algorithm.
-	 */
-
-	/**** FIX THIS ****/
-	switch (conf->algorithm) {
-	case ALGORITHM_LEFT_ASYMMETRIC:
-		*pd_idx = raid_disks - 1 - (stripe % raid_disks);
-		if (*pd_idx == raid_disks-1)
-		  	(*dd_idx)++; 	/* Q D D D P */
-		else if (*dd_idx >= *pd_idx)
-		  	(*dd_idx) += 2; /* D D P Q D */
-		break;
-	case ALGORITHM_RIGHT_ASYMMETRIC:
-		*pd_idx = stripe % raid_disks;
-		if (*pd_idx == raid_disks-1)
-		  	(*dd_idx)++; 	/* Q D D D P */
-		else if (*dd_idx >= *pd_idx)
-		  	(*dd_idx) += 2; /* D D P Q D */
-		break;
-	case ALGORITHM_LEFT_SYMMETRIC:
-		*pd_idx = raid_disks - 1 - (stripe % raid_disks);
-		*dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
-		break;
-	case ALGORITHM_RIGHT_SYMMETRIC:
-		*pd_idx = stripe % raid_disks;
-		*dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
-		break;
-	default:
-		printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
-			conf->algorithm);
-	}
-
-	PRINTK("raid6: chunk_number = %lu, pd_idx = %u, dd_idx = %u\n",
-	       chunk_number, *pd_idx, *dd_idx);
-
-	/*
-	 * Finally, compute the new sector number
-	 */
-	new_sector = (sector_t) stripe * sectors_per_chunk + chunk_offset;
-	return new_sector;
-}
-
-
-static sector_t compute_blocknr(struct stripe_head *sh, int i)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	int raid_disks = conf->raid_disks, data_disks = raid_disks - 2;
-	sector_t new_sector = sh->sector, check;
-	int sectors_per_chunk = conf->chunk_size >> 9;
-	sector_t stripe;
-	int chunk_offset;
-	int chunk_number, dummy1, dummy2, dd_idx = i;
-	sector_t r_sector;
-	int i0 = i;
-
-	chunk_offset = sector_div(new_sector, sectors_per_chunk);
-	stripe = new_sector;
-	if ( new_sector != stripe ) {
-		printk(KERN_CRIT "raid6: ERROR: new_sector = %llu, stripe = %lu\n",
-		       (unsigned long long)new_sector, (unsigned long)stripe);
-		BUG();
-	}
-
-	switch (conf->algorithm) {
-		case ALGORITHM_LEFT_ASYMMETRIC:
-		case ALGORITHM_RIGHT_ASYMMETRIC:
-		  	if (sh->pd_idx == raid_disks-1)
-				i--; 	/* Q D D D P */
-			else if (i > sh->pd_idx)
-				i -= 2; /* D D P Q D */
-			break;
-		case ALGORITHM_LEFT_SYMMETRIC:
-		case ALGORITHM_RIGHT_SYMMETRIC:
-			if (sh->pd_idx == raid_disks-1)
-				i--; /* Q D D D P */
-			else {
-				/* D D P Q D */
-				if (i < sh->pd_idx)
-					i += raid_disks;
-				i -= (sh->pd_idx + 2);
-			}
-			break;
-		default:
-			printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
-				conf->algorithm);
-	}
-
-	PRINTK("raid6: compute_blocknr: pd_idx = %u, i0 = %u, i = %u\n", sh->pd_idx, i0, i);
-
-	chunk_number = stripe * data_disks + i;
-	r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset;
-
-	check = raid6_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf);
-	if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) {
-		printk(KERN_CRIT "raid6: compute_blocknr: map not correct\n");
-		return 0;
-	}
-	return r_sector;
-}
-
-
-
-/*
- * Copy data between a page in the stripe cache, and one or more bion
- * The page could align with the middle of the bio, or there could be
- * several bion, each with several bio_vecs, which cover part of the page
- * Multiple bion are linked together on bi_next.  There may be extras
- * at the end of this list.  We ignore them.
- */
-static void copy_data(int frombio, struct bio *bio,
-		     struct page *page,
-		     sector_t sector)
-{
-	char *pa = page_address(page);
-	struct bio_vec *bvl;
-	int i;
-	int page_offset;
-
-	if (bio->bi_sector >= sector)
-		page_offset = (signed)(bio->bi_sector - sector) * 512;
-	else
-		page_offset = (signed)(sector - bio->bi_sector) * -512;
-	bio_for_each_segment(bvl, bio, i) {
-		int len = bio_iovec_idx(bio,i)->bv_len;
-		int clen;
-		int b_offset = 0;
-
-		if (page_offset < 0) {
-			b_offset = -page_offset;
-			page_offset += b_offset;
-			len -= b_offset;
-		}
-
-		if (len > 0 && page_offset + len > STRIPE_SIZE)
-			clen = STRIPE_SIZE - page_offset;
-		else clen = len;
-
-		if (clen > 0) {
-			char *ba = __bio_kmap_atomic(bio, i, KM_USER0);
-			if (frombio)
-				memcpy(pa+page_offset, ba+b_offset, clen);
-			else
-				memcpy(ba+b_offset, pa+page_offset, clen);
-			__bio_kunmap_atomic(ba, KM_USER0);
-		}
-		if (clen < len) /* hit end of page */
-			break;
-		page_offset +=  len;
-	}
-}
-
-#define check_xor() 	do { 						\
-			   if (count == MAX_XOR_BLOCKS) {		\
-				xor_block(count, STRIPE_SIZE, ptr);	\
-				count = 1;				\
-			   }						\
-			} while(0)
-
-/* Compute P and Q syndromes */
-static void compute_parity(struct stripe_head *sh, int method)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count;
-	struct bio *chosen;
-	/**** FIX THIS: This could be very bad if disks is close to 256 ****/
-	void *ptrs[disks];
-
-	qd_idx = raid6_next_disk(pd_idx, disks);
-	d0_idx = raid6_next_disk(qd_idx, disks);
-
-	PRINTK("compute_parity, stripe %llu, method %d\n",
-		(unsigned long long)sh->sector, method);
-
-	switch(method) {
-	case READ_MODIFY_WRITE:
-		BUG();		/* READ_MODIFY_WRITE N/A for RAID-6 */
-	case RECONSTRUCT_WRITE:
-		for (i= disks; i-- ;)
-			if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) {
-				chosen = sh->dev[i].towrite;
-				sh->dev[i].towrite = NULL;
-
-				if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
-					wake_up(&conf->wait_for_overlap);
-
-				BUG_ON(sh->dev[i].written);
-				sh->dev[i].written = chosen;
-			}
-		break;
-	case CHECK_PARITY:
-		BUG();		/* Not implemented yet */
-	}
-
-	for (i = disks; i--;)
-		if (sh->dev[i].written) {
-			sector_t sector = sh->dev[i].sector;
-			struct bio *wbi = sh->dev[i].written;
-			while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) {
-				copy_data(1, wbi, sh->dev[i].page, sector);
-				wbi = r5_next_bio(wbi, sector);
-			}
-
-			set_bit(R5_LOCKED, &sh->dev[i].flags);
-			set_bit(R5_UPTODATE, &sh->dev[i].flags);
-		}
-
-//	switch(method) {
-//	case RECONSTRUCT_WRITE:
-//	case CHECK_PARITY:
-//	case UPDATE_PARITY:
-		/* Note that unlike RAID-5, the ordering of the disks matters greatly. */
-		/* FIX: Is this ordering of drives even remotely optimal? */
-		count = 0;
-		i = d0_idx;
-		do {
-			ptrs[count++] = page_address(sh->dev[i].page);
-			if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags))
-				printk("block %d/%d not uptodate on parity calc\n", i,count);
-			i = raid6_next_disk(i, disks);
-		} while ( i != d0_idx );
-//		break;
-//	}
-
-	raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs);
-
-	switch(method) {
-	case RECONSTRUCT_WRITE:
-		set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
-		set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
-		set_bit(R5_LOCKED,   &sh->dev[pd_idx].flags);
-		set_bit(R5_LOCKED,   &sh->dev[qd_idx].flags);
-		break;
-	case UPDATE_PARITY:
-		set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
-		set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
-		break;
-	}
-}
-
-/* Compute one missing block */
-static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	int i, count, disks = conf->raid_disks;
-	void *ptr[MAX_XOR_BLOCKS], *p;
-	int pd_idx = sh->pd_idx;
-	int qd_idx = raid6_next_disk(pd_idx, disks);
-
-	PRINTK("compute_block_1, stripe %llu, idx %d\n",
-		(unsigned long long)sh->sector, dd_idx);
-
-	if ( dd_idx == qd_idx ) {
-		/* We're actually computing the Q drive */
-		compute_parity(sh, UPDATE_PARITY);
-	} else {
-		ptr[0] = page_address(sh->dev[dd_idx].page);
-		if (!nozero) memset(ptr[0], 0, STRIPE_SIZE);
-		count = 1;
-		for (i = disks ; i--; ) {
-			if (i == dd_idx || i == qd_idx)
-				continue;
-			p = page_address(sh->dev[i].page);
-			if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
-				ptr[count++] = p;
-			else
-				printk("compute_block() %d, stripe %llu, %d"
-				       " not present\n", dd_idx,
-				       (unsigned long long)sh->sector, i);
-
-			check_xor();
-		}
-		if (count != 1)
-			xor_block(count, STRIPE_SIZE, ptr);
-		if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
-		else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
-	}
-}
-
-/* Compute two missing blocks */
-static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	int i, count, disks = conf->raid_disks;
-	int pd_idx = sh->pd_idx;
-	int qd_idx = raid6_next_disk(pd_idx, disks);
-	int d0_idx = raid6_next_disk(qd_idx, disks);
-	int faila, failb;
-
-	/* faila and failb are disk numbers relative to d0_idx */
-	/* pd_idx become disks-2 and qd_idx become disks-1 */
-	faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx;
-	failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx;
-
-	BUG_ON(faila == failb);
-	if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; }
-
-	PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
-	       (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb);
-
-	if ( failb == disks-1 ) {
-		/* Q disk is one of the missing disks */
-		if ( faila == disks-2 ) {
-			/* Missing P+Q, just recompute */
-			compute_parity(sh, UPDATE_PARITY);
-			return;
-		} else {
-			/* We're missing D+Q; recompute D from P */
-			compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0);
-			compute_parity(sh, UPDATE_PARITY); /* Is this necessary? */
-			return;
-		}
-	}
-
-	/* We're missing D+P or D+D; build pointer table */
-	{
-		/**** FIX THIS: This could be very bad if disks is close to 256 ****/
-		void *ptrs[disks];
-
-		count = 0;
-		i = d0_idx;
-		do {
-			ptrs[count++] = page_address(sh->dev[i].page);
-			i = raid6_next_disk(i, disks);
-			if (i != dd_idx1 && i != dd_idx2 &&
-			    !test_bit(R5_UPTODATE, &sh->dev[i].flags))
-				printk("compute_2 with missing block %d/%d\n", count, i);
-		} while ( i != d0_idx );
-
-		if ( failb == disks-2 ) {
-			/* We're missing D+P. */
-			raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs);
-		} else {
-			/* We're missing D+D. */
-			raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs);
-		}
-
-		/* Both the above update both missing blocks */
-		set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags);
-		set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags);
-	}
-}
-
-
-/*
- * Each stripe/dev can have one or more bion attached.
- * toread/towrite point to the first in a chain.
- * The bi_next chain must be in order.
- */
-static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite)
-{
-	struct bio **bip;
-	raid6_conf_t *conf = sh->raid_conf;
-	int firstwrite=0;
-
-	PRINTK("adding bh b#%llu to stripe s#%llu\n",
-		(unsigned long long)bi->bi_sector,
-		(unsigned long long)sh->sector);
-
-
-	spin_lock(&sh->lock);
-	spin_lock_irq(&conf->device_lock);
-	if (forwrite) {
-		bip = &sh->dev[dd_idx].towrite;
-		if (*bip == NULL && sh->dev[dd_idx].written == NULL)
-			firstwrite = 1;
-	} else
-		bip = &sh->dev[dd_idx].toread;
-	while (*bip && (*bip)->bi_sector < bi->bi_sector) {
-		if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector)
-			goto overlap;
-		bip = &(*bip)->bi_next;
-	}
-	if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9))
-		goto overlap;
-
-	BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next);
-	if (*bip)
-		bi->bi_next = *bip;
-	*bip = bi;
-	bi->bi_phys_segments ++;
-	spin_unlock_irq(&conf->device_lock);
-	spin_unlock(&sh->lock);
-
-	PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n",
-		(unsigned long long)bi->bi_sector,
-		(unsigned long long)sh->sector, dd_idx);
-
-	if (conf->mddev->bitmap && firstwrite) {
-		sh->bm_seq = conf->seq_write;
-		bitmap_startwrite(conf->mddev->bitmap, sh->sector,
-				  STRIPE_SECTORS, 0);
-		set_bit(STRIPE_BIT_DELAY, &sh->state);
-	}
-
-	if (forwrite) {
-		/* check if page is covered */
-		sector_t sector = sh->dev[dd_idx].sector;
-		for (bi=sh->dev[dd_idx].towrite;
-		     sector < sh->dev[dd_idx].sector + STRIPE_SECTORS &&
-			     bi && bi->bi_sector <= sector;
-		     bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) {
-			if (bi->bi_sector + (bi->bi_size>>9) >= sector)
-				sector = bi->bi_sector + (bi->bi_size>>9);
-		}
-		if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS)
-			set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags);
-	}
-	return 1;
-
- overlap:
-	set_bit(R5_Overlap, &sh->dev[dd_idx].flags);
-	spin_unlock_irq(&conf->device_lock);
-	spin_unlock(&sh->lock);
-	return 0;
-}
-
-
-static int page_is_zero(struct page *p)
-{
-	char *a = page_address(p);
-	return ((*(u32*)a) == 0 &&
-		memcmp(a, a+4, STRIPE_SIZE-4)==0);
-}
-/*
- * handle_stripe - do things to a stripe.
- *
- * We lock the stripe and then examine the state of various bits
- * to see what needs to be done.
- * Possible results:
- *    return some read request which now have data
- *    return some write requests which are safely on disc
- *    schedule a read on some buffers
- *    schedule a write of some buffers
- *    return confirmation of parity correctness
- *
- * Parity calculations are done inside the stripe lock
- * buffers are taken off read_list or write_list, and bh_cache buffers
- * get BH_Lock set before the stripe lock is released.
- *
- */
-
-static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
-{
-	raid6_conf_t *conf = sh->raid_conf;
-	int disks = conf->raid_disks;
-	struct bio *return_bi= NULL;
-	struct bio *bi;
-	int i;
-	int syncing;
-	int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
-	int non_overwrite = 0;
-	int failed_num[2] = {0, 0};
-	struct r5dev *dev, *pdev, *qdev;
-	int pd_idx = sh->pd_idx;
-	int qd_idx = raid6_next_disk(pd_idx, disks);
-	int p_failed, q_failed;
-
-	PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n",
-	       (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count),
-	       pd_idx, qd_idx);
-
-	spin_lock(&sh->lock);
-	clear_bit(STRIPE_HANDLE, &sh->state);
-	clear_bit(STRIPE_DELAYED, &sh->state);
-
-	syncing = test_bit(STRIPE_SYNCING, &sh->state);
-	/* Now to look around and see what can be done */
-
-	rcu_read_lock();
-	for (i=disks; i--; ) {
-		mdk_rdev_t *rdev;
-		dev = &sh->dev[i];
-		clear_bit(R5_Insync, &dev->flags);
-
-		PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
-			i, dev->flags, dev->toread, dev->towrite, dev->written);
-		/* maybe we can reply to a read */
-		if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) {
-			struct bio *rbi, *rbi2;
-			PRINTK("Return read for disc %d\n", i);
-			spin_lock_irq(&conf->device_lock);
-			rbi = dev->toread;
-			dev->toread = NULL;
-			if (test_and_clear_bit(R5_Overlap, &dev->flags))
-				wake_up(&conf->wait_for_overlap);
-			spin_unlock_irq(&conf->device_lock);
-			while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) {
-				copy_data(0, rbi, dev->page, dev->sector);
-				rbi2 = r5_next_bio(rbi, dev->sector);
-				spin_lock_irq(&conf->device_lock);
-				if (--rbi->bi_phys_segments == 0) {
-					rbi->bi_next = return_bi;
-					return_bi = rbi;
-				}
-				spin_unlock_irq(&conf->device_lock);
-				rbi = rbi2;
-			}
-		}
-
-		/* now count some things */
-		if (test_bit(R5_LOCKED, &dev->flags)) locked++;
-		if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++;
-
-
-		if (dev->toread) to_read++;
-		if (dev->towrite) {
-			to_write++;
-			if (!test_bit(R5_OVERWRITE, &dev->flags))
-				non_overwrite++;
-		}
-		if (dev->written) written++;
-		rdev = rcu_dereference(conf->disks[i].rdev);
-		if (!rdev || !test_bit(In_sync, &rdev->flags)) {
-			/* The ReadError flag will 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)) {
-			if ( failed < 2 )
-				failed_num[failed] = i;
-			failed++;
-		} else
-			set_bit(R5_Insync, &dev->flags);
-	}
-	rcu_read_unlock();
-	PRINTK("locked=%d uptodate=%d to_read=%d"
-	       " to_write=%d failed=%d failed_num=%d,%d\n",
-	       locked, uptodate, to_read, to_write, failed,
-	       failed_num[0], failed_num[1]);
-	/* check if the array has lost >2 devices and, if so, some requests might
-	 * need to be failed
-	 */
-	if (failed > 2 && 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;
-				rcu_read_lock();
-				rdev = rcu_dereference(conf->disks[i].rdev);
-				if (rdev && test_bit(In_sync, &rdev->flags))
-					/* multiple read failures in one stripe */
-					md_error(conf->mddev, rdev);
-				rcu_read_unlock();
-			}
-
-			spin_lock_irq(&conf->device_lock);
-			/* fail all writes first */
-			bi = sh->dev[i].towrite;
-			sh->dev[i].towrite = NULL;
-			if (bi) { to_write--; bitmap_end = 1; }
-
-			if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
-				wake_up(&conf->wait_for_overlap);
-
-			while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
-				struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
-				clear_bit(BIO_UPTODATE, &bi->bi_flags);
-				if (--bi->bi_phys_segments == 0) {
-					md_write_end(conf->mddev);
-					bi->bi_next = return_bi;
-					return_bi = bi;
-				}
-				bi = nextbi;
-			}
-			/* and fail all 'written' */
-			bi = sh->dev[i].written;
-			sh->dev[i].written = NULL;
-			if (bi) bitmap_end = 1;
-			while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) {
-				struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
-				clear_bit(BIO_UPTODATE, &bi->bi_flags);
-				if (--bi->bi_phys_segments == 0) {
-					md_write_end(conf->mddev);
-					bi->bi_next = return_bi;
-					return_bi = bi;
-				}
-				bi = bi2;
-			}
-
-			/* fail any reads if this device is non-operational */
-			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))
-					wake_up(&conf->wait_for_overlap);
-				if (bi) to_read--;
-				while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
-					struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
-					clear_bit(BIO_UPTODATE, &bi->bi_flags);
-					if (--bi->bi_phys_segments == 0) {
-						bi->bi_next = return_bi;
-						return_bi = bi;
-					}
-					bi = nextbi;
-				}
-			}
-			spin_unlock_irq(&conf->device_lock);
-			if (bitmap_end)
-				bitmap_endwrite(conf->mddev->bitmap, sh->sector,
-						STRIPE_SECTORS, 0, 0);
-		}
-	}
-	if (failed > 2 && syncing) {
-		md_done_sync(conf->mddev, STRIPE_SECTORS,0);
-		clear_bit(STRIPE_SYNCING, &sh->state);
-		syncing = 0;
-	}
-
-	/*
-	 * might be able to return some write requests if the parity blocks
-	 * are safe, or on a failed drive
-	 */
-	pdev = &sh->dev[pd_idx];
-	p_failed = (failed >= 1 && failed_num[0] == pd_idx)
-		|| (failed >= 2 && failed_num[1] == pd_idx);
-	qdev = &sh->dev[qd_idx];
-	q_failed = (failed >= 1 && failed_num[0] == qd_idx)
-		|| (failed >= 2 && failed_num[1] == qd_idx);
-
-	if ( written &&
-	     ( p_failed || ((test_bit(R5_Insync, &pdev->flags)
-			     && !test_bit(R5_LOCKED, &pdev->flags)
-			     && test_bit(R5_UPTODATE, &pdev->flags))) ) &&
-	     ( q_failed || ((test_bit(R5_Insync, &qdev->flags)
-			     && !test_bit(R5_LOCKED, &qdev->flags)
-			     && test_bit(R5_UPTODATE, &qdev->flags))) ) ) {
-		/* any written block on an uptodate or failed drive can be
-		 * returned.  Note that if we 'wrote' to a failed drive,
-		 * it will be UPTODATE, but never LOCKED, so we don't need
-		 * to test 'failed' directly.
-		 */
-		for (i=disks; i--; )
-			if (sh->dev[i].written) {
-				dev = &sh->dev[i];
-				if (!test_bit(R5_LOCKED, &dev->flags) &&
-				    test_bit(R5_UPTODATE, &dev->flags) ) {
-					/* We can return any write requests */
-					int bitmap_end = 0;
-					struct bio *wbi, *wbi2;
-					PRINTK("Return write for stripe %llu disc %d\n",
-					       (unsigned long long)sh->sector, i);
-					spin_lock_irq(&conf->device_lock);
-					wbi = dev->written;
-					dev->written = NULL;
-					while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {
-						wbi2 = r5_next_bio(wbi, dev->sector);
-						if (--wbi->bi_phys_segments == 0) {
-							md_write_end(conf->mddev);
-							wbi->bi_next = return_bi;
-							return_bi = wbi;
-						}
-						wbi = wbi2;
-					}
-					if (dev->towrite == NULL)
-						bitmap_end = 1;
-					spin_unlock_irq(&conf->device_lock);
-					if (bitmap_end)
-						bitmap_endwrite(conf->mddev->bitmap, sh->sector,
-								STRIPE_SECTORS,
-								!test_bit(STRIPE_DEGRADED, &sh->state), 0);
-				}
-			}
-	}
-
-	/* Now we might consider reading some blocks, either to check/generate
-	 * parity, or to satisfy requests
-	 * or to load a block that is being partially written.
-	 */
-	if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) {
-		for (i=disks; i--;) {
-			dev = &sh->dev[i];
-			if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
-			    (dev->toread ||
-			     (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
-			     syncing ||
-			     (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
-			     (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
-				    )
-				) {
-				/* we would like to get this block, possibly
-				 * by computing it, but we might not be able to
-				 */
-				if (uptodate == disks-1) {
-					PRINTK("Computing stripe %llu block %d\n",
-					       (unsigned long long)sh->sector, i);
-					compute_block_1(sh, i, 0);
-					uptodate++;
-				} else if ( uptodate == disks-2 && failed >= 2 ) {
-					/* Computing 2-failure is *very* expensive; only do it if failed >= 2 */
-					int other;
-					for (other=disks; other--;) {
-						if ( other == i )
-							continue;
-						if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) )
-							break;
-					}
-					BUG_ON(other < 0);
-					PRINTK("Computing stripe %llu blocks %d,%d\n",
-					       (unsigned long long)sh->sector, i, other);
-					compute_block_2(sh, i, other);
-					uptodate += 2;
-				} else if (test_bit(R5_Insync, &dev->flags)) {
-					set_bit(R5_LOCKED, &dev->flags);
-					set_bit(R5_Wantread, &dev->flags);
-#if 0
-					/* if I am just reading this block and we don't have
-					   a failed drive, or any pending writes then sidestep the cache */
-					if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
-					    ! syncing && !failed && !to_write) {
-						sh->bh_cache[i]->b_page =  sh->bh_read[i]->b_page;
-						sh->bh_cache[i]->b_data =  sh->bh_read[i]->b_data;
-					}
-#endif
-					locked++;
-					PRINTK("Reading block %d (sync=%d)\n",
-						i, syncing);
-				}
-			}
-		}
-		set_bit(STRIPE_HANDLE, &sh->state);
-	}
-
-	/* now to consider writing and what else, if anything should be read */
-	if (to_write) {
-		int rcw=0, must_compute=0;
-		for (i=disks ; i--;) {
-			dev = &sh->dev[i];
-			/* Would I have to read this buffer for reconstruct_write */
-			if (!test_bit(R5_OVERWRITE, &dev->flags)
-			    && i != pd_idx && i != qd_idx
-			    && (!test_bit(R5_LOCKED, &dev->flags)
-#if 0
-				|| sh->bh_page[i] != bh->b_page
-#endif
-				    ) &&
-			    !test_bit(R5_UPTODATE, &dev->flags)) {
-				if (test_bit(R5_Insync, &dev->flags)) rcw++;
-				else {
-					PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags);
-					must_compute++;
-				}
-			}
-		}
-		PRINTK("for sector %llu, rcw=%d, must_compute=%d\n",
-		       (unsigned long long)sh->sector, rcw, must_compute);
-		set_bit(STRIPE_HANDLE, &sh->state);
-
-		if (rcw > 0)
-			/* want reconstruct write, but need to get some data */
-			for (i=disks; i--;) {
-				dev = &sh->dev[i];
-				if (!test_bit(R5_OVERWRITE, &dev->flags)
-				    && !(failed == 0 && (i == pd_idx || i == qd_idx))
-				    && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
-				    test_bit(R5_Insync, &dev->flags)) {
-					if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
-					{
-						PRINTK("Read_old stripe %llu block %d for Reconstruct\n",
-						       (unsigned long long)sh->sector, i);
-						set_bit(R5_LOCKED, &dev->flags);
-						set_bit(R5_Wantread, &dev->flags);
-						locked++;
-					} else {
-						PRINTK("Request delayed stripe %llu block %d for Reconstruct\n",
-						       (unsigned long long)sh->sector, i);
-						set_bit(STRIPE_DELAYED, &sh->state);
-						set_bit(STRIPE_HANDLE, &sh->state);
-					}
-				}
-			}
-		/* now if nothing is locked, and if we have enough data, we can start a write request */
-		if (locked == 0 && rcw == 0 &&
-		    !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
-			if ( must_compute > 0 ) {
-				/* We have failed blocks and need to compute them */
-				switch ( failed ) {
-				case 0:	BUG();
-				case 1: compute_block_1(sh, failed_num[0], 0); break;
-				case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break;
-				default: BUG();	/* This request should have been failed? */
-				}
-			}
-
-			PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector);
-			compute_parity(sh, RECONSTRUCT_WRITE);
-			/* now every locked buffer is ready to be written */
-			for (i=disks; i--;)
-				if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
-					PRINTK("Writing stripe %llu block %d\n",
-					       (unsigned long long)sh->sector, i);
-					locked++;
-					set_bit(R5_Wantwrite, &sh->dev[i].flags);
-				}
-			/* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
-			set_bit(STRIPE_INSYNC, &sh->state);
-
-			if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
-				atomic_dec(&conf->preread_active_stripes);
-				if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
-					md_wakeup_thread(conf->mddev->thread);
-			}
-		}
-	}
-
-	/* maybe we need to check and possibly fix the parity for this stripe
-	 * Any reads will already have been scheduled, so we just see if enough data
-	 * is available
-	 */
-	if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) {
-		int update_p = 0, update_q = 0;
-		struct r5dev *dev;
-
-		set_bit(STRIPE_HANDLE, &sh->state);
-
-		BUG_ON(failed>2);
-		BUG_ON(uptodate < disks);
-		/* Want to check and possibly repair P and Q.
-		 * However there could be one 'failed' device, in which
-		 * case we can only check one of them, possibly using the
-		 * other to generate missing data
-		 */
-
-		/* If !tmp_page, we cannot do the calculations,
-		 * but as we have set STRIPE_HANDLE, we will soon be called
-		 * by stripe_handle with a tmp_page - just wait until then.
-		 */
-		if (tmp_page) {
-			if (failed == q_failed) {
-				/* The only possible failed device holds 'Q', so it makes
-				 * sense to check P (If anything else were failed, we would
-				 * have used P to recreate it).
-				 */
-				compute_block_1(sh, pd_idx, 1);
-				if (!page_is_zero(sh->dev[pd_idx].page)) {
-					compute_block_1(sh,pd_idx,0);
-					update_p = 1;
-				}
-			}
-			if (!q_failed && failed < 2) {
-				/* q is not failed, and we didn't use it to generate
-				 * anything, so it makes sense to check it
-				 */
-				memcpy(page_address(tmp_page),
-				       page_address(sh->dev[qd_idx].page),
-				       STRIPE_SIZE);
-				compute_parity(sh, UPDATE_PARITY);
-				if (memcmp(page_address(tmp_page),
-					   page_address(sh->dev[qd_idx].page),
-					   STRIPE_SIZE)!= 0) {
-					clear_bit(STRIPE_INSYNC, &sh->state);
-					update_q = 1;
-				}
-			}
-			if (update_p || update_q) {
-				conf->mddev->resync_mismatches += STRIPE_SECTORS;
-				if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
-					/* don't try to repair!! */
-					update_p = update_q = 0;
-			}
-
-			/* now write out any block on a failed drive,
-			 * or P or Q if they need it
-			 */
-
-			if (failed == 2) {
-				dev = &sh->dev[failed_num[1]];
-				locked++;
-				set_bit(R5_LOCKED, &dev->flags);
-				set_bit(R5_Wantwrite, &dev->flags);
-			}
-			if (failed >= 1) {
-				dev = &sh->dev[failed_num[0]];
-				locked++;
-				set_bit(R5_LOCKED, &dev->flags);
-				set_bit(R5_Wantwrite, &dev->flags);
-			}
-
-			if (update_p) {
-				dev = &sh->dev[pd_idx];
-				locked ++;
-				set_bit(R5_LOCKED, &dev->flags);
-				set_bit(R5_Wantwrite, &dev->flags);
-			}
-			if (update_q) {
-				dev = &sh->dev[qd_idx];
-				locked++;
-				set_bit(R5_LOCKED, &dev->flags);
-				set_bit(R5_Wantwrite, &dev->flags);
-			}
-			clear_bit(STRIPE_DEGRADED, &sh->state);
-
-			set_bit(STRIPE_INSYNC, &sh->state);
-		}
-	}
-
-	if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
-		md_done_sync(conf->mddev, STRIPE_SECTORS,1);
-		clear_bit(STRIPE_SYNCING, &sh->state);
-	}
-
-	/* If the failed drives are just a ReadError, then we might need
-	 * to progress the repair/check process
-	 */
-	if (failed <= 2 && ! conf->mddev->ro)
-		for (i=0; i<failed;i++) {
-			dev = &sh->dev[failed_num[i]];
-			if (test_bit(R5_ReadError, &dev->flags)
-			    && !test_bit(R5_LOCKED, &dev->flags)
-			    && test_bit(R5_UPTODATE, &dev->flags)
-				) {
-				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)) {
-		int bytes = bi->bi_size;
-
-		return_bi = bi->bi_next;
-		bi->bi_next = NULL;
-		bi->bi_size = 0;
-		bi->bi_end_io(bi, bytes, 0);
-	}
-	for (i=disks; i-- ;) {
-		int rw;
-		struct bio *bi;
-		mdk_rdev_t *rdev;
-		if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
-			rw = 1;
-		else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
-			rw = 0;
-		else
-			continue;
-
-		bi = &sh->dev[i].req;
-
-		bi->bi_rw = rw;
-		if (rw)
-			bi->bi_end_io = raid6_end_write_request;
-		else
-			bi->bi_end_io = raid6_end_read_request;
-
-		rcu_read_lock();
-		rdev = rcu_dereference(conf->disks[i].rdev);
-		if (rdev && test_bit(Faulty, &rdev->flags))
-			rdev = NULL;
-		if (rdev)
-			atomic_inc(&rdev->nr_pending);
-		rcu_read_unlock();
-
-		if (rdev) {
-			if (syncing)
-				md_sync_acct(rdev->bdev, STRIPE_SECTORS);
-
-			bi->bi_bdev = rdev->bdev;
-			PRINTK("for %llu schedule op %ld on disc %d\n",
-				(unsigned long long)sh->sector, bi->bi_rw, i);
-			atomic_inc(&sh->count);
-			bi->bi_sector = sh->sector + rdev->data_offset;
-			bi->bi_flags = 1 << BIO_UPTODATE;
-			bi->bi_vcnt = 1;
-			bi->bi_max_vecs = 1;
-			bi->bi_idx = 0;
-			bi->bi_io_vec = &sh->dev[i].vec;
-			bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
-			bi->bi_io_vec[0].bv_offset = 0;
-			bi->bi_size = STRIPE_SIZE;
-			bi->bi_next = NULL;
-			if (rw == WRITE &&
-			    test_bit(R5_ReWrite, &sh->dev[i].flags))
-				atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
-			generic_make_request(bi);
-		} else {
-			if (rw == 1)
-				set_bit(STRIPE_DEGRADED, &sh->state);
-			PRINTK("skip op %ld on disc %d for sector %llu\n",
-				bi->bi_rw, i, (unsigned long long)sh->sector);
-			clear_bit(R5_LOCKED, &sh->dev[i].flags);
-			set_bit(STRIPE_HANDLE, &sh->state);
-		}
-	}
-}
-
-static void raid6_activate_delayed(raid6_conf_t *conf)
-{
-	if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
-		while (!list_empty(&conf->delayed_list)) {
-			struct list_head *l = conf->delayed_list.next;
-			struct stripe_head *sh;
-			sh = list_entry(l, struct stripe_head, lru);
-			list_del_init(l);
-			clear_bit(STRIPE_DELAYED, &sh->state);
-			if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
-				atomic_inc(&conf->preread_active_stripes);
-			list_add_tail(&sh->lru, &conf->handle_list);
-		}
-	}
-}
-
-static void activate_bit_delay(raid6_conf_t *conf)
-{
-	/* device_lock is held */
-	struct list_head head;
-	list_add(&head, &conf->bitmap_list);
-	list_del_init(&conf->bitmap_list);
-	while (!list_empty(&head)) {
-		struct stripe_head *sh = list_entry(head.next, struct stripe_head, lru);
-		list_del_init(&sh->lru);
-		atomic_inc(&sh->count);
-		__release_stripe(conf, sh);
-	}
-}
-
-static void unplug_slaves(mddev_t *mddev)
-{
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-	int i;
-
-	rcu_read_lock();
-	for (i=0; i<mddev->raid_disks; i++) {
-		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);
-			rcu_read_unlock();
-
-			if (r_queue->unplug_fn)
-				r_queue->unplug_fn(r_queue);
-
-			rdev_dec_pending(rdev, mddev);
-			rcu_read_lock();
-		}
-	}
-	rcu_read_unlock();
-}
-
-static void raid6_unplug_device(request_queue_t *q)
-{
-	mddev_t *mddev = q->queuedata;
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&conf->device_lock, flags);
-
-	if (blk_remove_plug(q)) {
-		conf->seq_flush++;
-		raid6_activate_delayed(conf);
-	}
-	md_wakeup_thread(mddev->thread);
-
-	spin_unlock_irqrestore(&conf->device_lock, flags);
-
-	unplug_slaves(mddev);
-}
-
-static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
-			     sector_t *error_sector)
-{
-	mddev_t *mddev = q->queuedata;
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-	int i, ret = 0;
-
-	rcu_read_lock();
-	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-		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);
-
-			if (!r_queue->issue_flush_fn)
-				ret = -EOPNOTSUPP;
-			else {
-				atomic_inc(&rdev->nr_pending);
-				rcu_read_unlock();
-				ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
-							      error_sector);
-				rdev_dec_pending(rdev, mddev);
-				rcu_read_lock();
-			}
-		}
-	}
-	rcu_read_unlock();
-	return ret;
-}
-
-static inline void raid6_plug_device(raid6_conf_t *conf)
-{
-	spin_lock_irq(&conf->device_lock);
-	blk_plug_device(conf->mddev->queue);
-	spin_unlock_irq(&conf->device_lock);
-}
-
-static int make_request (request_queue_t *q, struct bio * bi)
-{
-	mddev_t *mddev = q->queuedata;
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-	const unsigned int raid_disks = conf->raid_disks;
-	const unsigned int data_disks = raid_disks - 2;
-	unsigned int dd_idx, pd_idx;
-	sector_t new_sector;
-	sector_t logical_sector, last_sector;
-	struct stripe_head *sh;
-	const int rw = bio_data_dir(bi);
-
-	if (unlikely(bio_barrier(bi))) {
-		bio_endio(bi, bi->bi_size, -EOPNOTSUPP);
-		return 0;
-	}
-
-	md_write_start(mddev, bi);
-
-	disk_stat_inc(mddev->gendisk, ios[rw]);
-	disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi));
-
-	logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
-	last_sector = bi->bi_sector + (bi->bi_size>>9);
-
-	bi->bi_next = NULL;
-	bi->bi_phys_segments = 1;	/* over-loaded to count active stripes */
-
-	for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
-		DEFINE_WAIT(w);
-
-		new_sector = raid6_compute_sector(logical_sector,
-						  raid_disks, data_disks, &dd_idx, &pd_idx, conf);
-
-		PRINTK("raid6: make_request, sector %llu logical %llu\n",
-		       (unsigned long long)new_sector,
-		       (unsigned long long)logical_sector);
-
-	retry:
-		prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
-		sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK));
-		if (sh) {
-			if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) {
-				/* Add failed due to overlap.  Flush everything
-				 * and wait a while
-				 */
-				raid6_unplug_device(mddev->queue);
-				release_stripe(sh);
-				schedule();
-				goto retry;
-			}
-			finish_wait(&conf->wait_for_overlap, &w);
-			raid6_plug_device(conf);
-			handle_stripe(sh, NULL);
-			release_stripe(sh);
-		} else {
-			/* cannot get stripe for read-ahead, just give-up */
-			clear_bit(BIO_UPTODATE, &bi->bi_flags);
-			finish_wait(&conf->wait_for_overlap, &w);
-			break;
-		}
-
-	}
-	spin_lock_irq(&conf->device_lock);
-	if (--bi->bi_phys_segments == 0) {
-		int bytes = bi->bi_size;
-
-		if (rw == WRITE )
-			md_write_end(mddev);
-		bi->bi_size = 0;
-		bi->bi_end_io(bi, bytes, 0);
-	}
-	spin_unlock_irq(&conf->device_lock);
-	return 0;
-}
-
-/* FIXME go_faster isn't used */
-static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
-{
-	raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
-	struct stripe_head *sh;
-	int sectors_per_chunk = conf->chunk_size >> 9;
-	sector_t x;
-	unsigned long stripe;
-	int chunk_offset;
-	int dd_idx, pd_idx;
-	sector_t first_sector;
-	int raid_disks = conf->raid_disks;
-	int data_disks = raid_disks - 2;
-	sector_t max_sector = mddev->size << 1;
-	int sync_blocks;
-	int still_degraded = 0;
-	int i;
-
-	if (sector_nr >= max_sector) {
-		/* just being told to finish up .. nothing much to do */
-		unplug_slaves(mddev);
-
-		if (mddev->curr_resync < max_sector) /* aborted */
-			bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
-					&sync_blocks, 1);
-		else /* completed sync */
-			conf->fullsync = 0;
-		bitmap_close_sync(mddev->bitmap);
-
-		return 0;
-	}
-	/* if there are 2 or more failed drives and we are trying
-	 * to resync, then assert that we are finished, because there is
-	 * nothing we can do.
-	 */
-	if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
-		sector_t rv = (mddev->size << 1) - sector_nr;
-		*skipped = 1;
-		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;
-		*skipped = 1;
-		return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
-	}
-
-	x = sector_nr;
-	chunk_offset = sector_div(x, sectors_per_chunk);
-	stripe = x;
-	BUG_ON(x != stripe);
-
-	first_sector = raid6_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk
-		+ chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
-	sh = get_active_stripe(conf, sector_nr, pd_idx, 1);
-	if (sh == NULL) {
-		sh = get_active_stripe(conf, sector_nr, pd_idx, 0);
-		/* make sure we don't swamp the stripe cache if someone else
-		 * is trying to get access
-		 */
-		schedule_timeout_uninterruptible(1);
-	}
-	/* Need to check if array will still be degraded after recovery/resync
-	 * We don't need to check the 'failed' flag as when that gets set,
-	 * recovery aborts.
-	 */
-	for (i=0; i<mddev->raid_disks; i++)
-		if (conf->disks[i].rdev == NULL)
-			still_degraded = 1;
-
-	bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
-
-	spin_lock(&sh->lock);
-	set_bit(STRIPE_SYNCING, &sh->state);
-	clear_bit(STRIPE_INSYNC, &sh->state);
-	spin_unlock(&sh->lock);
-
-	handle_stripe(sh, NULL);
-	release_stripe(sh);
-
-	return STRIPE_SECTORS;
-}
-
-/*
- * This is our raid6 kernel thread.
- *
- * We scan the hash table for stripes which can be handled now.
- * During the scan, completed stripes are saved for us by the interrupt
- * handler, so that they will not have to wait for our next wakeup.
- */
-static void raid6d (mddev_t *mddev)
-{
-	struct stripe_head *sh;
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-	int handled;
-
-	PRINTK("+++ raid6d active\n");
-
-	md_check_recovery(mddev);
-
-	handled = 0;
-	spin_lock_irq(&conf->device_lock);
-	while (1) {
-		struct list_head *first;
-
-		if (conf->seq_flush - conf->seq_write > 0) {
-			int seq = conf->seq_flush;
-			spin_unlock_irq(&conf->device_lock);
-			bitmap_unplug(mddev->bitmap);
-			spin_lock_irq(&conf->device_lock);
-			conf->seq_write = seq;
-			activate_bit_delay(conf);
-		}
-
-		if (list_empty(&conf->handle_list) &&
-		    atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD &&
-		    !blk_queue_plugged(mddev->queue) &&
-		    !list_empty(&conf->delayed_list))
-			raid6_activate_delayed(conf);
-
-		if (list_empty(&conf->handle_list))
-			break;
-
-		first = conf->handle_list.next;
-		sh = list_entry(first, struct stripe_head, lru);
-
-		list_del_init(first);
-		atomic_inc(&sh->count);
-		BUG_ON(atomic_read(&sh->count)!= 1);
-		spin_unlock_irq(&conf->device_lock);
-
-		handled++;
-		handle_stripe(sh, conf->spare_page);
-		release_stripe(sh);
-
-		spin_lock_irq(&conf->device_lock);
-	}
-	PRINTK("%d stripes handled\n", handled);
-
-	spin_unlock_irq(&conf->device_lock);
-
-	unplug_slaves(mddev);
-
-	PRINTK("--- raid6d inactive\n");
-}
-
-static ssize_t
-raid6_show_stripe_cache_size(mddev_t *mddev, char *page)
-{
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-	if (conf)
-		return sprintf(page, "%d\n", conf->max_nr_stripes);
-	else
-		return 0;
-}
-
-static ssize_t
-raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
-{
-	raid6_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
-raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
-				raid6_show_stripe_cache_size,
-				raid6_store_stripe_cache_size);
-
-static ssize_t
-stripe_cache_active_show(mddev_t *mddev, char *page)
-{
-	raid6_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
-raid6_stripecache_active = __ATTR_RO(stripe_cache_active);
-
-static struct attribute *raid6_attrs[] =  {
-	&raid6_stripecache_size.attr,
-	&raid6_stripecache_active.attr,
-	NULL,
-};
-static struct attribute_group raid6_attrs_group = {
-	.name = NULL,
-	.attrs = raid6_attrs,
-};
-
-static int run(mddev_t *mddev)
-{
-	raid6_conf_t *conf;
-	int raid_disk, memory;
-	mdk_rdev_t *rdev;
-	struct disk_info *disk;
-	struct list_head *tmp;
-
-	if (mddev->level != 6) {
-		PRINTK("raid6: %s: raid level not set to 6 (%d)\n", mdname(mddev), mddev->level);
-		return -EIO;
-	}
-
-	mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL);
-	if ((conf = mddev->private) == NULL)
-		goto abort;
-	conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info),
-				 GFP_KERNEL);
-	if (!conf->disks)
-		goto abort;
-
-	conf->mddev = mddev;
-
-	if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
-		goto abort;
-
-	conf->spare_page = alloc_page(GFP_KERNEL);
-	if (!conf->spare_page)
-		goto abort;
-
-	spin_lock_init(&conf->device_lock);
-	init_waitqueue_head(&conf->wait_for_stripe);
-	init_waitqueue_head(&conf->wait_for_overlap);
-	INIT_LIST_HEAD(&conf->handle_list);
-	INIT_LIST_HEAD(&conf->delayed_list);
-	INIT_LIST_HEAD(&conf->bitmap_list);
-	INIT_LIST_HEAD(&conf->inactive_list);
-	atomic_set(&conf->active_stripes, 0);
-	atomic_set(&conf->preread_active_stripes, 0);
-
-	PRINTK("raid6: run(%s) called.\n", mdname(mddev));
-
-	ITERATE_RDEV(mddev,rdev,tmp) {
-		raid_disk = rdev->raid_disk;
-		if (raid_disk >= mddev->raid_disks
-		    || raid_disk < 0)
-			continue;
-		disk = conf->disks + raid_disk;
-
-		disk->rdev = rdev;
-
-		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),
-			       raid_disk);
-			conf->working_disks++;
-		}
-	}
-
-	conf->raid_disks = mddev->raid_disks;
-
-	/*
-	 * 0 for a fully functional array, 1 or 2 for a degraded array.
-	 */
-	mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks;
-	conf->mddev = mddev;
-	conf->chunk_size = mddev->chunk_size;
-	conf->level = mddev->level;
-	conf->algorithm = mddev->layout;
-	conf->max_nr_stripes = NR_STRIPES;
-
-	/* device size must be a multiple of chunk size */
-	mddev->size &= ~(mddev->chunk_size/1024 -1);
-	mddev->resync_max_sectors = mddev->size << 1;
-
-	if (conf->raid_disks < 4) {
-		printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
-		       mdname(mddev), conf->raid_disks);
-		goto abort;
-	}
-	if (!conf->chunk_size || conf->chunk_size % 4) {
-		printk(KERN_ERR "raid6: invalid chunk size %d for %s\n",
-		       conf->chunk_size, mdname(mddev));
-		goto abort;
-	}
-	if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) {
-		printk(KERN_ERR
-		       "raid6: unsupported parity algorithm %d for %s\n",
-		       conf->algorithm, mdname(mddev));
-		goto abort;
-	}
-	if (mddev->degraded > 2) {
-		printk(KERN_ERR "raid6: not enough operational devices for %s"
-		       " (%d/%d failed)\n",
-		       mdname(mddev), conf->failed_disks, conf->raid_disks);
-		goto abort;
-	}
-
-	if (mddev->degraded > 0 &&
-	    mddev->recovery_cp != MaxSector) {
-		if (mddev->ok_start_degraded)
-			printk(KERN_WARNING "raid6: starting dirty degraded array:%s"
-			       "- data corruption possible.\n",
-			       mdname(mddev));
-		else {
-			printk(KERN_ERR "raid6: cannot start dirty degraded array"
-			       " for %s\n", mdname(mddev));
-			goto abort;
-		}
-	}
-
-	{
-		mddev->thread = md_register_thread(raid6d, mddev, "%s_raid6");
-		if (!mddev->thread) {
-			printk(KERN_ERR
-			       "raid6: couldn't allocate thread for %s\n",
-			       mdname(mddev));
-			goto abort;
-		}
-	}
-
-	memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
-		 conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
-	if (grow_stripes(conf, conf->max_nr_stripes)) {
-		printk(KERN_ERR
-		       "raid6: couldn't allocate %dkB for buffers\n", memory);
-		shrink_stripes(conf);
-		md_unregister_thread(mddev->thread);
-		goto abort;
-	} else
-		printk(KERN_INFO "raid6: allocated %dkB for %s\n",
-		       memory, mdname(mddev));
-
-	if (mddev->degraded == 0)
-		printk(KERN_INFO "raid6: raid level %d set %s active with %d out of %d"
-		       " devices, algorithm %d\n", conf->level, mdname(mddev),
-		       mddev->raid_disks-mddev->degraded, mddev->raid_disks,
-		       conf->algorithm);
-	else
-		printk(KERN_ALERT "raid6: raid level %d set %s active with %d"
-		       " out of %d devices, algorithm %d\n", conf->level,
-		       mdname(mddev), mddev->raid_disks - mddev->degraded,
-		       mddev->raid_disks, conf->algorithm);
-
-	print_raid6_conf(conf);
-
-	/* read-ahead size must cover two whole stripes, which is
-	 * 2 * (n-2) * chunksize where 'n' is the number of raid devices
-	 */
-	{
-		int stripe = (mddev->raid_disks-2) * mddev->chunk_size
-			/ PAGE_SIZE;
-		if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-			mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
-	}
-
-	/* Ok, everything is just fine now */
-	sysfs_create_group(&mddev->kobj, &raid6_attrs_group);
-
-	mddev->array_size =  mddev->size * (mddev->raid_disks - 2);
-
-	mddev->queue->unplug_fn = raid6_unplug_device;
-	mddev->queue->issue_flush_fn = raid6_issue_flush;
-	return 0;
-abort:
-	if (conf) {
-		print_raid6_conf(conf);
-		safe_put_page(conf->spare_page);
-		kfree(conf->stripe_hashtbl);
-		kfree(conf->disks);
-		kfree(conf);
-	}
-	mddev->private = NULL;
-	printk(KERN_ALERT "raid6: failed to run raid set %s\n", mdname(mddev));
-	return -EIO;
-}
-
-
-
-static int stop (mddev_t *mddev)
-{
-	raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
-
-	md_unregister_thread(mddev->thread);
-	mddev->thread = NULL;
-	shrink_stripes(conf);
-	kfree(conf->stripe_hashtbl);
-	blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
-	sysfs_remove_group(&mddev->kobj, &raid6_attrs_group);
-	kfree(conf);
-	mddev->private = NULL;
-	return 0;
-}
-
-#if RAID6_DUMPSTATE
-static void print_sh (struct seq_file *seq, struct stripe_head *sh)
-{
-	int i;
-
-	seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n",
-		   (unsigned long long)sh->sector, sh->pd_idx, sh->state);
-	seq_printf(seq, "sh %llu,  count %d.\n",
-		   (unsigned long long)sh->sector, atomic_read(&sh->count));
-	seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector);
-	for (i = 0; i < sh->raid_conf->raid_disks; i++) {
-		seq_printf(seq, "(cache%d: %p %ld) ",
-			   i, sh->dev[i].page, sh->dev[i].flags);
-	}
-	seq_printf(seq, "\n");
-}
-
-static void printall (struct seq_file *seq, raid6_conf_t *conf)
-{
-	struct stripe_head *sh;
-	struct hlist_node *hn;
-	int i;
-
-	spin_lock_irq(&conf->device_lock);
-	for (i = 0; i < NR_HASH; i++) {
-		sh = conf->stripe_hashtbl[i];
-		hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) {
-			if (sh->raid_conf != conf)
-				continue;
-			print_sh(seq, sh);
-		}
-	}
-	spin_unlock_irq(&conf->device_lock);
-}
-#endif
-
-static void status (struct seq_file *seq, mddev_t *mddev)
-{
-	raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
-	int i;
-
-	seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
-	seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks);
-	for (i = 0; i < conf->raid_disks; i++)
- 		seq_printf (seq, "%s",
-			    conf->disks[i].rdev &&
-			    test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
-	seq_printf (seq, "]");
-#if RAID6_DUMPSTATE
-	seq_printf (seq, "\n");
-	printall(seq, conf);
-#endif
-}
-
-static void print_raid6_conf (raid6_conf_t *conf)
-{
-	int i;
-	struct disk_info *tmp;
-
-	printk("RAID6 conf printout:\n");
-	if (!conf) {
-		printk("(conf==NULL)\n");
-		return;
-	}
-	printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks,
-		 conf->working_disks, conf->failed_disks);
-
-	for (i = 0; i < conf->raid_disks; i++) {
-		char b[BDEVNAME_SIZE];
-		tmp = conf->disks + i;
-		if (tmp->rdev)
-		printk(" disk %d, o:%d, dev:%s\n",
-			i, !test_bit(Faulty, &tmp->rdev->flags),
-			bdevname(tmp->rdev->bdev,b));
-	}
-}
-
-static int raid6_spare_active(mddev_t *mddev)
-{
-	int i;
-	raid6_conf_t *conf = mddev->private;
-	struct disk_info *tmp;
-
-	for (i = 0; i < conf->raid_disks; i++) {
-		tmp = conf->disks + i;
-		if (tmp->rdev
-		    && !test_bit(Faulty, &tmp->rdev->flags)
-		    && !test_bit(In_sync, &tmp->rdev->flags)) {
-			mddev->degraded--;
-			conf->failed_disks--;
-			conf->working_disks++;
-			set_bit(In_sync, &tmp->rdev->flags);
-		}
-	}
-	print_raid6_conf(conf);
-	return 0;
-}
-
-static int raid6_remove_disk(mddev_t *mddev, int number)
-{
-	raid6_conf_t *conf = mddev->private;
-	int err = 0;
-	mdk_rdev_t *rdev;
-	struct disk_info *p = conf->disks + number;
-
-	print_raid6_conf(conf);
-	rdev = p->rdev;
-	if (rdev) {
-		if (test_bit(In_sync, &rdev->flags) ||
-		    atomic_read(&rdev->nr_pending)) {
-			err = -EBUSY;
-			goto abort;
-		}
-		p->rdev = NULL;
-		synchronize_rcu();
-		if (atomic_read(&rdev->nr_pending)) {
-			/* lost the race, try later */
-			err = -EBUSY;
-			p->rdev = rdev;
-		}
-	}
-
-abort:
-
-	print_raid6_conf(conf);
-	return err;
-}
-
-static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
-{
-	raid6_conf_t *conf = mddev->private;
-	int found = 0;
-	int disk;
-	struct disk_info *p;
-
-	if (mddev->degraded > 2)
-		/* no point adding a device */
-		return 0;
-	/*
-	 * find the disk ... but prefer rdev->saved_raid_disk
-	 * if possible.
-	 */
-	if (rdev->saved_raid_disk >= 0 &&
-	    conf->disks[rdev->saved_raid_disk].rdev == NULL)
-		disk = rdev->saved_raid_disk;
-	else
-		disk = 0;
-	for ( ; disk < mddev->raid_disks; disk++)
-		if ((p=conf->disks + disk)->rdev == NULL) {
-			clear_bit(In_sync, &rdev->flags);
-			rdev->raid_disk = disk;
-			found = 1;
-			if (rdev->saved_raid_disk != disk)
-				conf->fullsync = 1;
-			rcu_assign_pointer(p->rdev, rdev);
-			break;
-		}
-	print_raid6_conf(conf);
-	return found;
-}
-
-static int raid6_resize(mddev_t *mddev, sector_t sectors)
-{
-	/* no resync is happening, and there is enough space
-	 * on all devices, so we can resize.
-	 * We need to make sure resync covers any new space.
-	 * If the array is shrinking we should possibly wait until
-	 * any io in the removed space completes, but it hardly seems
-	 * worth it.
-	 */
-	sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
-	mddev->array_size = (sectors * (mddev->raid_disks-2))>>1;
-	set_capacity(mddev->gendisk, mddev->array_size << 1);
-	mddev->changed = 1;
-	if (sectors/2  > mddev->size && mddev->recovery_cp == MaxSector) {
-		mddev->recovery_cp = mddev->size << 1;
-		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-	}
-	mddev->size = sectors /2;
-	mddev->resync_max_sectors = sectors;
-	return 0;
-}
-
-static void raid6_quiesce(mddev_t *mddev, int state)
-{
-	raid6_conf_t *conf = mddev_to_conf(mddev);
-
-	switch(state) {
-	case 1: /* stop all writes */
-		spin_lock_irq(&conf->device_lock);
-		conf->quiesce = 1;
-		wait_event_lock_irq(conf->wait_for_stripe,
-				    atomic_read(&conf->active_stripes) == 0,
-				    conf->device_lock, /* nothing */);
-		spin_unlock_irq(&conf->device_lock);
-		break;
-
-	case 0: /* re-enable writes */
-		spin_lock_irq(&conf->device_lock);
-		conf->quiesce = 0;
-		wake_up(&conf->wait_for_stripe);
-		spin_unlock_irq(&conf->device_lock);
-		break;
-	}
-}
-
-static struct mdk_personality raid6_personality =
-{
-	.name		= "raid6",
-	.level		= 6,
-	.owner		= THIS_MODULE,
-	.make_request	= make_request,
-	.run		= run,
-	.stop		= stop,
-	.status		= status,
-	.error_handler	= error,
-	.hot_add_disk	= raid6_add_disk,
-	.hot_remove_disk= raid6_remove_disk,
-	.spare_active	= raid6_spare_active,
-	.sync_request	= sync_request,
-	.resize		= raid6_resize,
-	.quiesce	= raid6_quiesce,
-};
-
-static int __init raid6_init(void)
-{
-	int e;
-
-	e = raid6_select_algo();
-	if ( e )
-		return e;
-
-	return register_md_personality(&raid6_personality);
-}
-
-static void raid6_exit (void)
-{
-	unregister_md_personality(&raid6_personality);
-}
-
-module_init(raid6_init);
-module_exit(raid6_exit);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("md-personality-8"); /* RAID6 */
-MODULE_ALIAS("md-raid6");
-MODULE_ALIAS("md-level-6");
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 344d83a..ef52e6d 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -25,7 +25,7 @@
 	  module will be called videodev.
 
 config VIDEO_V4L1
-	boolean "Enable Video For Linux API 1 (DEPRECATED)"
+	bool "Enable Video For Linux API 1 (DEPRECATED)"
 	depends on VIDEO_DEV
 	select VIDEO_V4L1_COMPAT
 	default y
@@ -36,7 +36,7 @@
 	  If you are unsure as to whether this is required, answer Y.
 
 config VIDEO_V4L1_COMPAT
-	boolean "Enable Video For Linux API 1 compatible Layer"
+	bool "Enable Video For Linux API 1 compatible Layer"
 	depends on VIDEO_DEV
 	default y
 	---help---
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 61b8961..8e74482 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,5 @@
 saa7146-objs    := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
 ir-common-objs  := ir-functions.o ir-keymaps.o
 
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 397cff8..8eaa88f 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -269,4 +269,3 @@
  * c-basic-offset: 8
  * End:
  */
-
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index a294d5c..ca98d94 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -618,7 +618,7 @@
 
 EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
 
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
 	[ 0x3a ] = KEY_0,
 	[ 0x31 ] = KEY_1,
 	[ 0x32 ] = KEY_2,
@@ -670,7 +670,7 @@
 	[ 0x27 ] = KEY_RECORD,
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
 
 IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
 	[ 0x0f ] = KEY_0,
@@ -1263,34 +1263,51 @@
 	[ 0x0f ] = KEY_9,
 
 	[ 0x00 ] = KEY_POWER,
-	[ 0x02 ] = KEY_TUNER,		/* TV/FM */
-	[ 0x1e ] = KEY_VIDEO,
+	[ 0x1b ] = KEY_AUDIO,           /* Audio Source */
+	[ 0x02 ] = KEY_TUNER,		/* TV/FM, not on Y0400052 */
+	[ 0x1e ] = KEY_VIDEO,           /* Video Source */
+	[ 0x16 ] = KEY_INFO,            /* Display information */
 	[ 0x04 ] = KEY_VOLUMEUP,
 	[ 0x08 ] = KEY_VOLUMEDOWN,
 	[ 0x0c ] = KEY_CHANNELUP,
 	[ 0x10 ] = KEY_CHANNELDOWN,
 	[ 0x03 ] = KEY_ZOOM,		/* fullscreen */
-	[ 0x1f ] = KEY_SUBTITLE,		/* closed caption/teletext */
+	[ 0x1f ] = KEY_TEXT,		/* closed caption/teletext */
 	[ 0x20 ] = KEY_SLEEP,
+	[ 0x29 ] = KEY_CLEAR,           /* boss key */
 	[ 0x14 ] = KEY_MUTE,
 	[ 0x2b ] = KEY_RED,
 	[ 0x2c ] = KEY_GREEN,
 	[ 0x2d ] = KEY_YELLOW,
 	[ 0x2e ] = KEY_BLUE,
-	[ 0x18 ] = KEY_KPPLUS,		/* fine tune + */
-	[ 0x19 ] = KEY_KPMINUS,		/* fine tune - */
+	[ 0x18 ] = KEY_KPPLUS,		/* fine tune + , not on Y040052 */
+	[ 0x19 ] = KEY_KPMINUS,		/* fine tune - , not on Y040052 */
+	[ 0x2a ] = KEY_MEDIA,           /* PIP (Picture in picture */
 	[ 0x21 ] = KEY_DOT,
 	[ 0x13 ] = KEY_ENTER,
-	[ 0x22 ] = KEY_BACK,
+	[ 0x11 ] = KEY_LAST,            /* Recall (last channel */
+	[ 0x22 ] = KEY_PREVIOUS,
 	[ 0x23 ] = KEY_PLAYPAUSE,
 	[ 0x24 ] = KEY_NEXT,
+	[ 0x25 ] = KEY_ARCHIVE,       /* Time Shifting */
 	[ 0x26 ] = KEY_STOP,
-	[ 0x27 ] = KEY_RECORD
+	[ 0x27 ] = KEY_RECORD,
+	[ 0x28 ] = KEY_SAVE,          /* Screenshot */
+	[ 0x2f ] = KEY_MENU,
+	[ 0x30 ] = KEY_CANCEL,
+	[ 0x31 ] = KEY_CHANNEL,       /* Channel Surf */
+	[ 0x32 ] = KEY_SUBTITLE,
+	[ 0x33 ] = KEY_LANGUAGE,
+	[ 0x34 ] = KEY_REWIND,
+	[ 0x35 ] = KEY_FASTFORWARD,
+	[ 0x36 ] = KEY_TV,
+	[ 0x37 ] = KEY_RADIO,         /* FM */
+	[ 0x38 ] = KEY_DVD
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
 
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
 	[ 0x59 ] = KEY_MUTE,
 	[ 0x4a ] = KEY_POWER,
 
@@ -1348,7 +1365,7 @@
 	[ 0x0a ] = KEY_BACKSPACE,
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
 
 /* Hauppauge: the newer, gray remotes (seems there are multiple
  * slightly different versions), shipped with cx88+ivtv cards.
@@ -1413,3 +1430,46 @@
 
 EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
 
+IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
+	[ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+	[ 0x2a ] = KEY_FRONT,
+
+	[ 0x3e ] = KEY_1,
+	[ 0x02 ] = KEY_2,
+	[ 0x06 ] = KEY_3,
+	[ 0x0a ] = KEY_4,
+	[ 0x0e ] = KEY_5,
+	[ 0x12 ] = KEY_6,
+	[ 0x16 ] = KEY_7,
+	[ 0x1a ] = KEY_8,
+	[ 0x1e ] = KEY_9,
+	[ 0x3a ] = KEY_0,
+	[ 0x22 ] = KEY_NUMLOCK,         /* -/-- */
+	[ 0x20 ] = KEY_REFRESH,
+
+	[ 0x03 ] = KEY_BRIGHTNESSDOWN,
+	[ 0x28 ] = KEY_AUDIO,
+	[ 0x3c ] = KEY_UP,
+	[ 0x3f ] = KEY_LEFT,
+	[ 0x2e ] = KEY_MUTE,
+	[ 0x3b ] = KEY_RIGHT,
+	[ 0x00 ] = KEY_DOWN,
+	[ 0x07 ] = KEY_BRIGHTNESSUP,
+	[ 0x2c ] = KEY_TEXT,
+
+	[ 0x37 ] = KEY_RECORD,
+	[ 0x17 ] = KEY_PLAY,
+	[ 0x13 ] = KEY_PAUSE,
+	[ 0x26 ] = KEY_STOP,
+	[ 0x18 ] = KEY_FASTFORWARD,
+	[ 0x14 ] = KEY_REWIND,
+	[ 0x33 ] = KEY_ZOOM,
+	[ 0x32 ] = KEY_KEYBOARD,
+	[ 0x30 ] = KEY_GOTO,            /* Pointing arrow */
+	[ 0x36 ] = KEY_MACRO,           /* Maximize/Minimize (yellow) */
+	[ 0x0b ] = KEY_RADIO,
+	[ 0x10 ] = KEY_POWER,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_npgtech);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 523ab38..0027acc 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -501,6 +501,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
 
 int saa7146_vv_release(struct saa7146_dev* dev)
 {
@@ -515,6 +516,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
 
 int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 			    char *name, int type)
@@ -553,6 +555,7 @@
 	*vid = vfd;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_register_device);
 
 int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
 {
@@ -571,6 +574,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
 
 static int __init saa7146_vv_init_module(void)
 {
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index 33bec8a..2092e6c 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -641,6 +641,7 @@
 	vv->current_hps_source = source;
 	vv->current_hps_sync = sync;
 }
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
 
 int saa7146_enable_overlay(struct saa7146_fh *fh)
 {
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e7079d1..8393d47 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -318,6 +318,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
 
 int saa7146_stop_preview(struct saa7146_fh *fh)
 {
@@ -352,6 +353,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
 
 static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
 {
diff --git a/drivers/media/common/saa7146_vv_ksyms.c b/drivers/media/common/saa7146_vv_ksyms.c
deleted file mode 100644
index 62226eb..0000000
--- a/drivers/media/common/saa7146_vv_ksyms.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <linux/module.h>
-#include <media/saa7146_vv.h>
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 9c7f122..3be87c7 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -14,6 +14,7 @@
 #include "stv0297.h"
 #include "mt312.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
 #include "dvb-pll.h"
 
 /* lnb control */
@@ -166,11 +167,12 @@
 	return 0;
 }
 
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	u8 buf[4];
 	u32 div;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct flexcop_device *fc = fe->dvb->priv;
 
 	div = params->frequency / 125;
 
@@ -181,8 +183,11 @@
 
 	if (params->frequency < 1500000) buf[3] |= 0x10;
 
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
 		return -EIO;
+	}
 	return 0;
 }
 
@@ -241,7 +246,6 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
-	.pll_set = samsung_tbmu24112_pll_set,
 };
 
 /* dvb-t mt352 */
@@ -264,11 +268,14 @@
 	return 0;
 }
 
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	unsigned char bs = 0;
 
+	if (buf_len < 5)
+		return -EINVAL;
+
 	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
@@ -276,19 +283,18 @@
 	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
 	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
 
-	pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+	pllbuf[0] = 0x61;
 	pllbuf[1] = div >> 8;
 	pllbuf[2] = div & 0xff;
 	pllbuf[3] = 0xcc;
 	pllbuf[4] = bs;
 
-	return 0;
+	return 5;
 }
 
 static struct mt352_config samsung_tdtc9251dh0_config = {
 	.demod_address = 0x0f,
 	.demod_init    = samsung_tdtc9251dh0_demod_init,
-	.pll_set       = samsung_tdtc9251dh0_pll_set,
 };
 
 static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
@@ -297,56 +303,21 @@
 	return request_firmware(fw, name, fc->dev);
 }
 
-static int lgdt3303_pll_set(struct dvb_frontend* fe,
-			    struct dvb_frontend_parameters* params)
+static int lgdt3303_tuner_set_params(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;
+	return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
 }
 
 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 nxt200x_config samsung_tbmv_config = {
 	.demod_address    = 0x0a,
-	.pll_address      = 0xc2,
-	.pll_desc         = &dvb_pll_samsung_tbmv,
 };
 
 static struct bcm3510_config air2pc_atsc_first_gen_config = {
@@ -354,7 +325,7 @@
 	.request_firmware = flexcop_fe_request_firmware,
 };
 
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	u8 buf[4];
 	u32 div;
@@ -371,6 +342,8 @@
 	if (params->frequency < 1550000)
 		buf[3] |= 0x02;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -379,9 +352,52 @@
 static struct mt312_config skystar23_samsung_tbdu18132_config = {
 
 	.demod_address = 0x0e,
-	.pll_set = skystar23_samsung_tbdu18132_pll_set,
 };
 
+static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
+					       struct dvb_frontend_parameters *fep)
+{
+	struct flexcop_device *fc = fe->dvb->priv;
+	u8 buf[4];
+	u16 div;
+	int ret;
+
+/*  62.5 kHz * 10 */
+#define REF_FREQ    625
+#define FREQ_OFFSET 36125
+
+	div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
+
+	buf[0] = (u8)( div >> 8) & 0x7f;
+	buf[1] = (u8)        div & 0xff;
+
+/* F(osc) = N * Reference Freq. (62.5 kHz)
+ * byte 2 :  0 N14 N13 N12 N11 N10 N9  N8
+ * byte 3 : N7 N6  N5  N4  N3  N2  N1  N0
+ * byte 4 : 1  *   *   AGD R3  R2  R1  R0
+ * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
+	buf[2] = 0x95;
+
+// Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+//  47 - 153   0  *  0   0   0   0   0   1   0x01
+// 153 - 430   0  *  0   0   0   0   1   0   0x02
+// 430 - 822   0  *  0   0   1   0   0   0   0x08
+// 822 - 862   1  *  0   0   1   0   0   0   0x88
+
+	     if (fep->frequency <= 153000000) buf[3] = 0x01;
+	else if (fep->frequency <= 430000000) buf[3] = 0x02;
+	else if (fep->frequency <= 822000000) buf[3] = 0x08;
+	else buf[3] = 0x88;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+	ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+	deb_tuner("tuner write returned: %d\n",ret);
+
+	return 0;
+}
 
 static u8 alps_tdee4_stv0297_inittab[] = {
 	0x80, 0x01,
@@ -490,7 +506,9 @@
 
 	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
 	if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
-		ops = fc->fe->ops;
+		ops = &fc->fe->ops;
+
+		ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
 
 		ops->set_voltage = flexcop_set_voltage;
 
@@ -503,16 +521,19 @@
 	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
 	if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
 		fc->dev_type          = FC_AIR_DVB;
+		fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
 		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
 	} else
 	/* try the air atsc 2nd generation (nxt2002) */
 	if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC2;
+		dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
 		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;
+		fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
 		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 */
@@ -523,11 +544,14 @@
 	/* try the cable dvb (stv0297) */
 	if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type                        = FC_CABLE;
+		fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
 		info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
 	} else
 	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
 	if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
-		ops = fc->fe->ops;
+		ops = &fc->fe->ops;
+
+		ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
 
 		ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
 		ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
@@ -547,7 +571,7 @@
 	} else {
 		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
 			err("frontend registration failed!");
-			ops = fc->fe->ops;
+			ops = &fc->fe->ops;
 			if (ops->release != NULL)
 				ops->release(fc->fe);
 			fc->fe = NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 9bc40bd..f0404170 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -242,19 +242,16 @@
 	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
 		return ret;
 
-	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
-		goto dma1_free;
+	if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+		flexcop_dma_free(&fc_pci->dma[0]);
+		return ret;
+	}
 
 	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
 	flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO   | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
 
 	fc_pci->init_state |= FC_PCI_DMA_INIT;
 
-	goto success;
-dma1_free:
-	flexcop_dma_free(&fc_pci->dma[0]);
-
-success:
 	return ret;
 }
 
@@ -303,7 +300,7 @@
 	spin_lock_init(&fc_pci->irq_lock);
 
 	fc_pci->init_state |= FC_PCI_INIT;
-	goto success;
+	return ret;
 
 err_pci_iounmap:
 	pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
@@ -312,8 +309,6 @@
 	pci_release_regions(fc_pci->pdev);
 err_pci_disable_device:
 	pci_disable_device(fc_pci->pdev);
-
-success:
 	return ret;
 }
 
@@ -378,14 +373,14 @@
 
 	INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
 
-	goto success;
+	return ret;
+
 err_fc_exit:
 	flexcop_device_exit(fc);
 err_pci_exit:
 	flexcop_pci_exit(fc_pci);
 err_kfree:
 	flexcop_device_kfree(fc);
-success:
 	return ret;
 }
 
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 06ec9fff..515954f 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -433,11 +433,10 @@
 	flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
 	flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
 
-	ret = 0;
-	goto success;
+	return 0;
+
 urb_error:
 	flexcop_usb_transfer_exit(fc_usb);
-success:
 	return ret;
 }
 
@@ -515,15 +514,14 @@
 		goto err_fc_exit;
 
 	info("%s successfully initialized and connected.",DRIVER_NAME);
-	ret = 0;
-	goto success;
+	return 0;
+
 err_fc_exit:
 	flexcop_device_exit(fc);
 err_usb_exit:
 	flexcop_usb_exit(fc_usb);
 err_kfree:
 	flexcop_device_kfree(fc);
-success:
 	return ret;
 }
 
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 56ba524..29ec418 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -67,7 +67,7 @@
 static int flexcop_dvb_init(struct flexcop_device *fc)
 {
 	int ret;
-	if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+	if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
 		err("error registering DVB adapter");
 		return ret;
 	}
@@ -116,7 +116,7 @@
 	dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
 
 	fc->init_state |= FC_STATE_DVB_INIT;
-	goto success;
+	return 0;
 
 err_connect_frontend:
 	fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
@@ -129,9 +129,6 @@
 err_dmx:
 	dvb_unregister_adapter(&fc->dvb_adapter);
 	return ret;
-
-success:
-	return 0;
 }
 
 static void flexcop_dvb_exit(struct flexcop_device *fc)
@@ -279,11 +276,10 @@
 
 	flexcop_device_name(fc,"initialization of","complete");
 
-	ret = 0;
-	goto success;
+	return 0;
+
 error:
 	flexcop_device_exit(fc);
-success:
 	return ret;
 }
 EXPORT_SYMBOL(flexcop_device_initialize);
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 5500f8a..761fa6e 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -63,8 +63,6 @@
 int bt878_num;
 struct bt878 bt878[BT878_MAX];
 
-EXPORT_SYMBOL(bt878_debug);
-EXPORT_SYMBOL(bt878_verbose);
 EXPORT_SYMBOL(bt878_num);
 EXPORT_SYMBOL(bt878);
 
@@ -393,7 +391,9 @@
 	{ 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" },
-	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV"},
+	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
+	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" },
+
 	{ 0, -1, NULL }
 };
 
@@ -417,6 +417,11 @@
 
 	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
 	       bt878_num);
+	if (bt878_num >= BT878_MAX) {
+		printk(KERN_ERR "bt878: Too many devices inserted\n");
+		result = -ENOMEM;
+		goto fail0;
+	}
 	if (pci_enable_device(dev))
 		return -EIO;
 
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 1cfa5e5..d687a14 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -38,6 +38,10 @@
 module_param(dst_addons, int, 0644);
 MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
 
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
 #define HAS_LOCK		1
 #define ATTEMPT_TUNE		2
 #define HAS_POWER		4
@@ -47,20 +51,24 @@
 #define DST_INFO		2
 #define DST_DEBUG		3
 
-#define dprintk(x, y, z, format, arg...) do {						\
-	if (z) {									\
-		if	((x > DST_ERROR) && (x > y))					\
-			printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg);	\
-		else if	((x > DST_NOTICE) && (x > y))					\
-			printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg);	\
-		else if ((x > DST_INFO) && (x > y))					\
-			printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg);	\
-		else if ((x > DST_DEBUG) && (x > y))					\
-			printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg);	\
-	} else {									\
-		if (x > y)								\
-			printk(format, ##arg);						\
-	}										\
+#define dprintk(x, y, z, format, arg...) do {				\
+	if (z) {							\
+		if	((x > DST_ERROR) && (x > y))			\
+			printk(KERN_ERR "dst(%d) %s: " format "\n",	\
+				state->bt->nr, __func__ , ##arg);	\
+		else if	((x > DST_NOTICE) && (x > y))			\
+			printk(KERN_NOTICE "dst(%d) %s: " format "\n",  \
+				state->bt->nr, __func__ , ##arg);	\
+		else if ((x > DST_INFO) && (x > y))			\
+			printk(KERN_INFO "dst(%d) %s: " format "\n",	\
+				state->bt->nr, __func__ , ##arg);	\
+		else if ((x > DST_DEBUG) && (x > y))			\
+			printk(KERN_DEBUG "dst(%d) %s: " format "\n",	\
+				state->bt->nr,  __func__ , ##arg);	\
+	} else {							\
+		if (x > y)						\
+			printk(format, ##arg);				\
+	}								\
 } while(0)
 
 
@@ -110,7 +118,7 @@
 
 	*result = 0;
 	if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err);
+		dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
 		return -EREMOTEIO;
 	}
 	*result = (u8) rd_packet.rd.value;
@@ -363,6 +371,17 @@
 		state->tx_tuna[2] = (freq >> 16) & 0xff;
 		state->tx_tuna[3] = (freq >> 8) & 0xff;
 		state->tx_tuna[4] = (u8) freq;
+	} else if (state->dst_type == DST_TYPE_IS_ATSC) {
+		freq = freq / 1000;
+		if (freq < 51000 || freq > 858000)
+			return -EINVAL;
+		state->tx_tuna[2] = (freq >> 16) & 0xff;
+		state->tx_tuna[3] = (freq >>  8) & 0xff;
+		state->tx_tuna[4] = (u8) freq;
+		state->tx_tuna[5] = 0x00;		/*	ATSC	*/
+		state->tx_tuna[6] = 0x00;
+		if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+			state->tx_tuna[7] = 0x00;	/*	Digital	*/
 	} else
 		return -EINVAL;
 
@@ -447,29 +466,41 @@
 	}
 	dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
 	srate /= 1000;
-	if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
-		sval = srate;
-		sval <<= 20;
-		do_div(sval, 88000);
-		symcalc = (u32) sval;
-		dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
-		state->tx_tuna[5] = (u8) (symcalc >> 12);
-		state->tx_tuna[6] = (u8) (symcalc >> 4);
-		state->tx_tuna[7] = (u8) (symcalc << 4);
-	} else {
-		state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
-		state->tx_tuna[6] = (u8) (srate >> 8);
-		state->tx_tuna[7] = (u8) srate;
-	}
-	state->tx_tuna[8] &= ~0x20;
-	if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
-		if (srate > 8000)
-			state->tx_tuna[8] |= 0x20;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+			sval = srate;
+			sval <<= 20;
+			do_div(sval, 88000);
+			symcalc = (u32) sval;
+			dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+			state->tx_tuna[5] = (u8) (symcalc >> 12);
+			state->tx_tuna[6] = (u8) (symcalc >> 4);
+			state->tx_tuna[7] = (u8) (symcalc << 4);
+		} else {
+			state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+			state->tx_tuna[6] = (u8) (srate >> 8);
+			state->tx_tuna[7] = (u8) srate;
+		}
+		state->tx_tuna[8] &= ~0x20;
+		if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+			if (srate > 8000)
+				state->tx_tuna[8] |= 0x20;
+		}
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+		if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+			state->tx_tuna[5] = (u8) (srate >> 8);
+			state->tx_tuna[6] = (u8) srate;
+			state->tx_tuna[7] = 0x00;
+		} else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+			state->tx_tuna[5] = 0x00;
+			state->tx_tuna[6] = (u8) (srate >> 8);
+			state->tx_tuna[7] = (u8) srate;
+		}
 	}
 	return 0;
 }
 
-
 static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
 {
 	if (state->dst_type != DST_TYPE_IS_CABLE)
@@ -490,7 +521,10 @@
 		state->tx_tuna[8] = 0x80;
 		break;
 	case QAM_256:
-		state->tx_tuna[8] = 0x00;
+		if (!strncmp(state->fw_name, "DCTNEW", 6))
+			state->tx_tuna[8] = 0xff;
+		else if (!strncmp(state->fw_name, "DCT-CI", 6))
+			state->tx_tuna[8] = 0x00;
 		break;
 	case QPSK:
 	case QAM_AUTO:
@@ -523,13 +557,19 @@
 }
 EXPORT_SYMBOL(dst_check_sum);
 
-static void dst_type_flags_print(u32 type_flags)
+static void dst_type_flags_print(struct dst_state *state)
 {
+	u32 type_flags = state->type_flags;
+
 	dprintk(verbose, DST_ERROR, 0, "DST type flags :");
-	if (type_flags & DST_TYPE_HAS_NEWTUNE)
-		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+	if (type_flags & DST_TYPE_HAS_TS188)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+	if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
 	if (type_flags & DST_TYPE_HAS_TS204)
 		dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+	if (type_flags & DST_TYPE_HAS_VLF)
+		dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
 	if (type_flags & DST_TYPE_HAS_SYMDIV)
 		dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
 	if (type_flags & DST_TYPE_HAS_FW_1)
@@ -542,7 +582,7 @@
 }
 
 
-static int dst_type_print(u8 type)
+static int dst_type_print(struct dst_state *state, u8 type)
 {
 	char *otype;
 	switch (type) {
@@ -558,6 +598,10 @@
 		otype = "cable";
 		break;
 
+	case DST_TYPE_IS_ATSC:
+		otype = "atsc";
+		break;
+
 	default:
 		dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
 		return -EINVAL;
@@ -567,6 +611,127 @@
 	return 0;
 }
 
+struct tuner_types tuner_list[] = {
+	{
+		.tuner_type = TUNER_TYPE_L64724,
+		.tuner_name = "L 64724",
+		.board_name = "UNKNOWN",
+		.fw_name    = "UNKNOWN"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1020",
+		.fw_name    = "DST-MOT"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1020",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_MB86A15,
+		.tuner_name = "MB 86A15",
+		.board_name = "VP1022",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_MB86A15,
+		.tuner_name = "MB 86A15",
+		.board_name = "VP1025",
+		.fw_name    = "DST-03T"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1030",
+		.fw_name    = "DST-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_STV0299,
+		.tuner_name = "STV 0299",
+		.board_name = "VP1030",
+		.fw_name    = "DSTMCI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2021",
+		.fw_name    = "DCTNEW"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2030",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2031",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP2040",
+		.fw_name    = "DCT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3020",
+		.fw_name    = "DTTFTA"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3021",
+		.fw_name    = "DTTFTA"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_TDA10046,
+		.tuner_name = "TDA10046",
+		.board_name = "VP3040",
+		.fw_name    = "DTT-CI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_UNKNOWN,
+		.tuner_name = "UNKNOWN",
+		.board_name = "VP3051",
+		.fw_name    = "DTTNXT"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_NXT200x,
+		.tuner_name = "NXT200x",
+		.board_name = "VP3220",
+		.fw_name    = "ATSCDI"
+	},
+
+	{
+		.tuner_type = TUNER_TYPE_NXT200x,
+		.tuner_name = "NXT200x",
+		.board_name = "VP3250",
+		.fw_name    = "ATSCAD"
+	},
+};
+
 /*
 	Known cards list
 	Satellite
@@ -608,7 +773,8 @@
 		.offset = 0,
 		.dst_type =  DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
@@ -616,15 +782,17 @@
 		.offset = 0,
 		.dst_type =  DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
 		.device_id = "DST-030",
 		.offset =  0,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
@@ -633,7 +801,8 @@
 		.dst_type = DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
 		.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
-							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+							 | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+		.tuner_type = TUNER_TYPE_MULTI
 	 },
 
 	{
@@ -641,57 +810,63 @@
 		.offset =  0,
 		.dst_type = DST_TYPE_IS_SAT,
 		.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/*	obsolete	*/
 
 	{
 		.device_id = "DST-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-		.dst_feature = DST_TYPE_HAS_CA
+		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
 	},	/*	An OEM board	*/
 
 	{
 		.device_id = "DSTMCI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
 		.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
-							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+							| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+		.tuner_type = TUNER_TYPE_MULTI
 	},
 
 	{
 		.device_id = "DSTFCI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_SAT,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+		.dst_feature = 0,
+		.tuner_type = 0
 	},	/* unknown to vendor	*/
 
 	{
 		.device_id = "DCT-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_CABLE,
-		.type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
-							| DST_TYPE_HAS_FW_2,
-		.dst_feature = DST_TYPE_HAS_CA
+		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1	| DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
 	},
 
 	{
 		.device_id = "DCTNEW",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_CABLE,
-		.type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+		.dst_feature = 0,
+		.tuner_type = 0
 	},
 
 	{
 		.device_id = "DTT-CI",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
-		.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
+		.type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+		.dst_feature = DST_TYPE_HAS_CA,
+		.tuner_type = 0
 	},
 
 	{
@@ -699,7 +874,8 @@
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
 		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},
 
 	{
@@ -707,7 +883,8 @@
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_TERR,
 		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = DST_TYPE_HAS_ANALOG
+		.dst_feature = DST_TYPE_HAS_ANALOG,
+		.tuner_type = 0
 	},
 
 	{
@@ -715,15 +892,17 @@
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_ATSC,
 		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.dst_feature = 0,
+		.tuner_type = 0
 	},
 
 	{
 		.device_id = "ATSCAD",
 		.offset = 1,
 		.dst_type = DST_TYPE_IS_ATSC,
-		.type_flags = DST_TYPE_HAS_FW_2,
-		.dst_feature = 0
+		.type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+		.dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+		.tuner_type = 0
 	},
 
 	{ }
@@ -768,6 +947,9 @@
 
 static int dst_card_type(struct dst_state *state)
 {
+	int j;
+	struct tuner_types *p_tuner_list = NULL;
+
 	u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 	get_type[7] = dst_check_sum(get_type, 7);
 	if (dst_command(state, get_type, 8) < 0) {
@@ -775,9 +957,17 @@
 		return -1;
 	}
 	memset(&state->card_info, '\0', 8);
-	memcpy(&state->card_info, &state->rxbuffer, 8);
+	memcpy(&state->card_info, &state->rxbuffer, 7);
 	dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
 
+	for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+		if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+			state->tuner_type = p_tuner_list->tuner_type;
+			dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+				p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+		}
+	}
+
 	return 0;
 }
 
@@ -790,12 +980,64 @@
 		return -1;
 	}
 	memset(&state->vendor, '\0', 8);
-	memcpy(&state->vendor, &state->rxbuffer, 8);
+	memcpy(&state->vendor, &state->rxbuffer, 7);
 	dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
 
 	return 0;
 }
 
+static void debug_dst_buffer(struct dst_state *state)
+{
+	int i;
+
+	if (verbose > 2) {
+		printk("%s: [", __func__);
+		for (i = 0; i < 8; i++)
+			printk(" %02x", state->rxbuffer[i]);
+		printk("]\n");
+	}
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+	u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+	if (dst_command(state, check_stv0299, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+		return -1;
+	}
+	debug_dst_buffer(state);
+
+	if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+		dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+		state->tuner_type = TUNER_TYPE_STV0299;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+	u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+	if (dst_command(state, check_mb86a15, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+		return -1;
+	}
+	debug_dst_buffer(state);
+
+	if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+		dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+		state->tuner_type = TUNER_TYPE_MB86A15;
+		return 0;
+	}
+
+	return -1;
+}
+
 static int dst_get_tuner_info(struct dst_state *state)
 {
 	u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -803,60 +1045,59 @@
 
 	get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
 	get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+	dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
 	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;
+		if (dst_command(state, get_tuner_1, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+			goto force;
 		}
 	} else {
-		if (dst_command(state, get_tuner_1, 8) < 0) {
-			dprintk(verbose, DST_INFO, 1, "Unsupported Command");
-			return -1;
+		if (dst_command(state, get_tuner_2, 8) < 0) {
+			dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+			goto force;
 		}
 	}
 	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]);
+		dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+	}
+	if (state->board_info[0] == 0xbc) {
+		if (state->type_flags != DST_TYPE_IS_ATSC)
+			state->type_flags |= DST_TYPE_HAS_TS188;
+		else
+			state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
 
-		} 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]);
+		if (state->board_info[1] == 0x01) {
+			state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+			dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
 		}
 	}
 
 	return 0;
+force:
+	if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+		state->type_flags |= DST_TYPE_HAS_TS204;
+		dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+	}
+
+	return -1;
 }
 
 static int dst_get_device_id(struct dst_state *state)
 {
 	u8 reply;
 
-	int i;
-	struct dst_types *p_dst_type;
+	int i, j;
+	struct dst_types *p_dst_type = NULL;
+	struct tuner_types *p_tuner_list = NULL;
+
 	u8 use_dst_type = 0;
 	u32 use_type_flags = 0;
 
 	static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
 
+	state->tuner_type = 0;
 	device_type[7] = dst_check_sum(device_type, 7);
 
 	if (write_dst(state, device_type, FIXED_COMM))
@@ -888,8 +1129,34 @@
 
 			/*	Card capabilities	*/
 			state->dst_hw_cap = p_dst_type->dst_feature;
-			dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id);
-
+			dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+			strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+			/*	Multiple tuners		*/
+			if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+				switch (use_dst_type) {
+				case DST_TYPE_IS_SAT:
+					/*	STV0299 check	*/
+					if (dst_check_stv0299(state) < 0) {
+						dprintk(verbose, DST_ERROR, 1, "Unsupported");
+						state->tuner_type = TUNER_TYPE_MB86A15;
+					}
+					break;
+				default:
+					break;
+				}
+				if (dst_check_mb86a15(state) < 0)
+					dprintk(verbose, DST_ERROR, 1, "Unsupported");
+			/*	Single tuner		*/
+			} else {
+				state->tuner_type = p_dst_type->tuner_type;
+			}
+			for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+				if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+					p_tuner_list->tuner_type == state->tuner_type) {
+					dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+						p_dst_type->device_id, p_tuner_list->tuner_name);
+				}
+			}
 			break;
 		}
 	}
@@ -900,10 +1167,10 @@
 		use_dst_type = DST_TYPE_IS_SAT;
 		use_type_flags = DST_TYPE_HAS_SYMDIV;
 	}
-	dst_type_print(use_dst_type);
+	dst_type_print(state, use_dst_type);
 	state->type_flags = use_type_flags;
 	state->dst_type = use_dst_type;
-	dst_type_flags_print(state->type_flags);
+	dst_type_flags_print(state);
 
 	return 0;
 }
@@ -911,15 +1178,15 @@
 static int dst_probe(struct dst_state *state)
 {
 	mutex_init(&state->dst_mutex);
-	if ((rdc_8820_reset(state)) < 0) {
-		dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
-		return -1;
-	}
-	if (dst_addons & DST_TYPE_HAS_CA)
+	if (dst_addons & DST_TYPE_HAS_CA) {
+		if ((rdc_8820_reset(state)) < 0) {
+			dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+			return -1;
+		}
 		msleep(4000);
-	else
+	} else {
 		msleep(100);
-
+	}
 	if ((dst_comm_init(state)) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
 		return -1;
@@ -931,7 +1198,6 @@
 	}
 	if (dst_get_mac(state) < 0) {
 		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)
@@ -1048,6 +1314,10 @@
 			state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
 			state->decode_strength = state->rxbuffer[4] << 8;
 			state->decode_snr = state->rxbuffer[3] << 8;
+		} else if (state->dst_type == DST_TYPE_IS_ATSC) {
+			state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[4] << 8;
+			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
 		}
 		state->cur_jiff = jiffies;
 	}
@@ -1078,8 +1348,9 @@
 	state->diseq_flags &= ~(HAS_LOCK);
 	if (!dst_wait_dst_ready(state, NO_DELAY))
 		return -EIO;
-	if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
-		/* how to get variable length reply ???? */
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		!(state->dst_type == DST_TYPE_IS_ATSC))
+
 		retval = read_dst(state, state->rx_tuna, 10);
 	else
 		retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
@@ -1087,7 +1358,10 @@
 		dprintk(verbose, DST_DEBUG, 1, "read not successful");
 		return retval;
 	}
-	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		!(state->dst_type == DST_TYPE_IS_CABLE) &&
+		!(state->dst_type == DST_TYPE_IS_ATSC)) {
+
 		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
 			dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
 			return -EIO;
@@ -1133,7 +1407,10 @@
 		dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
 		goto error;
 	}
-	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+//	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+		(!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
 		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
 		retval = write_dst(state, &state->tx_tuna[0], 10);
 	} else {
@@ -1189,9 +1466,12 @@
 
 	if (state->dst_type != DST_TYPE_IS_SAT)
 		return 0;
-	if (cmd->msg_len == 0 || cmd->msg_len > 4)
+	if (cmd->msg_len > 0 && cmd->msg_len < 5)
+		memcpy(&paket[3], cmd->msg, cmd->msg_len);
+	else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+		memcpy(&paket[2], cmd->msg, cmd->msg_len);
+	else
 		return -EINVAL;
-	memcpy(&paket[3], cmd->msg, cmd->msg_len);
 	paket[7] = dst_check_sum(&paket[0], 7);
 	dst_command(state, paket, 8);
 	return 0;
@@ -1287,8 +1567,9 @@
 	static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
 	static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 	static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
-	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 	static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+	static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
 
 	state->inversion = INVERSION_OFF;
 	state->voltage = SEC_VOLTAGE_13;
@@ -1298,11 +1579,13 @@
 	state->bandwidth = BANDWIDTH_7_MHZ;
 	state->cur_jiff = jiffies;
 	if (state->dst_type == DST_TYPE_IS_SAT)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
 	else if (state->dst_type == DST_TYPE_IS_TERR)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
 	else if (state->dst_type == DST_TYPE_IS_CABLE)
-		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+	else if (state->dst_type == DST_TYPE_IS_ATSC)
+		memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
 
 	return 0;
 }
@@ -1341,7 +1624,36 @@
 	return 0;
 }
 
-static int dst_set_frontend(struct dvb_frontend* fe,
+static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+	struct dst_state *state = fe->demodulator_priv;
+
+	if (p != NULL) {
+		dst_set_freq(state, p->frequency);
+		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+				dst_set_inversion(state, p->inversion);
+			dst_set_fec(state, p->u.qpsk.fec_inner);
+			dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+			dst_set_polarization(state);
+			dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+		} else if (state->dst_type == DST_TYPE_IS_TERR)
+			dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+		else if (state->dst_type == DST_TYPE_IS_CABLE) {
+			dst_set_fec(state, p->u.qam.fec_inner);
+			dst_set_symbolrate(state, p->u.qam.symbol_rate);
+			dst_set_modulation(state, p->u.qam.modulation);
+		}
+		dst_write_tuna(fe);
+	}
+
+	return 0;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
 			    struct dvb_frontend_parameters* p,
 			    unsigned int mode_flags,
 			    int *delay,
@@ -1378,6 +1690,11 @@
 	return 0;
 }
 
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+	return dst_algo;
+}
+
 static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
 	struct dst_state *state = fe->demodulator_priv;
@@ -1408,6 +1725,7 @@
 static struct dvb_frontend_ops dst_dvbt_ops;
 static struct dvb_frontend_ops dst_dvbs_ops;
 static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
 
 struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
 {
@@ -1417,24 +1735,25 @@
 		return NULL;
 	}
 	/* determine settings based on type */
+	/* create dvb_frontend */
 	switch (state->dst_type) {
 	case DST_TYPE_IS_TERR:
-		memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	case DST_TYPE_IS_CABLE:
-		memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	case DST_TYPE_IS_SAT:
-		memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_ATSC:
+		memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	default:
 		dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
 		kfree(state);
 		return NULL;
 	}
-
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
 	state->frontend.demodulator_priv = state;
 
 	return state;				/*	Manu (DST is a card not a frontend)	*/
@@ -1455,8 +1774,10 @@
 
 	.release = dst_release,
 	.init = dst_init,
-	.tune = dst_set_frontend,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
@@ -1479,8 +1800,10 @@
 
 	.release = dst_release,
 	.init = dst_init,
-	.tune = dst_set_frontend,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
@@ -1506,13 +1829,38 @@
 
 	.release = dst_release,
 	.init = dst_init,
-	.tune = dst_set_frontend,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
 	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
 	.read_status = dst_read_status,
 	.read_signal_strength = dst_read_signal_strength,
 	.read_snr = dst_read_snr,
 };
 
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+static struct dvb_frontend_ops dst_atsc_ops = {
+	.info = {
+		.name = "DST ATSC",
+		.type = FE_ATSC,
+		.frequency_stepsize = 62500,
+		.frequency_min = 510000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.release = dst_release,
+	.init = dst_init,
+	.tune = dst_tune_frontend,
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+	.get_frontend_algo = dst_get_tuning_algo,
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
 MODULE_AUTHOR("Jamie Honan, Manu Abraham");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index f6b49a8..fa923b9 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -68,6 +68,13 @@
 	return -EOPNOTSUPP;
 }
 
+static void put_command_and_length(u8 *data, int command, int length)
+{
+	data[0] = (command >> 16) & 0xff;
+	data[1] = (command >> 8) & 0xff;
+	data[2] = command & 0xff;
+	data[3] = length;
+}
 
 static void put_checksum(u8 *check_string, int length)
 {
@@ -124,15 +131,18 @@
 	u8 dst_ca_comm_err = 0;
 
 	while (dst_ca_comm_err < RETRIES) {
-		dst_comm_init(state);
 		dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
 		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
 			dst_error_recovery(state);
 			dst_ca_comm_err++; // work required here.
+		} else {
+			break;
 		}
-		break;
 	}
 
+	if(dst_ca_comm_err == RETRIES)
+		return -1;
+
 	return 0;
 }
 
@@ -140,6 +150,7 @@
 
 static int ca_get_app_info(struct dst_state *state)
 {
+	int length, str_length;
 	static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
 
 	put_checksum(&command[0], command[0]);
@@ -154,6 +165,68 @@
 		(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
 	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
 
+	// Transform dst message to correct application_info message
+	length = state->messages[5];
+	str_length = length - 6;
+	if (str_length < 0) {
+		str_length = 0;
+		dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+	}
+
+	// First, the command and length fields
+	put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+	// Copy application_type, application_manufacturer and manufacturer_code
+	memcpy(&state->messages[4], &state->messages[7], 5);
+
+	// Set string length and copy string
+	state->messages[9] = str_length;
+	memcpy(&state->messages[10], &state->messages[12], str_length);
+
+	return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+	int srcPtr, dstPtr, i, num_ids;
+	static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+	const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+	put_checksum(&slot_command[0], slot_command[0]);
+	if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+		return -1;
+	}
+	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+	// Print raw data
+	dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+	for (i = 0; i < state->messages[0] + 1; i++) {
+		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+	}
+	dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+	// Set the command and length of the output
+	num_ids = state->messages[in_num_ids_pos];
+	if (num_ids >= 100) {
+		num_ids = 100;
+		dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+	}
+	put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+	dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+	srcPtr = in_system_id_pos;
+	dstPtr = out_system_id_pos;
+	for(i = 0; i < num_ids; i++) {
+		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+		// Append to output
+		state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+		state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+		srcPtr += 2;
+		dstPtr += 2;
+	}
+	dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
 	return 0;
 }
 
@@ -174,7 +247,7 @@
 
 	dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
 	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
-	for (i = 0; i < 8; i++)
+	for (i = 0; i < slot_cap[0] + 1; i++)
 		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
 	dprintk(verbose, DST_CA_INFO, 0, "\n");
 
@@ -260,6 +333,11 @@
 			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
 				return -EFAULT;
 			break;
+		case CA_INFO:
+			memcpy(p_ca_message->msg, state->messages, 128);
+			if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+				return -EFAULT;
+			break;
 		}
 	}
 
@@ -302,7 +380,7 @@
 		rdc_reset_state(state);
 		return -1;
 	}
-	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
+	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
 
 	return 0;
 }
@@ -340,6 +418,7 @@
 	return 0;
 }
 
+
 static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
 {
 	u32 length = 0;
@@ -455,6 +534,16 @@
 			}
 			dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
 			break;
+		case CA_INFO_ENQUIRY:
+			dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+			if ((ca_get_ca_info(state)) < 0) {
+				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+				result = -1;
+				goto free_mem_and_exit;
+			}
+			dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+			break;
 		}
 	}
 free_mem_and_exit:
@@ -473,18 +562,15 @@
 	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) {
+	p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+	p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+	p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+	if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
 		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
+		result = -ENOMEM;
+		goto free_mem_and_exit;
 	}
-	if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
-		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
-	}
-	if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
-		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
-		return -ENOMEM;
-	}
+
 	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
 	switch (cmd) {
 	case CA_SEND_MSG:
@@ -582,7 +668,7 @@
 
 static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
 {
-	int bytes_read = 0;
+	ssize_t bytes_read = 0;
 
 	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
 
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 51d4e04..0677b04 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -42,7 +42,7 @@
 #define DST_TYPE_IS_CABLE	2
 #define DST_TYPE_IS_ATSC	3
 
-#define DST_TYPE_HAS_NEWTUNE	1
+#define DST_TYPE_HAS_TS188	1
 #define DST_TYPE_HAS_TS204	2
 #define DST_TYPE_HAS_SYMDIV	4
 #define DST_TYPE_HAS_FW_1	8
@@ -52,6 +52,9 @@
 #define DST_TYPE_HAS_OBS_REGS	128
 #define DST_TYPE_HAS_INC_COUNT	256
 #define DST_TYPE_HAS_MULTI_FE	512
+#define DST_TYPE_HAS_NEWTUNE_2	1024
+#define DST_TYPE_HAS_DBOARD	2048
+#define DST_TYPE_HAS_VLF	4096
 
 /*	Card capability list	*/
 
@@ -64,6 +67,20 @@
 #define	DST_TYPE_HAS_ANALOG	64	/*	Analog inputs	*/
 #define DST_TYPE_HAS_SESSION	128
 
+#define TUNER_TYPE_MULTI	1
+#define TUNER_TYPE_UNKNOWN	2
+/*	DVB-S		*/
+#define TUNER_TYPE_L64724	4
+#define TUNER_TYPE_STV0299	8
+#define TUNER_TYPE_MB86A15	16
+
+/*	DVB-T		*/
+#define TUNER_TYPE_TDA10046	32
+
+/*	ATSC		*/
+#define TUNER_TYPE_NXT200x	64
+
+
 #define RDC_8820_PIO_0_DISABLE	0
 #define RDC_8820_PIO_0_ENABLE	1
 #define RDC_8820_INT		2
@@ -84,8 +101,6 @@
 
 	struct bt878* bt;
 
-	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct dst_config* config;
 
@@ -121,8 +136,17 @@
 	u8 card_info[8];
 	u8 vendor[8];
 	u8 board_info[8];
-
+	u32 tuner_type;
+	char *tuner_name;
 	struct mutex dst_mutex;
+	u8 fw_name[8];
+};
+
+struct tuner_types {
+	u32 tuner_type;
+	char *tuner_name;
+	char *board_name;
+	char *fw_name;
 };
 
 struct dst_types {
@@ -131,6 +155,7 @@
 	u8 dst_type;
 	u32 type_flags;
 	u32 dst_feature;
+	u32 tuner_type;
 };
 
 struct dst_config
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index ccc7b2e..b715b97 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -147,12 +147,15 @@
 	return 0;
 }
 
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	unsigned char bs = 0;
 	unsigned char cp = 0;
 
+	if (buf_len < 5)
+		return -EINVAL;
+
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
 	if (params->frequency < 542000000)
@@ -169,22 +172,25 @@
 	else
 		bs = 0x08;
 
-	pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+	pllbuf[0] = 0x60;
 	pllbuf[1] = div >> 8;
 	pllbuf[2] = div & 0xff;
 	pllbuf[3] = cp;
 	pllbuf[4] = bs;
 
-	return 0;
+	return 5;
 }
 
 static struct mt352_config thomson_dtt7579_config = {
 	.demod_address = 0x0f,
 	.demod_init = thomson_dtt7579_demod_init,
-	.pll_set = thomson_dtt7579_pll_set,
 };
 
-static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+	.demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	u32 freq = params->frequency;
 
@@ -237,7 +243,7 @@
 	return 0;
 }
 
-static int pinnsat_pll_init(struct dvb_frontend* fe)
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
 {
 	struct dvb_bt8xx_card *card = fe->dvb->priv;
 
@@ -247,7 +253,7 @@
 	return 0;
 }
 
-static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
 {
 	struct dvb_bt8xx_card *card = fe->dvb->priv;
 
@@ -258,12 +264,9 @@
 
 static struct cx24110_config pctvsat_config = {
 	.demod_address = 0x55,
-	.pll_init = pinnsat_pll_init,
-	.pll_set = cx24108_pll_set,
-	.pll_sleep = pinnsat_pll_sleep,
 };
 
-static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
 	u8 cfg, cpump, band_select;
@@ -297,6 +300,8 @@
 	data[2] = ((div >> 10) & 0x60) | cfg;
 	data[3] = (cpump << 6) | band_select;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(card->i2c_adapter, &msg, 1);
 	return (div * 166666 - 36000000);
 }
@@ -310,7 +315,6 @@
 
 static struct sp887x_config microtune_mt7202dtf_config = {
 	.demod_address = 0x70,
-	.pll_set = microtune_mt7202dtf_pll_set,
 	.request_firmware = microtune_mt7202dtf_request_firmware,
 };
 
@@ -337,12 +341,14 @@
 	return 0;
 }
 
-static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	unsigned char bs = 0;
 	unsigned char cp = 0;
 
+	if (buf_len < 5) return -EINVAL;
+
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
 	if (params->frequency < 150000000)
@@ -383,19 +389,18 @@
 	else
 		bs = 0x08;
 
-	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+	pllbuf[0] = 0x61;
 	pllbuf[1] = div >> 8;
 	pllbuf[2] = div & 0xff;
 	pllbuf[3] = cp;
 	pllbuf[4] = bs;
 
-	return 0;
+	return 5;
 }
 
 static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
 	.demod_address = 0x0f,
 	.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
-	.pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
 };
 
 static struct dst_config dst_config = {
@@ -455,7 +460,7 @@
 	.sleep = or51211_sleep,
 };
 
-static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
 	u8 buf[4];
@@ -478,6 +483,8 @@
 	else
 		return -EINVAL;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(card->i2c_adapter, &msg, 1);
 	return 0;
 }
@@ -485,7 +492,6 @@
 static struct nxt6000_config vp3021_alps_tded4_config = {
 	.demod_address = 0x0a,
 	.clock_inversion = 1,
-	.pll_set = vp3021_alps_tded4_pll_set,
 };
 
 static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
@@ -506,14 +512,17 @@
 	return 0;
 }
 
-static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
 {
 	u32 div;
 	struct dvb_ofdm_parameters *op = &params->u.ofdm;
 
+	if (buf_len < 5)
+		return -EINVAL;
+
 	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
-	pllbuf[0] = 0xc2;
+	pllbuf[0] = 0x61;
 	pllbuf[1] = (div >> 8) & 0x7F;
 	pllbuf[2] = div & 0xFF;
 	pllbuf[3] = 0x85;
@@ -530,7 +539,7 @@
 	if (op->bandwidth == 8)
 		pllbuf[4] |= 0x04;
 
-	return 0;
+	return 5;
 }
 
 static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
@@ -557,43 +566,18 @@
 static struct mt352_config digitv_alps_tded4_config = {
 	.demod_address = 0x0a,
 	.demod_init = digitv_alps_tded4_demod_init,
-	.pll_set = digitv_alps_tded4_pll_set,
 };
 
-static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int tdvs_tua6034_tuner_set_params(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;
+	return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
 }
 
 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)
@@ -617,17 +601,25 @@
 	switch(type) {
 	case BTTV_BOARD_DVICO_DVBT_LITE:
 		card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+
+		if (card->fe == NULL)
+			card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+						  card->i2c_adapter);
+
 		if (card->fe != NULL) {
-			card->fe->ops->info.frequency_min = 174000000;
-			card->fe->ops->info.frequency_max = 862000000;
+			card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+			card->fe->ops.info.frequency_min = 174000000;
+			card->fe->ops.info.frequency_max = 862000000;
 		}
 		break;
 
 	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
 		lgdt330x_reset(card);
 		card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
-		if (card->fe != NULL)
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
+		}
 		break;
 
 	case BTTV_BOARD_NEBULA_DIGITV:
@@ -640,6 +632,7 @@
 		digitv_alps_tded4_reset(card);
 		card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
 		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
 			dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
 			break;
 		}
@@ -648,19 +641,25 @@
 		digitv_alps_tded4_reset(card);
 		card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
 
-		if (card->fe != NULL)
+		if (card->fe != NULL) {
+			card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
 			dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+		}
 		break;
 
 	case BTTV_BOARD_AVDVBT_761:
 		card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+		if (card->fe) {
+			card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+		}
 		break;
 
 	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;
-			card->fe->ops->info.frequency_max = 862000000;
+			card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+			card->fe->ops.info.frequency_min = 174000000;
+			card->fe->ops.info.frequency_max = 862000000;
 		}
 		break;
 
@@ -687,6 +686,11 @@
 
 	case BTTV_BOARD_PINNACLESAT:
 		card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+		if (card->fe) {
+			card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+			card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+			card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+		}
 		break;
 
 	case BTTV_BOARD_PC_HDTV:
@@ -703,8 +707,8 @@
 	else
 		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
 			printk("dvb-bt8xx: Frontend registration failed!\n");
-			if (card->fe->ops->release)
-				card->fe->ops->release(card->fe);
+			if (card->fe->ops.release)
+				card->fe->ops.release(card->fe);
 			card->fe = NULL;
 		}
 }
@@ -713,7 +717,7 @@
 {
 	int result;
 
-	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
+	if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
 		printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
 		return result;
 	}
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 00dd9fa..4745a90 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -37,6 +37,8 @@
 #include "cx24110.h"
 #include "or51211.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "zl10353.h"
 
 struct dvb_bt8xx_card {
 	struct mutex lock;
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 6018fcd..b5cdd57 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -64,7 +64,7 @@
 config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
 	bool "Register the onboard IR Remote Control Receiver as Input Device"
 	depends on DVB_CINERGYT2_TUNING
-	default "yes"
+	default y
 	help
 	  Enable this option if you want to use the onboard Infrared Remote
 	  Control Receiver as Linux-Input device.
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 9325d03..1b89536 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -544,15 +544,19 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
+       unsigned int mask = 0;
 
 	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 
+       if (cinergyt2->pending_fe_events != 0)
+		mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
 	mutex_unlock(&cinergyt2->sem);
 
-	return (POLLIN | POLLRDNORM | POLLPRI);
+       return mask;
 }
 
 
@@ -902,7 +906,7 @@
 		return -ENOMEM;
 	}
 
-	if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+	if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
 		kfree(cinergyt2);
 		return err;
 	}
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
index 7adb50c..1105465 100644
--- a/drivers/media/dvb/dvb-core/Makefile
+++ b/drivers/media/dvb/dvb-core/Makefile
@@ -2,8 +2,8 @@
 # Makefile for the kernel DVB device drivers.
 #
 
-dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
-		dvb_ca_en50221.o dvb_frontend.o \
-		dvb_net.o dvb_ringbuffer.o
+dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o 	\
+		dvb_ca_en50221.o dvb_frontend.o 		\
+		dvb_net.o dvb_ringbuffer.o dvb_math.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 04578df..988499d 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -872,9 +872,6 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
-	case DMX_GET_EVENT:
-		break;
-
 	case DMX_GET_PES_PIDS:
 		if (!dmxdev->demux->get_pes_pids) {
 			ret = -EINVAL;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 00347a7..2a03bf5 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1060,8 +1060,18 @@
 				break;
 
 			case DVB_CA_SLOTSTATE_VALIDATE:
-				if (dvb_ca_en50221_parse_attributes(ca, slot)
-				    != 0) {
+				if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+					/* we need this extra check for annoying interfaces like the budget-av */
+					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+					    (ca->pub->poll_slot_status)) {
+						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+							dvb_ca_en50221_thread_update_delay(ca);
+							break;
+						}
+					}
+
 					printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
 					       ca->dvbdev->adapter->num);
 					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1108,6 +1118,17 @@
 
 			case DVB_CA_SLOTSTATE_LINKINIT:
 				if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+					/* we need this extra check for annoying interfaces like the budget-av */
+					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+					    (ca->pub->poll_slot_status)) {
+						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+							dvb_ca_en50221_thread_update_delay(ca);
+							break;
+						}
+					}
+
 					printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
 					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
 					dvb_ca_en50221_thread_update_delay(ca);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 83ec5e0..fcff5ea 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -473,7 +473,7 @@
 			goto bailout;
 		}
 		memcpy(&demux->tsbuf[i], buf, j);
-		if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) {
+		if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
 			memcpy(tmppack, demux->tsbuf, 188);
 			if (tmppack[0] == 0xB8)
 				tmppack[0] = 0x47;
@@ -484,7 +484,7 @@
 	}
 
 	while (p < count) {
-		if ((buf[p] == 0x47) | (buf[p] == 0xB8)) {
+		if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
 			if (count - p >= 204) {
 				memcpy(tmppack, &buf[p], 188);
 				if (tmppack[0] == 0xB8)
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a051790..5e8bb41 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -56,7 +56,7 @@
 module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
 module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
 
 #define dprintk if (dvb_frontend_debug) printk
 
@@ -72,6 +72,8 @@
 #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
 #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
 #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW		1
 /*
  * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
  * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@@ -151,8 +153,8 @@
 		sizeof (struct dvb_frontend_parameters));
 
 	if (status & FE_HAS_LOCK)
-		if (fe->ops->get_frontend)
-			fe->ops->get_frontend(fe, &e->parameters);
+		if (fe->ops.get_frontend)
+			fe->ops.get_frontend(fe, &e->parameters);
 
 	events->eventw = wp;
 
@@ -211,10 +213,15 @@
 {
 	dprintk ("DVB: initialising frontend %i (%s)...\n",
 		 fe->dvb->num,
-		 fe->ops->info.name);
+		 fe->ops.info.name);
 
-	if (fe->ops->init)
-		fe->ops->init(fe);
+	if (fe->ops.init)
+		fe->ops.init(fe);
+	if (fe->ops.tuner_ops.init) {
+		fe->ops.tuner_ops.init(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 }
 
 void dvb_frontend_reinitialise(struct dvb_frontend *fe)
@@ -259,7 +266,7 @@
 	u32 original_frequency = fepriv->parameters.frequency;
 
 	/* are we using autoinversion? */
-	autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+	autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
 			 (fepriv->parameters.inversion == INVERSION_AUTO));
 
 	/* setup parameters correctly */
@@ -329,8 +336,8 @@
 	fepriv->parameters.frequency += fepriv->lnb_drift;
 	if (autoinversion)
 		fepriv->parameters.inversion = fepriv->inversion;
-	if (fe->ops->set_frontend)
-		fe->ops->set_frontend(fe, &fepriv->parameters);
+	if (fe->ops.set_frontend)
+		fe->ops.set_frontend(fe, &fepriv->parameters);
 
 	fepriv->parameters.frequency = original_frequency;
 	fepriv->parameters.inversion = original_inversion;
@@ -354,8 +361,8 @@
 	/* in SCAN mode, we just set the frontend when asked and leave it alone */
 	if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
 		if (fepriv->state & FESTATE_RETUNE) {
-			if (fe->ops->set_frontend)
-				fe->ops->set_frontend(fe, &fepriv->parameters);
+			if (fe->ops.set_frontend)
+				fe->ops.set_frontend(fe, &fepriv->parameters);
 			fepriv->state = FESTATE_TUNED;
 		}
 		fepriv->delay = 3*HZ;
@@ -367,8 +374,8 @@
 	if (fepriv->state & FESTATE_RETUNE) {
 		s = 0;
 	} else {
-		if (fe->ops->read_status)
-			fe->ops->read_status(fe, &s);
+		if (fe->ops.read_status)
+			fe->ops.read_status(fe, &s);
 		if (s != fepriv->status) {
 			dvb_frontend_add_event(fe, s);
 			fepriv->status = s;
@@ -381,7 +388,7 @@
 		fepriv->state = FESTATE_TUNED;
 
 		/* if we're tuned, then we have determined the correct inversion */
-		if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+		if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
 		    (fepriv->parameters.inversion == INVERSION_AUTO)) {
 			fepriv->parameters.inversion = fepriv->inversion;
 		}
@@ -405,7 +412,7 @@
 	/* don't actually do anything if we're in the LOSTLOCK state,
 	 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
 	if ((fepriv->state & FESTATE_LOSTLOCK) &&
-	    (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+	    (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
 		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
 		return;
 	}
@@ -540,39 +547,45 @@
 		if (fepriv->reinitialise) {
 			dvb_frontend_init(fe);
 			if (fepriv->tone != -1) {
-				fe->ops->set_tone(fe, fepriv->tone);
+				fe->ops.set_tone(fe, fepriv->tone);
 			}
 			if (fepriv->voltage != -1) {
-				fe->ops->set_voltage(fe, fepriv->voltage);
+				fe->ops.set_voltage(fe, fepriv->voltage);
 			}
 			fepriv->reinitialise = 0;
 		}
 
 		/* do an iteration of the tuning loop */
-		if (fe->ops->tune) {
-			/* have we been asked to retune? */
-			params = NULL;
-			if (fepriv->state & FESTATE_RETUNE) {
-				params = &fepriv->parameters;
-				fepriv->state = FESTATE_TUNED;
-			}
+		if (fe->ops.get_frontend_algo) {
+			if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
+				/* have we been asked to retune? */
+				params = NULL;
+				if (fepriv->state & FESTATE_RETUNE) {
+					params = &fepriv->parameters;
+					fepriv->state = FESTATE_TUNED;
+				}
 
-			fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
-			if (s != fepriv->status) {
-				dvb_frontend_add_event(fe, s);
-				fepriv->status = s;
+				fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+				if (s != fepriv->status) {
+					dvb_frontend_add_event(fe, s);
+					fepriv->status = s;
+				}
 			}
-		} else {
+		} else
 			dvb_frontend_swzigzag(fe);
-		}
 	}
 
 	if (dvb_shutdown_timeout) {
 		if (dvb_powerdown_on_sleep)
-			if (fe->ops->set_voltage)
-				fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
-		if (fe->ops->sleep)
-			fe->ops->sleep(fe);
+			if (fe->ops.set_voltage)
+				fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+		if (fe->ops.tuner_ops.sleep) {
+			fe->ops.tuner_ops.sleep(fe);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (fe->ops.sleep)
+			fe->ops.sleep(fe);
 	}
 
 	fepriv->thread_pid = 0;
@@ -724,7 +737,7 @@
 	switch (cmd) {
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
-		memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
 
 		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
 		 * do it, it is done for it. */
@@ -744,58 +757,58 @@
 			break;
 		}
 
-		if (fe->ops->read_status)
-			err = fe->ops->read_status(fe, status);
+		if (fe->ops.read_status)
+			err = fe->ops.read_status(fe, status);
 		break;
 	}
 	case FE_READ_BER:
-		if (fe->ops->read_ber)
-			err = fe->ops->read_ber(fe, (__u32*) parg);
+		if (fe->ops.read_ber)
+			err = fe->ops.read_ber(fe, (__u32*) parg);
 		break;
 
 	case FE_READ_SIGNAL_STRENGTH:
-		if (fe->ops->read_signal_strength)
-			err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+		if (fe->ops.read_signal_strength)
+			err = fe->ops.read_signal_strength(fe, (__u16*) parg);
 		break;
 
 	case FE_READ_SNR:
-		if (fe->ops->read_snr)
-			err = fe->ops->read_snr(fe, (__u16*) parg);
+		if (fe->ops.read_snr)
+			err = fe->ops.read_snr(fe, (__u16*) parg);
 		break;
 
 	case FE_READ_UNCORRECTED_BLOCKS:
-		if (fe->ops->read_ucblocks)
-			err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+		if (fe->ops.read_ucblocks)
+			err = fe->ops.read_ucblocks(fe, (__u32*) parg);
 		break;
 
 
 	case FE_DISEQC_RESET_OVERLOAD:
-		if (fe->ops->diseqc_reset_overload) {
-			err = fe->ops->diseqc_reset_overload(fe);
+		if (fe->ops.diseqc_reset_overload) {
+			err = fe->ops.diseqc_reset_overload(fe);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISEQC_SEND_MASTER_CMD:
-		if (fe->ops->diseqc_send_master_cmd) {
-			err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+		if (fe->ops.diseqc_send_master_cmd) {
+			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISEQC_SEND_BURST:
-		if (fe->ops->diseqc_send_burst) {
-			err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+		if (fe->ops.diseqc_send_burst) {
+			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_SET_TONE:
-		if (fe->ops->set_tone) {
-			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+		if (fe->ops.set_tone) {
+			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
 			fepriv->tone = (fe_sec_tone_mode_t) parg;
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
@@ -803,8 +816,8 @@
 		break;
 
 	case FE_SET_VOLTAGE:
-		if (fe->ops->set_voltage) {
-			err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+		if (fe->ops.set_voltage) {
+			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
 			fepriv->voltage = (fe_sec_voltage_t) parg;
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
@@ -812,11 +825,11 @@
 		break;
 
 	case FE_DISHNETWORK_SEND_LEGACY_CMD:
-		if (fe->ops->dishnetwork_send_legacy_command) {
-			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+		if (fe->ops.dishnetwork_send_legacy_command) {
+			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
-		} else if (fe->ops->set_voltage) {
+		} else if (fe->ops.set_voltage) {
 			/*
 			 * NOTE: This is a fallback condition.  Some frontends
 			 * (stv0299 for instance) take longer than 8msec to
@@ -846,7 +859,7 @@
 			/* before sending a command, initialize by sending
 			 * a 32ms 18V to the switch
 			 */
-			fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
 			dvb_frontend_sleep_until(&nexttime, 32000);
 
 			for (i = 0; i < 9; i++) {
@@ -854,7 +867,7 @@
 					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);
+					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
 					last = (last) ? 0 : 1;
 				}
 				cmd = cmd >> 1;
@@ -874,13 +887,13 @@
 		break;
 
 	case FE_DISEQC_RECV_SLAVE_REPLY:
-		if (fe->ops->diseqc_recv_slave_reply)
-			err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+		if (fe->ops.diseqc_recv_slave_reply)
+			err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
 		break;
 
 	case FE_ENABLE_HIGH_LNB_VOLTAGE:
-		if (fe->ops->enable_high_lnb_voltage)
-			err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
+		if (fe->ops.enable_high_lnb_voltage)
+			err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
 		break;
 
 	case FE_SET_FRONTEND: {
@@ -898,7 +911,7 @@
 			fepriv->parameters.inversion = INVERSION_AUTO;
 			fetunesettings.parameters.inversion = INVERSION_AUTO;
 		}
-		if (fe->ops->info.type == FE_OFDM) {
+		if (fe->ops.info.type == FE_OFDM) {
 			/* without hierachical coding code_rate_LP is irrelevant,
 			 * so we tolerate the otherwise invalid FEC_NONE setting */
 			if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
@@ -907,13 +920,13 @@
 		}
 
 		/* get frontend-specific tuning settings */
-		if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
+		if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
 			fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
 			fepriv->max_drift = fetunesettings.max_drift;
 			fepriv->step_size = fetunesettings.step_size;
 		} else {
 			/* default values */
-			switch(fe->ops->info.type) {
+			switch(fe->ops.info.type) {
 			case FE_QPSK:
 				fepriv->min_delay = HZ/20;
 				fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
@@ -928,11 +941,13 @@
 
 			case FE_OFDM:
 				fepriv->min_delay = HZ/20;
-				fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
-				fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+				fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+				fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
 				break;
 			case FE_ATSC:
-				printk("dvb-core: FE_ATSC not handled yet.\n");
+				fepriv->min_delay = HZ/20;
+				fepriv->step_size = 0;
+				fepriv->max_drift = 0;
 				break;
 			}
 		}
@@ -952,9 +967,9 @@
 		break;
 
 	case FE_GET_FRONTEND:
-		if (fe->ops->get_frontend) {
+		if (fe->ops.get_frontend) {
 			memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
-			err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+			err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
 		}
 		break;
 
@@ -1067,7 +1082,7 @@
 
 	printk ("DVB: registering frontend %i (%s)...\n",
 		fe->dvb->num,
-		fe->ops->info.name);
+		fe->ops.info.name);
 
 	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
 			     fe, DVB_DEVICE_FRONTEND);
@@ -1085,10 +1100,15 @@
 	mutex_lock(&frontend_mutex);
 	dvb_unregister_device (fepriv->dvbdev);
 	dvb_frontend_stop (fe);
-	if (fe->ops->release)
-		fe->ops->release(fe);
+	if (fe->ops.tuner_ops.release) {
+		fe->ops.tuner_ops.release(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	if (fe->ops.release)
+		fe->ops.release(fe);
 	else
-		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+		printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
 	/* fe is invalid now */
 	kfree(fepriv);
 	mutex_unlock(&frontend_mutex);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 5926a3b..2887e2b 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -49,6 +49,44 @@
 
 struct dvb_frontend;
 
+struct dvb_tuner_info {
+	char name[128];
+
+	u32 frequency_min;
+	u32 frequency_max;
+	u32 frequency_step;
+
+	u32 bandwidth_min;
+	u32 bandwidth_max;
+	u32 bandwidth_step;
+};
+
+struct dvb_tuner_ops {
+
+	struct dvb_tuner_info info;
+
+	int (*release)(struct dvb_frontend *fe);
+	int (*init)(struct dvb_frontend *fe);
+	int (*sleep)(struct dvb_frontend *fe);
+
+	/** This is for simple PLLs - set all parameters in one go. */
+	int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
+	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+	int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+
+	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+
+#define TUNER_STATUS_LOCKED 1
+	int (*get_status)(struct dvb_frontend *fe, u32 *status);
+
+	/** These are provided seperately from set_params in order to facilitate silicon
+	 * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+	int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+};
+
 struct dvb_frontend_ops {
 
 	struct dvb_frontend_info info;
@@ -64,6 +102,8 @@
 		    unsigned int mode_flags,
 		    int *delay,
 		    fe_status_t *status);
+	/* get frontend tuning algorithm from the module */
+	int (*get_frontend_algo)(struct dvb_frontend *fe);
 
 	/* these two are only used for the swzigzag code */
 	int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -86,6 +126,8 @@
 	int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
 	int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
 	int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+
+	struct dvb_tuner_ops tuner_ops;
 };
 
 #define MAX_EVENT 8
@@ -100,9 +142,10 @@
 };
 
 struct dvb_frontend {
-	struct dvb_frontend_ops* ops;
+	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
 	void* demodulator_priv;
+	void* tuner_priv;
 	void* frontend_priv;
 	void* misc_priv;
 };
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c
new file mode 100644
index 0000000..beb7c93
--- /dev/null
+++ b/drivers/media/dvb/dvb-core/dvb_math.c
@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+	0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+	0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+	0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+	0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+	0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+	0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+	0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+	0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+	0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+	0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+	0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+	0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+	0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+	0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+	0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+	0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+	0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+	0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+	0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+	0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+	0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+	0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+	0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+	0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+	0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+	0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+	0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+	0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+	0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+	0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+	0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+	0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+	/**
+	 *	returns: log2(value) * 2^24
+	 *	wrong result if value = 0 (log2(0) is undefined)
+	 */
+	unsigned int msb;
+	unsigned int logentry;
+	unsigned int significand;
+	unsigned int interpolation;
+
+	if (unlikely(value == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	/* first detect the msb (count begins at 0) */
+	msb = fls(value) - 1;
+
+	/**
+	 *	now we use a logtable after the following method:
+	 *
+	 *	log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+	 *	where x = msb and therefore 1 <= y < 2
+	 *	first y is determined by shifting the value left
+	 *	so that msb is bit 31
+	 *		0x00231f56 -> 0x8C7D5800
+	 *	the result is y * 2^31 -> "significand"
+	 *	then the highest 9 bits are used for a table lookup
+	 *	the highest bit is discarded because it's always set
+	 *	the highest nine bits in our example are 100011000
+	 *	so we would use the entry 0x18
+	 */
+	significand = value << (31 - msb);
+	logentry = (significand >> 23) & 0xff;
+
+	/**
+	 *	last step we do is interpolation because of the
+	 *	limitations of the log table the error is that part of
+	 *	the significand which isn't used for lookup then we
+	 *	compute the ratio between the error and the next table entry
+	 *	and interpolate it between the log table entry used and the
+	 *	next one the biggest error possible is 0x7fffff
+	 *	(in our example it's 0x7D5800)
+	 *	needed value for next table entry is 0x800000
+	 *	so the interpolation is
+	 *	(error / 0x800000) * (logtable_next - logtable_current)
+	 *	in the implementation the division is moved to the end for
+	 *	better accuracy there is also an overflow correction if
+	 *	logtable_next is 256
+	 */
+	interpolation = ((significand & 0x7fffff) *
+			((logtable[(logentry + 1) & 0xff] -
+			  logtable[logentry]) & 0xffff)) >> 15;
+
+	/* now we return the result */
+	return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+	/**
+	 *	returns: log10(value) * 2^24
+	 *	wrong result if value = 0 (log10(0) is undefined)
+	 */
+	u64 log;
+
+	if (unlikely(value == 0)) {
+		WARN_ON(1);
+		return 0;
+	}
+
+	log = intlog2(value);
+
+	/**
+	 *	we use the following method:
+	 *	log10(x) = log2(x) * log10(2)
+	 */
+
+	return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h
new file mode 100644
index 0000000..aecc867
--- /dev/null
+++ b/drivers/media/dvb/dvb-core/dvb_math.h
@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 9fd8752..8859ab7 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -12,7 +12,7 @@
  *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
  *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
  *
- * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
+ * ULE Decaps according to RFC 4326.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -42,6 +42,9 @@
  *                     Bugfixes and robustness improvements.
  *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
  *                     ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
+ *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ *                       Paris Lodron University of Salzburg.
  */
 
 /*
@@ -49,9 +52,6 @@
  *
  * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
  *
- * TS_FEED callback is called once for every single TS cell although it is
- * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()).
- *
  */
 
 #include <linux/module.h>
@@ -89,6 +89,9 @@
 
 #ifdef ULE_DEBUG
 
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
 #define isprint(c)	((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
 
 static void hexdump( const unsigned char *buf, unsigned short len )
@@ -214,6 +217,8 @@
 #define ULE_TEST	0
 #define ULE_BRIDGED	1
 
+#define ULE_OPTEXTHDR_PADDING 0
+
 static int ule_test_sndu( struct dvb_net_priv *p )
 {
 	return -1;
@@ -221,14 +226,28 @@
 
 static int ule_bridged_sndu( struct dvb_net_priv *p )
 {
-	/* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
-	 * This has to be the last extension header, otherwise it won't work.
-	 * Blame the authors!
+	struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+	if(ntohs(hdr->h_proto) < 1536) {
+		int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+		/* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+		if(framelen != ntohs(hdr->h_proto)) {
+			return -1;
+		}
+	}
+	/* Note:
+	 * From RFC4326:
+	 *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
+	 *   It must be the final (or only) extension header specified in the header chain of a SNDU."
+	 * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
 	 */
 	p->ule_bridged = 1;
 	return 0;
 }
 
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+	return 0;
+}
 
 /** Handle ULE extension headers.
  *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
@@ -242,7 +261,8 @@
 		{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
 
 	/* Table of optional extension header handlers.  The header type is the index. */
-	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };
+	static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+		{ [0] = ule_exthdr_padding, [1] = NULL, };
 
 	int ext_len = 0;
 	unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
@@ -253,25 +273,31 @@
 		/* Mandatory extension header */
 		if (ule_mandatory_ext_handlers[htype]) {
 			ext_len = ule_mandatory_ext_handlers[htype]( p );
-			p->ule_next_hdr += ext_len;
-			if (! p->ule_bridged) {
-				p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
-				p->ule_next_hdr += 2;
-			} else {
-				p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );
-				/* This assures the extension handling loop will terminate. */
+			if(ext_len >= 0) {
+				p->ule_next_hdr += ext_len;
+				if (!p->ule_bridged) {
+					p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+					p->ule_next_hdr += 2;
+				} else {
+					p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+					/* This assures the extension handling loop will terminate. */
+				}
 			}
+			// else: extension handler failed or SNDU should be discarded
 		} else
 			ext_len = -1;	/* SNDU has to be discarded. */
 	} else {
 		/* Optional extension header.  Calculate the length. */
-		ext_len = hlen << 2;
+		ext_len = hlen << 1;
 		/* Process the optional extension header according to its type. */
 		if (ule_optional_ext_handlers[htype])
 			(void)ule_optional_ext_handlers[htype]( p );
 		p->ule_next_hdr += ext_len;
-		p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
-		p->ule_next_hdr += 2;
+		p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+		/*
+		 * note: the length of the next header type is included in the
+		 * length of THIS optional extension header
+		 */
 	}
 
 	return ext_len;
@@ -284,8 +310,14 @@
 	p->ule_next_hdr = p->ule_skb->data;
 	do {
 		l = handle_one_ule_extension( p );
-		if (l == -1) return -1;	/* Stop extension header processing and discard SNDU. */
+		if (l < 0)
+			return l;	/* Stop extension header processing and discard SNDU. */
 		total_ext_len += l;
+#ifdef ULE_DEBUG
+		dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+			"l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+			(int) p->ule_sndu_type, l, total_ext_len);
+#endif
 
 	} while (p->ule_sndu_type < 1536);
 
@@ -355,8 +387,8 @@
 				if (priv->ule_skb) {
 					dev_kfree_skb( priv->ule_skb );
 					/* Prepare for next SNDU. */
-					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+					priv->stats.rx_errors++;
+					priv->stats.rx_frame_errors++;
 				}
 				reset_ule(priv);
 				priv->need_pusi = 1;
@@ -396,27 +428,25 @@
 			}
 		}
 
-		/* Check continuity counter. */
 		if (new_ts) {
+			/* Check continuity counter. */
 			if ((ts[3] & 0x0F) == priv->tscc)
 				priv->tscc = (priv->tscc + 1) & 0x0F;
 			else {
 				/* TS discontinuity handling: */
 				printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
-				       "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+				       "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
 				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 				if (priv->ule_skb) {
 					dev_kfree_skb( priv->ule_skb );
 					/* Prepare for next SNDU. */
 					// reset_ule(priv);  moved to below.
-					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-					((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+					priv->stats.rx_errors++;
+					priv->stats.rx_frame_errors++;
 				}
 				reset_ule(priv);
 				/* skip to next PUSI. */
 				priv->need_pusi = 1;
-				ts += TS_SZ;
-				priv->ts_count++;
 				continue;
 			}
 			/* If we still have an incomplete payload, but PUSI is
@@ -425,7 +455,7 @@
 			 * cells (continuity counter wrap). */
 			if (ts[1] & TS_PUSI) {
 				if (! priv->need_pusi) {
-					if (*from_where > 181) {
+					if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
 						/* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
 						printk(KERN_WARNING "%lu: Invalid pointer "
 						       "field: %u.\n", priv->ts_count, *from_where);
@@ -438,8 +468,6 @@
 						}
 						reset_ule(priv);
 						priv->need_pusi = 1;
-						ts += TS_SZ;
-						priv->ts_count++;
 						continue;
 					}
 					/* Skip pointer field (we're processing a
@@ -452,8 +480,8 @@
 				if (priv->ule_sndu_remain > 183) {
 					/* Current SNDU lacks more data than there could be available in the
 					 * current TS cell. */
-					((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-					((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+					priv->stats.rx_errors++;
+					priv->stats.rx_length_errors++;
 					printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
 					       "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
 					       priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -492,9 +520,11 @@
 				} else
 					priv->ule_dbit = 0;
 
-				if (priv->ule_sndu_len > 32763) {
+				if (priv->ule_sndu_len < 5) {
 					printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
 					       "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+					priv->stats.rx_errors++;
+					priv->stats.rx_length_errors++;
 					priv->ule_sndu_len = 0;
 					priv->need_pusi = 1;
 					new_ts = 1;
@@ -608,58 +638,103 @@
 				ule_dump = 1;
 #endif
 
-				((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
-				((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+				priv->stats.rx_errors++;
+				priv->stats.rx_crc_errors++;
 				dev_kfree_skb(priv->ule_skb);
 			} else {
 				/* CRC32 verified OK. */
-				/* Handle ULE Extension Headers. */
-				if (priv->ule_sndu_type < 1536) {
-					/* There is an extension header.  Handle it accordingly. */
-					int l = handle_ule_extensions( priv );
-					if (l < 0) {
-						/* Mandatory extension header unknown or TEST SNDU.  Drop it. */
-						// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
-						dev_kfree_skb( priv->ule_skb );
-						goto sndu_done;
-					}
-					skb_pull( priv->ule_skb, l );
-				}
+				u8 dest_addr[ETH_ALEN];
+				static const u8 bc_addr[ETH_ALEN] =
+					{ [ 0 ... ETH_ALEN-1] = 0xff };
 
 				/* CRC32 was OK. Remove it from skb. */
 				priv->ule_skb->tail -= 4;
 				priv->ule_skb->len -= 4;
 
-				/* Filter on receiver's destination MAC address, if present. */
 				if (!priv->ule_dbit) {
-					/* The destination MAC address is the next data in the skb. */
-					if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) {
-						/* MAC addresses don't match.  Drop SNDU. */
-						// printk( KERN_WARNING "Dropping SNDU, MAC address.\n" );
-						dev_kfree_skb( priv->ule_skb );
+					/*
+					 * The destination MAC address is the
+					 * next data in the skb.  It comes
+					 * before any extension headers.
+					 *
+					 * Check if the payload of this SNDU
+					 * should be passed up the stack.
+					 */
+					register int drop = 0;
+					if (priv->rx_mode != RX_MODE_PROMISC) {
+						if (priv->ule_skb->data[0] & 0x01) {
+							/* multicast or broadcast */
+							if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+								/* multicast */
+								if (priv->rx_mode == RX_MODE_MULTI) {
+									int i;
+									for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+										;
+									if (i == priv->multi_num)
+										drop = 1;
+								} else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+									drop = 1; /* no broadcast; */
+								/* else: all multicast mode: accept all multicast packets */
+							}
+							/* else: broadcast */
+						}
+						else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+							drop = 1;
+						/* else: destination address matches the MAC address of our receiver device */
+					}
+					/* else: promiscious mode; pass everything up the stack */
+
+					if (drop) {
+#ifdef ULE_DEBUG
+						dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+							MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+						dev_kfree_skb(priv->ule_skb);
 						goto sndu_done;
 					}
-					if (! priv->ule_bridged) {
-						skb_push( priv->ule_skb, ETH_ALEN + 2 );
-						ethh = (struct ethhdr *)priv->ule_skb->data;
-						memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN );
-						memset( ethh->h_source, 0, ETH_ALEN );
-						ethh->h_proto = htons( priv->ule_sndu_type );
-					} else {
-						/* Skip the Receiver destination MAC address. */
-						skb_pull( priv->ule_skb, ETH_ALEN );
-					}
-				} else {
-					if (! priv->ule_bridged) {
-						skb_push( priv->ule_skb, ETH_HLEN );
-						ethh = (struct ethhdr *)priv->ule_skb->data;
-						memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN );
-						memset( ethh->h_source, 0, ETH_ALEN );
-						ethh->h_proto = htons( priv->ule_sndu_type );
-					} else {
-						/* skb is in correct state; nothing to do. */
+					else
+					{
+						memcpy(dest_addr,  priv->ule_skb->data, ETH_ALEN);
+						skb_pull(priv->ule_skb, ETH_ALEN);
 					}
 				}
+
+				/* Handle ULE Extension Headers. */
+				if (priv->ule_sndu_type < 1536) {
+					/* There is an extension header.  Handle it accordingly. */
+					int l = handle_ule_extensions(priv);
+					if (l < 0) {
+						/* Mandatory extension header unknown or TEST SNDU.  Drop it. */
+						// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
+						dev_kfree_skb(priv->ule_skb);
+						goto sndu_done;
+					}
+					skb_pull(priv->ule_skb, l);
+				}
+
+				/*
+				 * Construct/assure correct ethernet header.
+				 * Note: in bridged mode (priv->ule_bridged !=
+				 * 0) we already have the (original) ethernet
+				 * header at the start of the payload (after
+				 * optional dest. address and any extension
+				 * headers).
+				 */
+
+				if (!priv->ule_bridged) {
+					skb_push(priv->ule_skb, ETH_HLEN);
+					ethh = (struct ethhdr *)priv->ule_skb->data;
+					if (!priv->ule_dbit) {
+						 /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+						memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+						memset(ethh->h_source, 0, ETH_ALEN);
+					}
+					else /* zeroize source and dest */
+						memset( ethh, 0, ETH_ALEN*2 );
+
+					ethh->h_proto = htons(priv->ule_sndu_type);
+				}
+				/* else:  skb is in correct state; nothing to do. */
 				priv->ule_bridged = 0;
 
 				/* Stuff into kernel's protocol stack. */
@@ -668,8 +743,8 @@
 				 * receive the packet anyhow. */
 				/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
 					priv->ule_skb->pkt_type = PACKET_HOST; */
-				((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
-				((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+				priv->stats.rx_packets++;
+				priv->stats.rx_bytes += priv->ule_skb->len;
 				netif_rx(priv->ule_skb);
 			}
 			sndu_done:
@@ -944,7 +1019,7 @@
 		dprintk("%s: start filtering\n", __FUNCTION__);
 		priv->secfeed->start_filtering(priv->secfeed);
 	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-		struct timespec timeout = { 0, 30000000 }; // 30 msec
+		struct timespec timeout = { 0, 10000000 }; // 10 msec
 
 		/* we have payloads encapsulated in TS */
 		dprintk("%s: alloc tsfeed\n", __FUNCTION__);
@@ -956,10 +1031,13 @@
 
 		/* Set netdevice pointer for ts decaps callback. */
 		priv->tsfeed->priv = (void *)dev;
-		ret = priv->tsfeed->set(priv->tsfeed, priv->pid,
-					TS_PACKET, DMX_TS_PES_OTHER,
+		ret = priv->tsfeed->set(priv->tsfeed,
+					priv->pid, /* pid */
+					TS_PACKET, /* type */
+					DMX_TS_PES_OTHER, /* pes type */
 					32768,     /* circular buffer size */
-					timeout);
+					timeout    /* timeout */
+					);
 
 		if (ret < 0) {
 			printk("%s: could not set ts feed\n", dev->name);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 3852430..134c2bb 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -236,7 +236,7 @@
 			"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
 
 	class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-			    NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+			    adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
 
 	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
@@ -285,7 +285,7 @@
 }
 
 
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
 {
 	int num;
 
@@ -306,6 +306,7 @@
 	adap->num = num;
 	adap->name = name;
 	adap->module = module;
+	adap->device = device;
 
 	list_add_tail (&adap->list_head, &dvb_adapter_list);
 
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 74ed585..d7a976d 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -51,6 +51,8 @@
 	u8 proposed_mac [6];
 	void* priv;
 
+	struct device *device;
+
 	struct module *module;
 };
 
@@ -76,7 +78,7 @@
 };
 
 
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
 extern int dvb_unregister_adapter (struct dvb_adapter *adap);
 
 extern int dvb_register_device (struct dvb_adapter *adap,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index e388fb1..3bc6722 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -88,6 +88,7 @@
 	select DVB_CX22702
 	select DVB_LGDT330X
 	select DVB_MT352
+	select DVB_ZL10353
 	help
 	  Say Y here to support the Conexant USB2.0 hybrid reference design.
 	  Currently, only DVB and ATSC modes are supported, analog mode
@@ -130,6 +131,15 @@
 
 	  DVB-S USB2.0 receivers.
 
+config DVB_USB_GP8PSK
+	tristate "GENPIX 8PSK->USB module support"
+	depends on DVB_USB
+	help
+	  Say Y here to support the
+	    GENPIX 8psk module
+
+	  DVB-S USB2.0 receivers.
+
 config DVB_USB_NOVA_T_USB2
 	tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
 	depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 2dc9aad..9643f56 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -7,6 +7,9 @@
 dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
 obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
 
+dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
 dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
 obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
 
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 1f0d3e9..ae23bdd 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -27,8 +27,10 @@
 
 #include "cx22702.h"
 #include "lgdt330x.h"
+#include "lg_h06xf.h"
 #include "mt352.h"
 #include "mt352_priv.h"
+#include "zl10353.h"
 
 /* debug */
 int dvb_usb_cxusb_debug;
@@ -322,32 +324,37 @@
 	return 0;
 }
 
+static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+					  struct dvb_frontend_parameters *fep)
+{
+	struct dvb_usb_device *d = fe->dvb->priv;
+	return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+}
+
 static struct cx22702_config cxusb_cx22702_config = {
 	.demod_address = 0x63,
 
 	.output_mode = CX22702_PARALLEL_OUTPUT,
-
-	.pll_init = dvb_usb_pll_init_i2c,
-	.pll_set  = dvb_usb_pll_set_i2c,
 };
 
 static struct lgdt330x_config cxusb_lgdt3303_config = {
 	.demod_address = 0x0e,
 	.demod_chip    = LGDT3303,
-	.pll_set       = dvb_usb_pll_set_i2c,
 };
 
 static struct mt352_config cxusb_dee1601_config = {
 	.demod_address = 0x0f,
 	.demod_init    = cxusb_dee1601_demod_init,
-	.pll_set       = dvb_usb_pll_set,
 };
 
-struct mt352_config cxusb_mt352_config = {
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+	.demod_address = 0x0f,
+};
+
+static struct mt352_config cxusb_mt352_config = {
 	/* used in both lgz201 and th7579 */
 	.demod_address = 0x0f,
 	.demod_init    = cxusb_mt352_demod_init,
-	.pll_set       = dvb_usb_pll_set,
 };
 
 /* Callbacks for DVB USB */
@@ -357,17 +364,10 @@
 	d->pll_addr = 0x61;
 	memcpy(d->pll_init, bpll, 4);
 	d->pll_desc = &dvb_pll_fmd1216me;
-	return 0;
-}
 
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
-{
-	u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
-	/* bpll[2] : unset bit 3, set bits 4&5
-	   bpll[3] : 0x50 - digital, 0x20 - analog */
-	d->pll_addr = 0x61;
-	memcpy(d->pll_init, bpll, 4);
-	d->pll_desc = &dvb_pll_tdvs_tua6034;
+	d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+	d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
 	return 0;
 }
 
@@ -375,6 +375,7 @@
 {
 	d->pll_addr = 0x61;
 	d->pll_desc = &dvb_pll_thomson_dtt7579;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 	return 0;
 }
 
@@ -382,6 +383,7 @@
 {
 	d->pll_addr = 0x61;
 	d->pll_desc = &dvb_pll_lg_z201;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 	return 0;
 }
 
@@ -389,6 +391,13 @@
 {
 	d->pll_addr = 0x60;
 	d->pll_desc = &dvb_pll_thomson_dtt7579;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+	return 0;
+}
+
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+{
+	d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
 	return 0;
 }
 
@@ -439,7 +448,8 @@
 
 	cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
 
-	if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+	if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+	    ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
 		return 0;
 
 	return -EIO;
@@ -555,7 +565,7 @@
 	.streaming_ctrl   = cxusb_streaming_ctrl,
 	.power_ctrl       = cxusb_bluebird_power_ctrl,
 	.frontend_attach  = cxusb_lgdt3303_frontend_attach,
-	.tuner_attach     = cxusb_lgh064f_tuner_attach,
+	.tuner_attach     = cxusb_lgdt3303_tuner_attach,
 
 	.i2c_algo         = &cxusb_i2c_algo,
 
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 2d52b76..abd75b4 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -173,11 +173,10 @@
 	struct dib3000_config demod_cfg;
 	struct dibusb_state *st = d->priv;
 
-	demod_cfg.pll_set = dvb_usb_pll_set_i2c;
-	demod_cfg.pll_init = dvb_usb_pll_init_i2c;
-
 	for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
 		if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+			d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+			d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
 			d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
 			return 0;
 		}
@@ -190,6 +189,10 @@
 {
 	d->pll_addr = 0x60;
 	d->pll_desc = &dvb_pll_env57h1xd5;
+
+	d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+	d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
 	return 0;
 }
 EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index dd5a131..f4c45f3 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -20,11 +20,12 @@
 	struct dibusb_state *st = d->priv;
 
 	demod_cfg.demod_address = 0x8;
-	demod_cfg.pll_set = dvb_usb_pll_set_i2c;
-	demod_cfg.pll_init = dvb_usb_pll_init_i2c;
 
-	if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+	if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+		d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+		d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
 		return -ENODEV;
+	}
 
 	d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
 
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 91136c0..c14d9ef 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -112,27 +112,30 @@
 
 static struct mt352_config digitv_mt352_config = {
 	.demod_init = digitv_mt352_demod_init,
-	.pll_set = dvb_usb_pll_set,
 };
 
-static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 	u8 b[5];
-	dvb_usb_pll_set(fe,fep,b);
+	dvb_usb_tuner_calc_regs(fe,fep,b, 5);
 	return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
 }
 
 static struct nxt6000_config digitv_nxt6000_config = {
 	.clock_inversion = 1,
-	.pll_set = digitv_nxt6000_pll_set,
 };
 
 static int digitv_frontend_attach(struct dvb_usb_device *d)
 {
-	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL ||
-		(d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL)
+	if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+		d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 		return 0;
+	}
+	if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+		d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+		return 0;
+	}
 	return -EIO;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index cd21ddb..17413ad 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -18,7 +18,6 @@
 
 	struct dvb_frontend_parameters fep;
 	struct dvb_frontend frontend;
-	struct dvb_frontend_ops ops;
 };
 
 static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
@@ -163,16 +162,13 @@
 	deb_info("attaching frontend dtt200u\n");
 
 	state->d = d;
-	memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
 
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
-	goto success;
+	return &state->frontend;
 error:
 	return NULL;
-success:
-	return &state->frontend;
 }
 
 static struct dvb_frontend_ops dtt200u_fe_ops = {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index 6fa9210..ec63170 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -82,7 +82,7 @@
 	int ret;
 
 	if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
-			d->owner)) < 0) {
+			d->owner, &d->udev->dev)) < 0) {
 		deb_info("dvb_register_adapter failed: error %d", ret);
 		goto err;
 	}
@@ -121,16 +121,15 @@
 
 	dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
 
-	goto success;
+	d->state |= DVB_USB_STATE_DVB;
+	return 0;
+
 err_dmx_dev:
 	dvb_dmx_release(&d->demux);
 err_dmx:
 	dvb_unregister_adapter(&d->dvb_adap);
 err:
 	return ret;
-success:
-	d->state |= DVB_USB_STATE_DVB;
-	return 0;
 }
 
 int dvb_usb_dvb_exit(struct dvb_usb_device *d)
@@ -184,13 +183,13 @@
 
 	/* re-assign sleep and wakeup functions */
 	if (d->fe != NULL) {
-		d->fe_init = d->fe->ops->init;   d->fe->ops->init  = dvb_usb_fe_wakeup;
-		d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+		d->fe_init = d->fe->ops.init;   d->fe->ops.init  = dvb_usb_fe_wakeup;
+		d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
 
 		if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
 			err("Frontend registration failed.");
-			if (d->fe->ops->release)
-				d->fe->ops->release(d->fe);
+			if (d->fe->ops.release)
+				d->fe->ops.release(d->fe);
 			d->fe = NULL;
 			return -ENODEV;
 		}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 9b25453..6b611a7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,7 +46,7 @@
 	return 0;
 }
 
-int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 	struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
@@ -63,6 +63,8 @@
 	deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
 			d->pll_init[2],d->pll_init[3]);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
 		err("tuner i2c write failed for pll_init.");
 		ret = -EREMOTEIO;
@@ -73,38 +75,42 @@
 		d->tuner_pass_ctrl(fe,0,d->pll_addr);
 	return ret;
 }
-EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
 
-int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 
+	if (buf_len != 5)
+		return -EINVAL;
 	if (d->pll_desc == NULL)
 		return 0;
 
 	deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
 
-	b[0] = d->pll_addr << 1;
+	b[0] = d->pll_addr;
 	dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
 
 	deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
 
-	return 0;
+	return 5;
 }
-EXPORT_SYMBOL(dvb_usb_pll_set);
+EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
 
-int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
 	struct dvb_usb_device *d = fe->dvb->priv;
 	int ret = 0;
 	u8 b[5];
 	struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
 
-	dvb_usb_pll_set(fe,fep,b);
+	dvb_usb_tuner_calc_regs(fe,fep,b,5);
 
 	if (d->tuner_pass_ctrl)
 		d->tuner_pass_ctrl(fe,1,d->pll_addr);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
 		err("tuner i2c write failed for pll_set.");
 		ret = -EREMOTEIO;
@@ -116,4 +122,4 @@
 
 	return ret;
 }
-EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index cb23904..9569891 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -31,6 +31,7 @@
 #define USB_VID_VISIONPLUS					0x13d3
 #define USB_VID_TWINHAN						0x1822
 #define USB_VID_ULTIMA_ELECTRONIC			0x05d8
+#define USB_VID_GENPIX					0x09c0
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
@@ -104,5 +105,6 @@
 #define USB_PID_KYE_DVB_T_WARM				0x701f
 #define USB_PID_PCTV_200E					0x020e
 #define USB_PID_PCTV_400E					0x020f
-
+#define USB_PID_GENPIX_8PSK_COLD				0x0200
+#define USB_PID_GENPIX_8PSK_WARM				0x0201
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index fead958..4cf9f89 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -330,9 +330,9 @@
 extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
 
 /* commonly used pll init and set functions */
-extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
-extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
+extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
 
 /* commonly used firmware download types and function */
 struct hexline {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
new file mode 100644
index 0000000..6ccbdc9
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -0,0 +1,272 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+struct gp8psk_fe_state {
+	struct dvb_frontend fe;
+
+	struct dvb_usb_device *d;
+
+	u16 snr;
+
+	unsigned long next_snr_check;
+};
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 lock;
+
+	if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
+		return -EINVAL;
+
+	if (lock)
+		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+	else
+		*status = 0;
+
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+	(void) fe;
+	*ber = 0;
+	return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+	(void) fe;
+	*unc = 0;
+	return 0;
+}
+
+static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 buf[2];
+
+	if (time_after(jiffies,st->next_snr_check)) {
+		gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
+		*snr = (int)(buf[1]) << 8 | buf[0];
+		/* snr is reported in dBu*256 */
+		/* snr / 38.4 ~= 100% strength */
+		/* snr * 17 returns 100% strength as 65535 */
+		if (*snr <= 3855)
+			*snr = (*snr<<4) + *snr; // snr * 17
+		else
+			*snr = 65535;
+		st->next_snr_check = jiffies + (10*HZ)/1000;
+	} else {
+		*snr = st->snr;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+	return gp8psk_fe_read_snr(fe, strength);
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 800;
+	return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	u8 cmd[10];
+	u32 freq = fep->frequency * 1000;
+
+	cmd[4] = freq         & 0xff;
+	cmd[5] = (freq >> 8)  & 0xff;
+	cmd[6] = (freq >> 16) & 0xff;
+	cmd[7] = (freq >> 24) & 0xff;
+
+	switch(fe->ops.info.type) {
+	case FE_QPSK:
+		cmd[0] =  fep->u.qpsk.symbol_rate        & 0xff;
+		cmd[1] = (fep->u.qpsk.symbol_rate >>  8) & 0xff;
+		cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
+		cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
+		cmd[8] = ADV_MOD_DVB_QPSK;
+		cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+		break;
+	default:
+		// other modes are unsuported right now
+		cmd[0] = 0;
+		cmd[1] = 0;
+		cmd[2] = 0;
+		cmd[3] = 0;
+		cmd[8] = 0;
+		cmd[9] = 0;
+		break;
+	}
+
+	gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+
+	state->next_snr_check = jiffies;
+
+	return 0;
+}
+
+static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	return 0;
+}
+
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+				    struct dvb_diseqc_master_cmd *m)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+	deb_fe("%s\n",__FUNCTION__);
+
+	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+			m->msg, m->msg_len)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+				    fe_sec_mini_cmd_t burst)
+{
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	u8 cmd;
+
+	deb_fe("%s\n",__FUNCTION__);
+
+	/* These commands are certainly wrong */
+	cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+			&cmd, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+	if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+		 (tone == SEC_TONE_ON), 0, NULL, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+			 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+	u8 cmd = sw_cmd & 0x7f;
+
+	if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+			NULL, 0)) {
+		return -EINVAL;
+	}
+	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+			0, NULL, 0)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+	struct gp8psk_fe_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+	struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+	if (s == NULL)
+		goto error;
+
+	s->d = d;
+	memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+	s->fe.demodulator_priv = s;
+
+	goto success;
+error:
+	return NULL;
+success:
+	return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+	.info = {
+		.name			= "Genpix 8psk-USB DVB-S",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 100,
+		.symbol_rate_min        = 1000000,
+		.symbol_rate_max        = 45000000,
+		.symbol_rate_tolerance  = 500,  /* ppm */
+		.caps = FE_CAN_INVERSION_AUTO |
+				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_QPSK
+	},
+
+	.release = gp8psk_fe_release,
+
+	.init = NULL,
+	.sleep = NULL,
+
+	.set_frontend = gp8psk_fe_set_frontend,
+	.get_frontend = gp8psk_fe_get_frontend,
+	.get_tune_settings = gp8psk_fe_get_tune_settings,
+
+	.read_status = gp8psk_fe_read_status,
+	.read_ber = gp8psk_fe_read_ber,
+	.read_signal_strength = gp8psk_fe_read_signal_strength,
+	.read_snr = gp8psk_fe_read_snr,
+	.read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+	.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+	.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+	.set_tone = gp8psk_fe_set_tone,
+	.set_voltage = gp8psk_fe_set_voltage,
+	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
new file mode 100644
index 0000000..9a98f3f
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -0,0 +1,256 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+	int ret = 0,try = 0;
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	while (ret >= 0 && ret != blen && try < 3) {
+		ret = usb_control_msg(d->udev,
+			usb_rcvctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_IN,
+			value,index,b,blen,
+			2000);
+		deb_info("reading number %d (ret: %d)\n",try,ret);
+		try++;
+	}
+
+	if (ret < 0 || ret != blen) {
+		warn("usb in operation failed.");
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+			     u16 index, u8 *b, int blen)
+{
+	int ret;
+
+	deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+	debug_dump(b,blen,deb_xfer);
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	if (usb_control_msg(d->udev,
+			usb_sndctrlpipe(d->udev,0),
+			req,
+			USB_TYPE_VENDOR | USB_DIR_OUT,
+			value,index,b,blen,
+			2000) != blen) {
+		warn("usb out operation failed.");
+		ret = -EIO;
+	} else
+		ret = 0;
+	mutex_unlock(&d->usb_mutex);
+
+	return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+	int ret;
+	const struct firmware *fw = NULL;
+	u8 *ptr, *buf;
+	if ((ret = request_firmware(&fw, bcm4500_firmware,
+					&d->udev->dev)) != 0) {
+		err("did not find the bcm4500 firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+			bcm4500_firmware,ret);
+		return ret;
+	}
+
+	ret = -EINVAL;
+
+	if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
+		goto out_rel_fw;
+
+	info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+
+	ptr = fw->data;
+	buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+
+	while (ptr[0] != 0xff) {
+		u16 buflen = ptr[0] + 4;
+		if (ptr + buflen >= fw->data + fw->size) {
+			err("failed to load bcm4500 firmware.");
+			goto out_free;
+		}
+		memcpy(buf, ptr, buflen);
+		if (dvb_usb_generic_write(d, buf, buflen)) {
+			err("failed to load bcm4500 firmware.");
+			goto out_free;
+		}
+		ptr += buflen;
+	}
+
+	ret = 0;
+
+out_free:
+	kfree(buf);
+out_rel_fw:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 status, buf;
+	if (onoff) {
+		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+		if (! (status & 0x01))  /* started */
+			if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+				return -EINVAL;
+
+		if (! (status & 0x02)) /* BCM4500 firmware loaded */
+			if(gp8psk_load_bcm4500fw(d))
+				return EINVAL;
+
+		if (! (status & 0x04)) /* LNB Power */
+			if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
+					&buf, 1))
+				return EINVAL;
+
+		/* Set DVB mode */
+		if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+			return -EINVAL;
+		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+	} else {
+		/* Turn off LNB power */
+		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+			return EINVAL;
+		/* Turn off 8psk power */
+		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+			return -EINVAL;
+
+	}
+	return 0;
+}
+
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+{
+	d->fe = gp8psk_fe_attach(d);
+
+	return 0;
+}
+
+static struct dvb_usb_properties gp8psk_properties;
+
+static int gp8psk_usb_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id gp8psk_usb_table [] = {
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+	    { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_properties gp8psk_properties = {
+	.caps = 0,
+
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-gp8psk-01.fw",
+
+	.streaming_ctrl   = gp8psk_streaming_ctrl,
+	.power_ctrl       = gp8psk_power_ctrl,
+	.frontend_attach  = gp8psk_frontend_attach,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	/* parameter for the MPEG2-data transfer */
+	.urb = {
+		.type = DVB_USB_BULK,
+		.count = 7,
+		.endpoint = 0x82,
+		.u = {
+			.bulk = {
+				.buffersize = 8192,
+			}
+		}
+	},
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+		  .cold_ids = { &gp8psk_usb_table[0], NULL },
+		  .warm_ids = { &gp8psk_usb_table[1], NULL },
+		},
+		{ 0 },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+	.name		= "dvb_usb_gp8psk",
+	.probe		= gp8psk_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table	= gp8psk_usb_table,
+};
+
+/* module stuff */
+static int __init gp8psk_usb_module_init(void)
+{
+	int result;
+	if ((result = usb_register(&gp8psk_usb_driver))) {
+		err("usb_register failed. (%d)",result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit gp8psk_usb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&gp8psk_usb_driver);
+}
+
+module_init(gp8psk_usb_module_init);
+module_exit(gp8psk_usb_module_exit);
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
new file mode 100644
index 0000000..3eba706
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -0,0 +1,79 @@
+/* DVB USB compliant Linux driver for the
+ *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ *	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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...)   dprintk(dvb_usb_gp8psk_debug,0x08,args)
+/* gp8psk commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN                     0xC0
+#define TH_COMMAND_OUT                    0xC1
+
+/* command bytes */
+#define GET_8PSK_CONFIG                 0x80
+#define SET_8PSK_CONFIG                 0x81
+#define ARM_TRANSFER                    0x85
+#define TUNE_8PSK                       0x86
+#define GET_SIGNAL_STRENGTH             0x87
+#define LOAD_BCM4500                    0x88
+#define BOOT_8PSK                       0x89
+#define START_INTERSIL                  0x8A
+#define SET_LNB_VOLTAGE                 0x8B
+#define SET_22KHZ_TONE                  0x8C
+#define SEND_DISEQC_COMMAND             0x8D
+#define SET_DVB_MODE                    0x8E
+#define SET_DN_SWITCH                   0x8F
+#define GET_SIGNAL_LOCK                 0x90
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1   /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2   /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3  /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4  /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5  /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6  /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8     /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9     /* DVB-S BPSK */
+
+#define GET_USB_SPEED                     0x07
+ #define USB_SPEED_LOW                    0
+ #define USB_SPEED_FULL                   1
+ #define USB_SPEED_HIGH                   2
+
+#define RESET_FX2                         0x13
+
+#define FW_VERSION_READ                   0x0B
+#define VENDOR_STRING_READ                0x0C
+#define PRODUCT_STRING_READ               0x0D
+#define FW_BCD_VERSION_READ               0x14
+
+extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+			     u16 index, u8 *b, int blen);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 14f1911..97d74da 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -57,7 +57,6 @@
 	memset(&umt_config,0,sizeof(struct mt352_config));
 	umt_config.demod_init = umt_mt352_demod_init;
 	umt_config.demod_address = 0xf;
-	umt_config.pll_set = dvb_usb_pll_set;
 
 	d->fe = mt352_attach(&umt_config, &d->i2c_adap);
 
@@ -68,6 +67,7 @@
 {
 	d->pll_addr = 0x61;
 	d->pll_desc = &dvb_pll_tua6034;
+	d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index 2a89f8c..d4da494 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -287,17 +287,16 @@
 		goto error;
 
 	s->d = d;
-	s->fe.ops = &vp702x_fe_ops;
+
+	memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
 	s->fe.demodulator_priv = s;
 
 	s->lnb_buf[1] = SET_LNB_POWER;
 	s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
 
-	goto success;
+	return &s->fe;
 error:
 	return NULL;
-success:
-	return &s->fe;
 }
 
 
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
index 9999336..8452eef 100644
--- a/drivers/media/dvb/dvb-usb/vp7045-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c
@@ -23,8 +23,6 @@
 
 struct vp7045_fe_state {
 	struct dvb_frontend fe;
-	struct dvb_frontend_ops ops;
-
 	struct dvb_usb_device *d;
 };
 
@@ -151,15 +149,12 @@
 		goto error;
 
 	s->d = d;
-	memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
-	s->fe.ops = &s->ops;
+	memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
 	s->fe.demodulator_priv = s;
 
-	goto success;
+	return &s->fe;
 error:
 	return NULL;
-success:
-	return &s->fe;
 }
 
 
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 37d5e0a..0ef361f 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -157,7 +157,7 @@
 	help
 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
 	depends on DVB_CORE
 
 config DVB_NXT200X
@@ -216,4 +216,20 @@
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+
+comment "Miscellaneous devices"
+	depends on DVB_CORE
+
+config DVB_LNBP21
+	tristate "LNBP21 SEC controller"
+	depends on DVB_CORE
+	help
+	  An SEC control chip.
+
+config DVB_ISL6421
+	tristate "ISL6421 SEC controller"
+	depends on DVB_CORE
+	help
+	  An SEC control chip.
+
 endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index d09b607..5222245 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -31,3 +31,5 @@
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 1708a1d..baeb311d 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -48,7 +48,6 @@
 struct bcm3510_state {
 
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct bcm3510_config* config;
 	struct dvb_frontend frontend;
 
@@ -791,10 +790,9 @@
 
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	mutex_init(&state->hab_mutex);
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
index 78573b2..d8f6573 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -89,12 +89,13 @@
 	return 0;
 }
 
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, 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) };
+	struct i2c_adapter *i2c = fe->tuner_priv;
 
 	if ((params->frequency < 950000) || (params->frequency > 2150000))
 		return -EINVAL;
@@ -105,6 +106,8 @@
 	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
 	data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	ret = i2c_transfer(i2c, &msg, 1);
 	return (ret != 1) ? -EIO : 0;
 }
@@ -117,7 +120,6 @@
 	.skip_reinit = 0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_bsbe1_set_symbol_rate,
-	.pll_set = alps_bsbe1_pll_set,
 };
 
 #endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index 2a5366c..e231cd8 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -101,11 +101,12 @@
 	return 0;
 }
 
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	u8 buf[4];
 	u32 div;
 	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct i2c_adapter *i2c = fe->tuner_priv;
 
 	if ((params->frequency < 950000) || (params->frequency > 2150000))
 		return -EINVAL;
@@ -119,6 +120,8 @@
 	if (params->frequency > 1530000)
 		buf[3] = 0xc0;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(i2c, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -134,7 +137,6 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_bsru6_set_symbol_rate,
-	.pll_set = alps_bsru6_pll_set,
 };
 
 #endif
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 755f774..3c7c09a 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -34,8 +34,6 @@
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	const struct cx22700_config* config;
 
 	struct dvb_frontend frontend;
@@ -247,12 +245,6 @@
 
 	cx22700_writereg (state, 0x00, 0x01);
 
-	if (state->config->pll_init) {
-		cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
-		state->config->pll_init(fe);
-		cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
-	}
-
 	return 0;
 }
 
@@ -333,9 +325,11 @@
 	cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
 	cx22700_writereg (state, 0x00, 0x00);
 
-	cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
-	state->config->pll_set(fe, p);
-	cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
 	cx22700_set_inversion (state, p->inversion);
 	cx22700_set_tps (state, &p->u.ofdm);
 	cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
@@ -353,6 +347,17 @@
 	return cx22700_get_tps (state, &p->u.ofdm);
 }
 
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct cx22700_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return cx22700_writereg(state, 0x0a, 0x00);
+	} else {
+		return cx22700_writereg(state, 0x0a, 0x01);
+	}
+}
+
 static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
 	fesettings->min_delay_ms = 150;
@@ -381,13 +386,12 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (cx22700_readreg(state, 0x07) < 0) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -413,6 +417,7 @@
 	.release = cx22700_release,
 
 	.init = cx22700_init,
+	.i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
 
 	.set_frontend = cx22700_set_frontend,
 	.get_frontend = cx22700_get_frontend,
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index c9145b4..dcd8979 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -29,10 +29,6 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 0fc899f..4106d46 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -40,8 +40,6 @@
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct cx22702_config* config;
 
@@ -211,22 +209,10 @@
 	u8 val;
 	struct cx22702_state* state = fe->demodulator_priv;
 
-	/* set PLL */
-	cx22702_i2c_gate_ctrl(fe, 1);
-	if (state->config->pll_set) {
-		state->config->pll_set(fe, p);
-	} else if (state->config->pll_desc) {
-		u8 pllbuf[4];
-		struct i2c_msg msg = { .addr = state->config->pll_address,
-				       .buf = pllbuf, .len = 4 };
-		dvb_pll_configure(state->config->pll_desc, pllbuf,
-				  p->frequency,
-				  p->u.ofdm.bandwidth);
-		i2c_transfer(state->i2c, &msg, 1);
-	} else {
-		BUG();
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 	}
-	cx22702_i2c_gate_ctrl(fe, 0);
 
 	/* set inversion */
 	cx22702_set_inversion (state, p->inversion);
@@ -358,10 +344,6 @@
 
 	cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
-	/* init PLL */
-	if (state->config->pll_init)
-		state->config->pll_init(fe);
-
 	cx22702_i2c_gate_ctrl(fe, 0);
 
 	return 0;
@@ -495,7 +477,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
 	state->prevUCBlocks = 0;
 
 	/* check if the demod is there */
@@ -503,7 +484,7 @@
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -530,6 +511,7 @@
 	.release = cx22702_release,
 
 	.init = cx22702_init,
+	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 
 	.set_frontend = cx22702_set_tps,
 	.get_frontend = cx22702_get_frontend,
@@ -540,7 +522,6 @@
 	.read_signal_strength = cx22702_read_signal_strength,
 	.read_snr = cx22702_read_snr,
 	.read_ucblocks = cx22702_read_ucblocks,
-	.i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 };
 
 module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 5633976..7f2f241 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -39,13 +39,6 @@
 #define CX22702_PARALLEL_OUTPUT 0
 #define CX22702_SERIAL_OUTPUT   1
 	u8 output_mode;
-
-	/* PLL maintenance */
-	u8 pll_address;
-	struct dvb_pll_desc *pll_desc;
-
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index f3edf8b..ce3c739 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -36,8 +36,6 @@
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	const struct cx24110_config* config;
 
 	struct dvb_frontend frontend;
@@ -250,7 +248,7 @@
 	static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
 	int i;
 
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+	dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
 	if (srate>90999000UL/2)
 		srate=90999000UL/2;
 	if (srate<500000)
@@ -366,17 +364,6 @@
 		cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
 	};
 
-	if (state->config->pll_init) state->config->pll_init(fe);
-
-	return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
-	struct cx24110_state *state = fe->demodulator_priv;
-
-	if (state->config->pll_sleep)
-		  return state->config->pll_sleep(fe);
 	return 0;
 }
 
@@ -548,7 +535,12 @@
 {
 	struct cx24110_state *state = fe->demodulator_priv;
 
-	state->config->pll_set(fe, p);
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
 	cx24110_set_inversion (state, p->inversion);
 	cx24110_set_fec (state, p->u.qpsk.fec_inner);
 	cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -612,7 +604,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
 	state->lastbler = 0;
 	state->lastesn0 = 0;
@@ -622,7 +613,7 @@
 	if ((ret != 0x5a) && (ret != 0x69)) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -651,7 +642,6 @@
 	.release = cx24110_release,
 
 	.init = cx24110_initfe,
-	.sleep = cx24110_sleep,
 	.set_frontend = cx24110_set_frontend,
 	.get_frontend = cx24110_get_frontend,
 	.read_status = cx24110_read_status,
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index 609ac64..b354a64 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -31,11 +31,6 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-	int (*pll_sleep)(struct dvb_frontend* fe);
 };
 
 extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 691dc84..f2f795c 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -41,14 +41,12 @@
 struct cx24123_state
 {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct cx24123_config* config;
 
 	struct dvb_frontend frontend;
 
 	u32 lastber;
 	u16 snr;
-	u8  lnbreg;
 
 	/* Some PLL specifics for tuning */
 	u32 VCAarg;
@@ -249,29 +247,6 @@
 	return 0;
 }
 
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
-	u8 buf[] = { reg, data };
-	/* fixme: put the intersil addr int the config */
-	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
-	int err;
-
-	if (debug>1)
-		printk("cx24123: %s:  writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
-						__FUNCTION__,reg, data);
-
-	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
-			 " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
-		return -EREMOTEIO;
-	}
-
-	/* cache the write, no way to read back */
-	state->lnbreg = data;
-
-	return 0;
-}
-
 static int cx24123_readreg(struct cx24123_state* state, u8 reg)
 {
 	int ret;
@@ -295,11 +270,6 @@
 	return b1[0];
 }
 
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
-	return state->lnbreg;
-}
-
 static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
 {
 	u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -458,8 +428,8 @@
 	u8 pll_mult;
 
 	/*  check if symbol rate is within limits */
-	if ((srate > state->ops.info.symbol_rate_max) ||
-	    (srate < state->ops.info.symbol_rate_min))
+	if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+	    (srate < state->frontend.ops.info.symbol_rate_min))
 		return -EOPNOTSUPP;;
 
 	/* choose the sampling rate high enough for the required operation,
@@ -687,13 +657,6 @@
 	for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
 		cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
 
-	if (state->config->pll_init)
-		state->config->pll_init(fe);
-
-	/* Configure the LNB for 14V */
-	if (state->config->use_isl6421)
-		cx24123_writelnbreg(state, 0x0, 0x2a);
-
 	return 0;
 }
 
@@ -702,50 +665,18 @@
 	struct cx24123_state *state = fe->demodulator_priv;
 	u8 val;
 
-	switch (state->config->use_isl6421) {
+	val = cx24123_readreg(state, 0x29) & ~0x40;
 
-	case 1:
-
-		val = cx24123_readlnbreg(state, 0x0);
-
-		switch (voltage) {
-		case SEC_VOLTAGE_13:
-			dprintk("%s:  isl6421 voltage = 13V\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
-		case SEC_VOLTAGE_18:
-			dprintk("%s:  isl6421 voltage = 18V\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
-		case SEC_VOLTAGE_OFF:
-			dprintk("%s:  isl5421 voltage off\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val & 0x30);
-		default:
-			return -EINVAL;
-		};
-
-	case 0:
-
-		val = cx24123_readreg(state, 0x29);
-
-		switch (voltage) {
-		case SEC_VOLTAGE_13:
-			dprintk("%s: setting voltage 13V\n", __FUNCTION__);
-			if (state->config->enable_lnb_voltage)
-				state->config->enable_lnb_voltage(fe, 1);
-			return cx24123_writereg(state, 0x29, val | 0x80);
-		case SEC_VOLTAGE_18:
-			dprintk("%s: setting voltage 18V\n", __FUNCTION__);
-			if (state->config->enable_lnb_voltage)
-				state->config->enable_lnb_voltage(fe, 1);
-			return cx24123_writereg(state, 0x29, val & 0x7f);
-		case SEC_VOLTAGE_OFF:
-			dprintk("%s: setting voltage off\n", __FUNCTION__);
-			if (state->config->enable_lnb_voltage)
-				state->config->enable_lnb_voltage(fe, 0);
-			return 0;
-		default:
-			return -EINVAL;
-		};
-	}
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+		return cx24123_writereg(state, 0x29, val | 0x80);
+	case SEC_VOLTAGE_18:
+		dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+		return cx24123_writereg(state, 0x29, val & 0x7f);
+	default:
+		return -EINVAL;
+	};
 
 	return 0;
 }
@@ -766,27 +697,20 @@
 static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	int i, val;
+	int i, val, tone;
 
 	dprintk("%s:\n",__FUNCTION__);
 
-	/* check if continuous tone has been stopped */
-	if (state->config->use_isl6421)
-		val = cx24123_readlnbreg(state, 0x00) & 0x10;
-	else
-		val = cx24123_readreg(state, 0x29) & 0x10;
-
-
-	if (val) {
-		printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
-		return -ENOTSUPP;
-	}
+	/* stop continuous tone if enabled */
+	tone = cx24123_readreg(state, 0x29);
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x50);
 
 	/* wait for diseqc queue ready */
 	cx24123_wait_for_diseqc(state);
 
 	/* select tone mode */
-	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
 	for (i = 0; i < cmd->msg_len; i++)
 		cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -797,36 +721,33 @@
 	/* wait for diseqc message to finish sending */
 	cx24123_wait_for_diseqc(state);
 
+	/* restart continuous tone if enabled */
+	if (tone & 0x10) {
+		cx24123_writereg(state, 0x29, tone & ~0x40);
+	}
+
 	return 0;
 }
 
 static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	int val;
+	int val, tone;
 
 	dprintk("%s:\n", __FUNCTION__);
 
-	/* check if continuous tone has been stoped */
-	if (state->config->use_isl6421)
-		val = cx24123_readlnbreg(state, 0x00) & 0x10;
-	else
-		val = cx24123_readreg(state, 0x29) & 0x10;
+	/* stop continuous tone if enabled */
+	tone = cx24123_readreg(state, 0x29);
+	if (tone & 0x10)
+		cx24123_writereg(state, 0x29, tone & ~0x50);
 
-
-	if (val) {
-		printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
-		return -ENOTSUPP;
-	}
-
+	/* wait for diseqc queue ready */
 	cx24123_wait_for_diseqc(state);
 
 	/* select tone mode */
-	val = cx24123_readreg(state, 0x2a) & 0xf8;
-	cx24123_writereg(state, 0x2a, val | 0x04);
-
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+	msleep(30);
 	val = cx24123_readreg(state, 0x29);
-
 	if (burst == SEC_MINI_A)
 		cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
 	else if (burst == SEC_MINI_B)
@@ -835,7 +756,12 @@
 		return -EINVAL;
 
 	cx24123_wait_for_diseqc(state);
+	cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
 
+	/* restart continuous tone if enabled */
+	if (tone & 0x10) {
+		cx24123_writereg(state, 0x29, tone & ~0x40);
+	}
 	return 0;
 }
 
@@ -976,38 +902,21 @@
 	struct cx24123_state *state = fe->demodulator_priv;
 	u8 val;
 
-	switch (state->config->use_isl6421) {
-	case 1:
+	/* wait for diseqc queue ready */
+	cx24123_wait_for_diseqc(state);
 
-		val = cx24123_readlnbreg(state, 0x0);
+	val = cx24123_readreg(state, 0x29) & ~0x40;
 
-		switch (tone) {
-		case SEC_TONE_ON:
-			dprintk("%s:  isl6421 sec tone on\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val | 0x10);
-		case SEC_TONE_OFF:
-			dprintk("%s:  isl6421 sec tone off\n",__FUNCTION__);
-			return cx24123_writelnbreg(state, 0x0, val & 0x2f);
-		default:
-			printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-			return -EINVAL;
-		}
-
-	case 0:
-
-		val = cx24123_readreg(state, 0x29);
-
-		switch (tone) {
-		case SEC_TONE_ON:
-			dprintk("%s: setting tone on\n", __FUNCTION__);
-			return cx24123_writereg(state, 0x29, val | 0x10);
-		case SEC_TONE_OFF:
-			dprintk("%s: setting tone off\n",__FUNCTION__);
-			return cx24123_writereg(state, 0x29, val & 0xef);
-		default:
-			printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
-			return -EINVAL;
-		}
+	switch (tone) {
+	case SEC_TONE_ON:
+		dprintk("%s: setting tone on\n", __FUNCTION__);
+		return cx24123_writereg(state, 0x29, val | 0x10);
+	case SEC_TONE_OFF:
+		dprintk("%s: setting tone off\n",__FUNCTION__);
+		return cx24123_writereg(state, 0x29, val & 0xef);
+	default:
+		printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+		return -EINVAL;
 	}
 
 	return 0;
@@ -1040,10 +949,8 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
 	state->snr = 0;
-	state->lnbreg = 0;
 	state->VCAarg = 0;
 	state->VGAarg = 0;
 	state->bandselectarg = 0;
@@ -1059,7 +966,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 0c922b5..9606f82 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -28,21 +28,8 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
-	/*
-	   cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
-	   for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
-	   from register 0x29 of the CX24123 demodulator
-	*/
-	int use_isl6421;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
-	void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
 };
 
 extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
index c31d6df..be1c0d3 100644
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ b/drivers/media/dvb/frontends/dib3000-common.h
@@ -38,8 +38,6 @@
 struct dib3000_state {
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 /* configuration settings */
 	struct dib3000_config config;
 
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index 2d5475b..ec92762 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -30,10 +30,6 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance and the i2c address of the PLL */
-	int (*pll_init)(struct dvb_frontend *fe);
-	int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
 };
 
 struct dib_fe_xfer_ops
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ae589ad..7c6dc7e 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -60,8 +60,9 @@
 	fe_code_rate_t fe_cr = FEC_NONE;
 	int search_state, seq;
 
-	if (tuner && state->config.pll_set) {
-		state->config.pll_set(fe, fep);
+	if (tuner && fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, fep);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
 		deb_setf("bandwidth: ");
 		switch (ofdm->bandwidth) {
@@ -386,9 +387,6 @@
 
 	wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
 
-	if (state->config.pll_init)
-		state->config.pll_init(fe);
-
 	return 0;
 }
 
@@ -707,7 +705,6 @@
 	/* setup the state */
 	state->i2c = i2c;
 	memcpy(&state->config,config,sizeof(struct dib3000_config));
-	memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check for the correct demod */
 	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -717,7 +714,7 @@
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	/* set the xfer operations */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 3b303db..6c3be25 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -462,8 +462,9 @@
 	int search_state,auto_val;
 	u16 val;
 
-	if (tuner && state->config.pll_set) { /* initial call from dvb */
-		state->config.pll_set(fe,fep);
+	if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+		fe->ops.tuner_ops.set_params(fe, fep);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
 		state->last_tuned_freq = fep->frequency;
 	//	if (!scanboost) {
@@ -642,9 +643,6 @@
 
 	set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
 
-	if (state->config.pll_init)
-		state->config.pll_init(fe);
-
 	deb_info("init end\n");
 	return 0;
 }
@@ -839,7 +837,6 @@
 	/* setup the state */
 	state->i2c = i2c;
 	memcpy(&state->config,config,sizeof(struct dib3000_config));
-	memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check for the correct demod */
 	if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -859,7 +856,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	/* set the xfer operations */
@@ -876,6 +873,7 @@
 	kfree(state);
 	return NULL;
 }
+EXPORT_SYMBOL(dib3000mc_attach);
 
 static struct dvb_frontend_ops dib3000mc_ops = {
 
@@ -914,5 +912,3 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 791706e..a189683 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -227,10 +227,10 @@
 EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
  */
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
-	.name  = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+	.name  = "LG TDVS-H06xF",
 	.min   =  54000000,
 	.max   = 863000000,
 	.count = 3,
@@ -240,7 +240,7 @@
 		{  999999999, 44000000, 62500, 0xce, 0x04 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
 
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
@@ -419,6 +419,19 @@
 };
 EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
 
+struct dvb_pll_priv {
+	/* i2c details */
+	int pll_i2c_address;
+	struct i2c_adapter *i2c;
+
+	/* the PLL descriptor */
+	struct dvb_pll_desc *pll_desc;
+
+	/* cached frequency/bandwidth */
+	u32 frequency;
+	u32 bandwidth;
+};
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
@@ -443,7 +456,8 @@
 	if (debug)
 		printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
 		       desc->name, freq, bandwidth, i, desc->count);
-	BUG_ON(i == desc->count);
+	if (i == desc->count)
+		return -EINVAL;
 
 	div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
 	buf[0] = div >> 8;
@@ -462,6 +476,163 @@
 }
 EXPORT_SYMBOL(dvb_pll_configure);
 
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+	if (fe->tuner_priv)
+		kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	u8 buf[4];
+	struct i2c_msg msg =
+		{ .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	int i;
+	int result;
+
+	for (i = 0; i < priv->pll_desc->count; i++) {
+		if (priv->pll_desc->entries[i].limit == 0)
+			break;
+	}
+	if (i == priv->pll_desc->count)
+		return 0;
+
+	buf[0] = 0;
+	buf[1] = 0;
+	buf[2] = priv->pll_desc->entries[i].config;
+	buf[3] = priv->pll_desc->entries[i].cb;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+		return result;
+	}
+
+	return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	u8 buf[4];
+	struct i2c_msg msg =
+		{ .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	int result;
+	u32 div;
+	int i;
+	u32 bandwidth = 0;
+
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
+	// DVBT bandwidth only just now
+	if (fe->ops.info.type == FE_OFDM) {
+		bandwidth = params->u.ofdm.bandwidth;
+	}
+
+	if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+		return result;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+		return result;
+	}
+
+	// calculate the frequency we set it to
+	for (i = 0; i < priv->pll_desc->count; i++) {
+		if (params->frequency > priv->pll_desc->entries[i].limit)
+			continue;
+		break;
+	}
+	div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+	priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+	priv->bandwidth = bandwidth;
+
+	return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	int result;
+	u32 div;
+	int i;
+	u32 bandwidth = 0;
+
+	if (buf_len < 5)
+		return -EINVAL;
+
+	// DVBT bandwidth only just now
+	if (fe->ops.info.type == FE_OFDM) {
+		bandwidth = params->u.ofdm.bandwidth;
+	}
+
+	if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+		return result;
+	buf[0] = priv->pll_i2c_address;
+
+	// calculate the frequency we set it to
+	for (i = 0; i < priv->pll_desc->count; i++) {
+		if (params->frequency > priv->pll_desc->entries[i].limit)
+			continue;
+		break;
+	}
+	div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+	priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+	priv->bandwidth = bandwidth;
+
+	return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+	.release = dvb_pll_release,
+	.sleep = dvb_pll_sleep,
+	.set_params = dvb_pll_set_params,
+	.calc_regs = dvb_pll_calc_regs,
+	.get_frequency = dvb_pll_get_frequency,
+	.get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+	struct dvb_pll_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->pll_i2c_address = pll_addr;
+	priv->i2c = i2c;
+	priv->pll_desc = desc;
+
+	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+	strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+	fe->ops.tuner_ops.info.frequency_min = desc->min;
+	fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+	fe->tuner_priv = priv;
+	return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
 MODULE_DESCRIPTION("dvb pll library");
 MODULE_AUTHOR("Gerd Knorr");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 2b84617..66361cd 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -5,6 +5,9 @@
 #ifndef __DVB_PLL_H__
 #define __DVB_PLL_H__
 
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
 struct dvb_pll_desc {
 	char *name;
 	u32  min;
@@ -31,7 +34,7 @@
 extern struct dvb_pll_desc dvb_pll_tua6010xs;
 extern struct dvb_pll_desc dvb_pll_env57h1xd5;
 extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
 extern struct dvb_pll_desc dvb_pll_tda665x;
 extern struct dvb_pll_desc dvb_pll_fmd1216me;
 extern struct dvb_pll_desc dvb_pll_tded4;
@@ -44,7 +47,18 @@
 
 extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
 
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 		      u32 freq, int bandwidth);
 
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
 #endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 645946a..6271b1e 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -30,7 +30,6 @@
 
 
 struct dvb_dummy_fe_state {
-	struct dvb_frontend_ops ops;
 	struct dvb_frontend frontend;
 };
 
@@ -77,6 +76,11 @@
 
 static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
+	if (fe->ops->tuner_ops->set_params) {
+		fe->ops->tuner_ops->set_params(fe, p);
+		if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+	}
+
 	return 0;
 }
 
@@ -116,11 +120,8 @@
 	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
-	/* setup the state */
-	memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -139,11 +140,8 @@
 	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
-	/* setup the state */
-	memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -162,11 +160,8 @@
 	state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
-	/* setup the state */
-	memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
new file mode 100644
index 0000000..58c34db
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -0,0 +1,149 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	u8			i2c_addr;
+	void			(*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
+				.buf = &isl6421->config,
+				.len = sizeof(isl6421->config) };
+
+	isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		isl6421->config |= ISL6421_EN1;
+		break;
+	case SEC_VOLTAGE_18:
+		isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	isl6421->config |= isl6421->override_or;
+	isl6421->config &= isl6421->override_and;
+
+	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = isl6421->i2c_addr, .flags = 0,
+				.buf = &isl6421->config,
+				.len = sizeof(isl6421->config) };
+
+	if (arg)
+		isl6421->config |= ISL6421_LLC1;
+	else
+		isl6421->config &= ~ISL6421_LLC1;
+
+	isl6421->config |= isl6421->override_or;
+	isl6421->config &= isl6421->override_and;
+
+	return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+	struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+	/* power off */
+	isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data & call next release routine */
+	fe->ops.release = isl6421->release_chain;
+	kfree(fe->misc_priv);
+	fe->misc_priv = NULL;
+	if (fe->ops.release)
+		fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+		   u8 override_set, u8 override_clear)
+{
+	struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+	if (!isl6421)
+		return -ENOMEM;
+
+	/* default configuration */
+	isl6421->config = ISL6421_ISEL1;
+	isl6421->i2c = i2c;
+	isl6421->i2c_addr = i2c_addr;
+	fe->misc_priv = isl6421;
+
+	/* bits which should be forced to '1' */
+	isl6421->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	isl6421->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(isl6421);
+		fe->misc_priv = NULL;
+		return -EIO;
+	}
+
+	/* install release callback */
+	isl6421->release_chain = fe->ops.release;
+	fe->ops.release = isl6421_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = isl6421_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+	return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
new file mode 100644
index 0000000..675f80a
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -0,0 +1,46 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1	0x01
+#define ISL6421_EN1	0x02
+#define ISL6421_VSEL1	0x04
+#define ISL6421_LLC1	0x08
+#define ISL6421_ENT1	0x10
+#define ISL6421_ISEL1	0x20
+#define ISL6421_DCL	0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+			  u8 override_set, u8 override_clear);
+
+#endif
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1c7c912..f3bc82e 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -32,7 +32,6 @@
 
 struct l64781_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct l64781_config* config;
 	struct dvb_frontend frontend;
 
@@ -141,7 +140,10 @@
 	u8 val0x06;
 	int bw = p->bandwidth - BANDWIDTH_8_MHZ;
 
-	state->config->pll_set(fe, param);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	if (param->inversion != INVERSION_ON &&
 	    param->inversion != INVERSION_OFF)
@@ -463,8 +465,6 @@
 	/* Everything is two's complement, soft bit and CSI_OUT too */
 	l64781_writereg (state, 0x1e, 0x09);
 
-	if (state->config->pll_init) state->config->pll_init(fe);
-
 	/* delay a bit after first init attempt */
 	if (state->first) {
 		state->first = 0;
@@ -508,7 +508,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
 	state->first = 1;
 
 	/**
@@ -554,7 +553,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 947f65f..83b8bc2 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -29,10 +29,6 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 
diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
new file mode 100644
index 0000000..754d51d
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg_h06xf.h
@@ -0,0 +1,64 @@
+/*
+ *  lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ *  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 _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+		     struct dvb_frontend_parameters* params)
+{
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+	int err;
+
+	dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lg_h06xf: %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[0] = buf[2];
+	buf[0] &= ~0x20;
+	buf[0] |= 0x18;
+	buf[1] = 0x50;
+	msg.len = 2;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+		printk(KERN_WARNING "lg_h06xf: %s error "
+			"(addr %02x <- %02x, err = %i)\n",
+			__FUNCTION__, buf[0], buf[1], err);
+		if (err < 0)
+			return err;
+		else
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+#endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 4691ac5..6e8ad17 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -29,6 +29,7 @@
  *   DViCO FusionHDTV 5 Lite
  *   DViCO FusionHDTV 5 USB Gold
  *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ *   pcHDTV HD5500
  *
  * TODO:
  * signal strength always returns 0.
@@ -59,7 +60,6 @@
 struct lgdt330x_state
 {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 
 	/* Configuration settings */
 	const struct lgdt330x_config* config;
@@ -399,8 +399,10 @@
 	}
 
 	/* Tune to the specified frequency */
-	if (state->config->pll_set)
-		state->config->pll_set(fe, param);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	/* Keep track of the new frequency */
 	/* FIXME this is the wrong way to do this...           */
@@ -672,6 +674,7 @@
 
 	if (state->current_modulation == VSB_8) {
 
+		i2c_read_demod_bytes(state, 0x6e, buf, 5);
 		/* Phase Tracker Mean-Square Error Register for VSB */
 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
 	} else {
@@ -721,16 +724,19 @@
 	/* Setup the state */
 	state->config = config;
 	state->i2c = i2c;
+
+	/* Create dvb_frontend */
 	switch (config->demod_chip) {
 	case LGDT3302:
-		memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	case LGDT3303:
-		memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+		memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
 		break;
 	default:
 		goto error;
 	}
+	state->frontend.demodulator_priv = state;
 
 	/* Verify communication with demod chip */
 	if (i2c_read_demod_bytes(state, 2, buf, 1))
@@ -739,9 +745,6 @@
 	state->current_frequency = -1;
 	state->current_modulation = -1;
 
-	/* Create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
 error:
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index 2a6529c..bad903c 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -43,7 +43,6 @@
 
 	/* PLL interface */
 	int (*pll_rf_set) (struct dvb_frontend* fe, int index);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
new file mode 100644
index 0000000..e933edc
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -0,0 +1,145 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+
+struct lnbp21 {
+	u8			config;
+	u8			override_or;
+	u8			override_and;
+	struct i2c_adapter	*i2c;
+	void			(*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+	switch(voltage) {
+	case SEC_VOLTAGE_OFF:
+		break;
+	case SEC_VOLTAGE_13:
+		lnbp21->config |= LNBP21_EN;
+		break;
+	case SEC_VOLTAGE_18:
+		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
+				.buf = &lnbp21->config,
+				.len = sizeof(lnbp21->config) };
+
+	if (arg)
+		lnbp21->config |= LNBP21_LLC;
+	else
+		lnbp21->config &= ~LNBP21_LLC;
+
+	lnbp21->config |= lnbp21->override_or;
+	lnbp21->config &= lnbp21->override_and;
+
+	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+	/* LNBP power off */
+	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	/* free data & call next release routine */
+	fe->ops.release = lnbp21->release_chain;
+	kfree(fe->misc_priv);
+	fe->misc_priv = NULL;
+	if (fe->ops.release)
+		fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+	if (!lnbp21)
+		return -ENOMEM;
+
+	/* default configuration */
+	lnbp21->config = LNBP21_ISEL;
+	lnbp21->i2c = i2c;
+	fe->misc_priv = lnbp21;
+
+	/* bits which should be forced to '1' */
+	lnbp21->override_or = override_set;
+
+	/* bits which should be forced to '0' */
+	lnbp21->override_and = ~override_clear;
+
+	/* detect if it is present or not */
+	if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+		kfree(lnbp21);
+		fe->misc_priv = NULL;
+		return -EIO;
+	}
+
+	/* install release callback */
+	lnbp21->release_chain = fe->ops.release;
+	fe->ops.release = lnbp21_release;
+
+	/* override frontend ops */
+	fe->ops.set_voltage = lnbp21_set_voltage;
+	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+	return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 0dcbe61..047a4ab 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -27,7 +27,7 @@
 #ifndef _LNBP21_H
 #define _LNBP21_H
 
-/* system register */
+/* system register bits */
 #define LNBP21_OLF	0x01
 #define LNBP21_OTF	0x02
 #define LNBP21_EN	0x04
@@ -37,103 +37,9 @@
 #define LNBP21_ISEL	0x40
 #define LNBP21_PCL	0x80
 
-struct lnbp21 {
-	u8			config;
-	u8			override_or;
-	u8			override_and;
-	struct i2c_adapter	*i2c;
-	void			(*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
 
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
-	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		break;
-	case SEC_VOLTAGE_13:
-		lnbp21->config |= LNBP21_EN;
-		break;
-	case SEC_VOLTAGE_18:
-		lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-	struct i2c_msg msg = {	.addr = 0x08, .flags = 0,
-				.buf = &lnbp21->config,
-				.len = sizeof(lnbp21->config) };
-
-	if (arg)
-		lnbp21->config |= LNBP21_LLC;
-	else
-		lnbp21->config &= ~LNBP21_LLC;
-
-	lnbp21->config |= lnbp21->override_or;
-	lnbp21->config &= lnbp21->override_and;
-
-	return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
-	struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
-	/* LNBP power off */
-	lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
-	/* free data & call next release routine */
-	fe->ops->release = lnbp21->release_chain;
-	kfree(fe->misc_priv);
-	fe->misc_priv = NULL;
-	if (fe->ops->release)
-		fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
-	struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
-	if (!lnbp21)
-		return -ENOMEM;
-
-	/* default configuration */
-	lnbp21->config = LNBP21_ISEL;
-
-	/* bits which should be forced to '1' */
-	lnbp21->override_or = override_set;
-
-	/* bits which should be forced to '0' */
-	lnbp21->override_and = ~override_clear;
-
-	/* install release callback */
-	lnbp21->release_chain = fe->ops->release;
-	fe->ops->release = lnbp21_exit;
-
-	/* override frontend ops */
-	fe->ops->set_voltage = lnbp21_set_voltage;
-	fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
-	lnbp21->i2c = i2c;
-	fe->misc_priv = lnbp21;
-
-	return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
 
 #endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index d3aea83..1ef8218 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -39,7 +39,6 @@
 
 struct mt312_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct mt312_config* config;
 	struct dvb_frontend frontend;
@@ -277,12 +276,6 @@
 	if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
 		return ret;
 
-	if (state->config->pll_init) {
-		mt312_writereg(state, GPP_CTRL, 0x40);
-		state->config->pll_init(fe);
-		mt312_writereg(state, GPP_CTRL, 0x00);
-	}
-
 	return 0;
 }
 
@@ -477,16 +470,16 @@
 
 	dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
 
-	if ((p->frequency < fe->ops->info.frequency_min)
-	    || (p->frequency > fe->ops->info.frequency_max))
+	if ((p->frequency < fe->ops.info.frequency_min)
+	    || (p->frequency > fe->ops.info.frequency_max))
 		return -EINVAL;
 
 	if ((p->inversion < INVERSION_OFF)
 	    || (p->inversion > INVERSION_ON))
 		return -EINVAL;
 
-	if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
-	    || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+	if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+	    || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
 		return -EINVAL;
 
 	if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -529,9 +522,10 @@
 		return -EINVAL;
 	}
 
-	mt312_writereg(state, GPP_CTRL, 0x40);
-	state->config->pll_set(fe, p);
-	mt312_writereg(state, GPP_CTRL, 0x00);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
 	sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -578,6 +572,17 @@
 	return 0;
 }
 
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct mt312_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return mt312_writereg(state, GPP_CTRL, 0x40);
+	} else {
+		return mt312_writereg(state, GPP_CTRL, 0x00);
+	}
+}
+
 static int mt312_sleep(struct dvb_frontend* fe)
 {
 	struct mt312_state *state = fe->demodulator_priv;
@@ -633,6 +638,7 @@
 
 	.init = mt312_initfe,
 	.sleep = mt312_sleep,
+	.i2c_gate_ctrl = mt312_i2c_gate_ctrl,
 
 	.set_frontend = mt312_set_frontend,
 	.get_frontend = mt312_get_frontend,
@@ -663,19 +669,22 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (mt312_readreg(state, ID, &state->id) < 0)
 		goto error;
 
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
 	switch (state->id) {
 	case ID_VP310:
-		strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
 		state->frequency = 90;
 		break;
 	case ID_MT312:
-		strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
 		state->frequency = 60;
 		break;
 	default:
@@ -683,9 +692,6 @@
 		goto error;
 	}
 
-	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
-	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
 error:
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 074d844..666a1bd 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -32,10 +32,6 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index aaaec90..5de7376 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -45,7 +45,6 @@
 struct mt352_state {
 	struct i2c_adapter* i2c;
 	struct dvb_frontend frontend;
-	struct dvb_frontend_ops ops;
 
 	/* configuration settings */
 	struct mt352_config config;
@@ -286,16 +285,25 @@
 
 	mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
 	mt352_calc_input_freq(state, buf+6);
-	state->config.pll_set(fe, param, buf+8);
 
-	mt352_write(fe, buf, sizeof(buf));
 	if (state->config.no_tuner) {
-		/* start decoding */
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe, param);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+
+		mt352_write(fe, buf, 8);
 		mt352_write(fe, fsm_go, 2);
 	} else {
-		/* start tuning */
-		mt352_write(fe, tuner_go, 2);
+		if (fe->ops.tuner_ops.calc_regs) {
+			fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+			buf[8] <<= 1;
+			mt352_write(fe, buf, sizeof(buf));
+			mt352_write(fe, tuner_go, 2);
+		}
 	}
+
 	return 0;
 }
 
@@ -541,13 +549,12 @@
 	/* setup the state */
 	state->i2c = i2c;
 	memcpy(&state->config,config,sizeof(struct mt352_config));
-	memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 03040cd..9e7ff4b 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -49,12 +49,6 @@
 
 	/* Initialise the demodulator and PLL. Cannot be NULL */
 	int (*demod_init)(struct dvb_frontend* fe);
-
-	/* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
-	 * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
-	 * byte1-4: PLL configuration.
-	 */
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
 };
 
 extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index 9e353539..55671cb 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -55,7 +55,6 @@
 struct nxt200x_state {
 
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct nxt200x_config* config;
 	struct dvb_frontend frontend;
 
@@ -333,17 +332,17 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+	dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
 
 	/* 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))
+			if (i2c_writebytes(state, data[0], data+1, 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);
+				i2c_readbytes(state, data[0], &buf, 1);
 				if (buf & 0x40)
 					return 0;
 				msleep(100);
@@ -361,10 +360,10 @@
 			nxt200x_writebytes(state, 0x34, &buf, 1);
 
 			/* write actual tuner bytes */
-			nxt200x_writebytes(state, 0x36, data, 4);
+			nxt200x_writebytes(state, 0x36, data+1, 4);
 
 			/* set tuner i2c address */
-			buf = state->config->pll_address;
+			buf = data[0] << 1;
 			nxt200x_writebytes(state, 0x35, &buf, 1);
 
 			/* write UC Opmode to begin transfer */
@@ -534,7 +533,7 @@
 					     struct dvb_frontend_parameters *p)
 {
 	struct nxt200x_state* state = fe->demodulator_priv;
-	u8 buf[4];
+	u8 buf[5];
 
 	/* stop the micro first */
 	nxt200x_microcontroller_stop(state);
@@ -548,7 +547,9 @@
 	}
 
 	/* get tuning information */
-	dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+	if (fe->ops.tuner_ops.calc_regs) {
+		fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+	}
 
 	/* set additional params */
 	switch (p->u.vsb.modulation) {
@@ -1159,7 +1160,6 @@
 	/* 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 */
@@ -1198,7 +1198,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 1d9d70b..34d6173 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,10 +38,6 @@
 	/* 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);
 
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index a16eeba..d313d7d 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -33,7 +33,6 @@
 
 struct nxt6000_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct nxt6000_config* config;
 	struct dvb_frontend frontend;
@@ -207,12 +206,6 @@
 		nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
 
 	nxt6000_writereg(state, TS_FORMAT, 0);
-
-	if (state->config->pll_init) {
-		nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);	/* open i2c bus switch */
-		state->config->pll_init(fe);
-		nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);	/* close i2c bus switch */
-	}
 }
 
 static void nxt6000_dump_status(struct nxt6000_state *state)
@@ -469,9 +462,10 @@
 	struct nxt6000_state* state = fe->demodulator_priv;
 	int result;
 
-	nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);	/* open i2c bus switch */
-	state->config->pll_set(fe, param);
-	nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);	/* close i2c bus switch */
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
 		return result;
@@ -532,6 +526,17 @@
 	return 0;
 }
 
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct nxt6000_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+	} else {
+		return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+	}
+}
+
 static struct dvb_frontend_ops nxt6000_ops;
 
 struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
@@ -546,13 +551,12 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -584,6 +588,7 @@
 	.release = nxt6000_release,
 
 	.init = nxt6000_init,
+	.i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
 
 	.get_tune_settings = nxt6000_fe_get_tune_settings,
 
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index b7d9bea..117031d 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -31,10 +31,6 @@
 
 	/* should clock inversion be used? */
 	u8 clock_inversion:1;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 80e0f28..d20ab30 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -54,7 +54,6 @@
 struct or51132_state
 {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 
 	/* Configuration settings */
 	const struct or51132_config* config;
@@ -106,9 +105,8 @@
 {
 	struct or51132_state* state = fe->demodulator_priv;
 	static u8 run_buf[] = {0x7F,0x01};
-	static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
-	u8 rec_buf[14];
-	u8 cmd_buf[14];
+	u8 rec_buf[8];
+	u8 cmd_buf[3];
 	u32 firmwareAsize, firmwareBsize;
 	int i,ret;
 
@@ -157,7 +155,6 @@
 	cmd_buf[0] = 0x10;
 	cmd_buf[1] = 0x10;
 	cmd_buf[2] = 0x00;
-	cmd_buf[3] = 0x00;
 	msleep(20); /* 20ms */
 	if ((ret = i2c_writebytes(state,state->config->demod_address,
 				 cmd_buf,3))) {
@@ -167,8 +164,6 @@
 
 	cmd_buf[0] = 0x04;
 	cmd_buf[1] = 0x17;
-	cmd_buf[2] = 0x00;
-	cmd_buf[3] = 0x00;
 	msleep(20); /* 20ms */
 	if ((ret = i2c_writebytes(state,state->config->demod_address,
 				 cmd_buf,2))) {
@@ -178,8 +173,6 @@
 
 	cmd_buf[0] = 0x00;
 	cmd_buf[1] = 0x00;
-	cmd_buf[2] = 0x00;
-	cmd_buf[3] = 0x00;
 	msleep(20); /* 20ms */
 	if ((ret = i2c_writebytes(state,state->config->demod_address,
 				 cmd_buf,2))) {
@@ -189,7 +182,11 @@
 
 	for(i=0;i<4;i++) {
 		msleep(20); /* 20ms */
-		get_ver_buf[4] = i+1;
+		/* Once upon a time, this command might have had something
+		   to do with getting the firmware version, but it's
+		   not used anymore:
+		   {0x04,0x00,0x30,0x00,i+1} */
+		/* Read 8 bytes, two bytes at a time */
 		if ((ret = i2c_readbytes(state,state->config->demod_address,
 					&rec_buf[i*2],2))) {
 			printk(KERN_WARNING
@@ -208,7 +205,6 @@
 	cmd_buf[0] = 0x10;
 	cmd_buf[1] = 0x00;
 	cmd_buf[2] = 0x00;
-	cmd_buf[3] = 0x00;
 	msleep(20); /* 20ms */
 	if ((ret = i2c_writebytes(state,state->config->demod_address,
 				 cmd_buf,3))) {
@@ -243,7 +239,7 @@
 static int or51132_setmode(struct dvb_frontend* fe)
 {
 	struct or51132_state* state = fe->demodulator_priv;
-	unsigned char cmd_buf[4];
+	unsigned char cmd_buf[3];
 
 	dprintk("setmode %d\n",(int)state->current_modulation);
 	/* set operation mode in Receiver 1 register; */
@@ -263,7 +259,6 @@
 	default:
 		printk("setmode:Modulation set to unsupported value\n");
 	};
-	cmd_buf[3] = 0x00;
 	if (i2c_writebytes(state,state->config->demod_address,
 			   cmd_buf,3)) {
 		printk(KERN_WARNING "or51132: set_mode error 1\n");
@@ -301,7 +296,6 @@
 	default:
 		printk("setmode: Modulation set to unsupported value\n");
 	};
-	cmd_buf[3] = 0x00;
 	msleep(20); /* 20ms */
 	if (i2c_writebytes(state,state->config->demod_address,
 			   cmd_buf,3)) {
@@ -313,52 +307,65 @@
 	return 0;
 }
 
+/* Some modulations use the same firmware.  This classifies modulations
+   by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN	0
+#define MOD_FWCLASS_VSB		1
+#define MOD_FWCLASS_QAM		2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+	switch(modulation) {
+	case VSB_8:
+		return MOD_FWCLASS_VSB;
+	case QAM_AUTO:
+	case QAM_64:
+	case QAM_256:
+		return MOD_FWCLASS_QAM;
+	default:
+		return MOD_FWCLASS_UNKNOWN;
+	}
+}
+
 static int or51132_set_parameters(struct dvb_frontend* fe,
 				  struct dvb_frontend_parameters *param)
 {
 	int ret;
-	u8 buf[4];
 	struct or51132_state* state = fe->demodulator_priv;
 	const struct firmware *fw;
+	const char *fwname;
+	int clock_mode;
 
-	/* Change only if we are actually changing the modulation */
-	if (state->current_modulation != param->u.vsb.modulation) {
-		switch(param->u.vsb.modulation) {
-		case VSB_8:
+	/* Upload new firmware only if we need a different one */
+	if (modulation_fw_class(state->current_modulation) !=
+	    modulation_fw_class(param->u.vsb.modulation)) {
+		switch(modulation_fw_class(param->u.vsb.modulation)) {
+		case MOD_FWCLASS_VSB:
 			dprintk("set_parameters VSB MODE\n");
-			printk("or51132: Waiting for firmware upload(%s)...\n",
-			       OR51132_VSB_FIRMWARE);
-			ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
-					       &state->i2c->dev);
-			if (ret){
-				printk(KERN_WARNING "or51132: No firmware up"
-				       "loaded(timeout or file not found?)\n");
-				return ret;
-			}
+			fwname = OR51132_VSB_FIRMWARE;
+
 			/* Set non-punctured clock for VSB */
-			state->config->set_ts_params(fe, 0);
+			clock_mode = 0;
 			break;
-		case QAM_AUTO:
-		case QAM_64:
-		case QAM_256:
+		case MOD_FWCLASS_QAM:
 			dprintk("set_parameters QAM MODE\n");
-			printk("or51132: Waiting for firmware upload(%s)...\n",
-			       OR51132_QAM_FIRMWARE);
-			ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
-					       &state->i2c->dev);
-			if (ret){
-				printk(KERN_WARNING "or51132: No firmware up"
-				       "loaded(timeout or file not found?)\n");
-				return ret;
-			}
+			fwname = OR51132_QAM_FIRMWARE;
+
 			/* Set punctured clock for QAM */
-			state->config->set_ts_params(fe, 1);
+			clock_mode = 1;
 			break;
 		default:
-			printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+			printk("or51132: Modulation type(%d) UNSUPPORTED\n",
 			       param->u.vsb.modulation);
 			return -1;
-		};
+		}
+		printk("or51132: Waiting for firmware upload(%s)...\n",
+		       fwname);
+		ret = request_firmware(&fw, fwname, &state->i2c->dev);
+		if (ret) {
+			printk(KERN_WARNING "or51132: No firmware up"
+			       "loaded(timeout or file not found?)\n");
+			return ret;
+		}
 		ret = or51132_load_firmware(fe, fw);
 		release_firmware(fw);
 		if (ret) {
@@ -367,18 +374,18 @@
 			return ret;
 		}
 		printk("or51132: Firmware upload complete.\n");
-
+		state->config->set_ts_params(fe, clock_mode);
+	}
+	/* Change only if we are actually changing the modulation */
+	if (state->current_modulation != param->u.vsb.modulation) {
 		state->current_modulation = param->u.vsb.modulation;
 		or51132_setmode(fe);
 	}
 
-	dvb_pll_configure(state->config->pll_desc, buf,
-			  param->frequency, 0);
-	dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
-		"0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
-	if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
-		printk(KERN_WARNING "or51132: set_parameters error "
-		       "writing to tuner\n");
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, param);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	/* Set to current mode */
 	or51132_setmode(fe);
@@ -388,6 +395,44 @@
 	return 0;
 }
 
+static int or51132_get_parameters(struct dvb_frontend* fe,
+				  struct dvb_frontend_parameters *param)
+{
+	struct or51132_state* state = fe->demodulator_priv;
+	u8 buf[2];
+
+	/* Receiver Status */
+	buf[0]=0x04;
+	buf[1]=0x00;
+	msleep(30); /* 30ms */
+	if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
+		printk(KERN_WARNING "or51132: get_parameters write error\n");
+		return -EREMOTEIO;
+	}
+	msleep(30); /* 30ms */
+	if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
+		printk(KERN_WARNING "or51132: get_parameters read error\n");
+		return -EREMOTEIO;
+	}
+	switch(buf[0]) {
+		case 0x06: param->u.vsb.modulation = VSB_8; break;
+		case 0x43: param->u.vsb.modulation = QAM_64; break;
+		case 0x45: param->u.vsb.modulation = QAM_256; break;
+		default:
+			printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+			       buf[0]);
+			return -EREMOTEIO;
+	}
+
+	/* FIXME: Read frequency from frontend, take AFC into account */
+	param->frequency = state->current_frequency;
+
+	/* FIXME: How to read inversion setting? Receiver 6 register? */
+	param->inversion = INVERSION_AUTO;
+
+	return 0;
+}
+
 static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
 	struct or51132_state* state = fe->demodulator_priv;
@@ -572,12 +617,11 @@
 	/* Setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
 	state->current_frequency = -1;
 	state->current_modulation = -1;
 
 	/* Create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -590,7 +634,7 @@
 
 	.info = {
 		.name			= "Oren OR51132 VSB/QAM Frontend",
-		.type 			= FE_ATSC,
+		.type			= FE_ATSC,
 		.frequency_min		= 44000000,
 		.frequency_max		= 958000000,
 		.frequency_stepsize	= 166666,
@@ -606,6 +650,7 @@
 	.sleep = or51132_sleep,
 
 	.set_frontend = or51132_set_parameters,
+	.get_frontend = or51132_get_parameters,
 	.get_tune_settings = or51132_get_tune_settings,
 
 	.read_status = or51132_read_status,
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index 622cdd1..8965888 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -29,8 +29,6 @@
 {
 	/* The demodulator's i2c address */
 	u8 demod_address;
-	u8 pll_address;
-	struct dvb_pll_desc *pll_desc;
 
 	/* Need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 7c3aed1..26bed61 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -54,7 +54,6 @@
 struct or51211_state {
 
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 
 	/* Configuration settings */
 	const struct or51211_config* config;
@@ -585,12 +584,11 @@
 	/* Setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
 	state->initialized = 0;
 	state->current_frequency = 0;
 
 	/* Create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index d694775..2c2c344 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -38,7 +38,6 @@
 
 struct s5h1420_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct s5h1420_config* config;
 	struct dvb_frontend frontend;
 
@@ -584,7 +583,6 @@
 	struct s5h1420_state* state = fe->demodulator_priv;
 	int frequency_delta;
 	struct dvb_frontend_tune_settings fesettings;
-	u32 tmp;
 
 	/* check if we should do a fast-tune */
 	memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
@@ -596,10 +594,17 @@
 	    (state->fec_inner == p->u.qpsk.fec_inner) &&
 	    (state->symbol_rate == p->u.qpsk.symbol_rate)) {
 
-		if (state->config->pll_set) {
-			s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-			state->config->pll_set(fe, p, &tmp);
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe, p);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (fe->ops.tuner_ops.get_frequency) {
+			u32 tmp;
+			fe->ops.tuner_ops.get_frequency(fe, &tmp);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 			s5h1420_setfreqoffset(state, p->frequency - tmp);
+		} else {
+			s5h1420_setfreqoffset(state, 0);
 		}
 		return 0;
 	}
@@ -646,9 +651,9 @@
 	s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
 
 	/* set tuner PLL */
-	if (state->config->pll_set) {
-		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-		state->config->pll_set(fe, p, &tmp);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 		s5h1420_setfreqoffset(state, 0);
 	}
 
@@ -708,6 +713,17 @@
 	return 0;
 }
 
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+	} else {
+		return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+	}
+}
+
 static int s5h1420_init (struct dvb_frontend* fe)
 {
 	struct s5h1420_state* state = fe->demodulator_priv;
@@ -717,13 +733,6 @@
 	msleep(10);
 	s5h1420_reset(state);
 
-	/* init PLL */
-	if (state->config->pll_init) {
-		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
-		state->config->pll_init(fe);
-		s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
-	}
-
 	return 0;
 }
 
@@ -756,7 +765,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
 	state->postlocked = 0;
 	state->fclk = 88000000;
 	state->tunedfreq = 0;
@@ -769,7 +777,7 @@
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -800,6 +808,7 @@
 
 	.init = s5h1420_init,
 	.sleep = s5h1420_sleep,
+	.i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
 
 	.set_frontend = s5h1420_set_frontend,
 	.get_frontend = s5h1420_get_frontend,
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 73296f1..4e39015 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -32,10 +32,6 @@
 
 	/* does the inversion require inversion? */
 	u8 invert:1;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
 };
 
 extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index 73829e6..44ec5b9 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -44,8 +44,6 @@
 
 	struct i2c_adapter* i2c;
 
-	struct dvb_frontend_ops ops;
-
 	const struct sp8870_config* config;
 
 	struct dvb_frontend frontend;
@@ -262,9 +260,10 @@
 	sp8870_microcontroller_stop(state);
 
 	// set tuner parameters
-	sp8870_writereg(state, 0x206, 0x001);
-	state->config->pll_set(fe, p);
-	sp8870_writereg(state, 0x206, 0x000);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	// sample rate correction bit [23..17]
 	sp8870_writereg(state, 0x0319, 0x000A);
@@ -349,13 +348,6 @@
 	sp8870_writereg(state, 0x0D00, 0x010);
 	sp8870_writereg(state, 0x0D01, 0x000);
 
-	/* setup PLL */
-	if (state->config->pll_init) {
-		sp8870_writereg(state, 0x206, 0x001);
-		state->config->pll_init(fe);
-		sp8870_writereg(state, 0x206, 0x000);
-	}
-
 	return 0;
 }
 
@@ -541,6 +533,17 @@
 	return 0;
 }
 
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct sp8870_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return sp8870_writereg(state, 0x206, 0x001);
+	} else {
+		return sp8870_writereg(state, 0x206, 0x000);
+	}
+}
+
 static void sp8870_release(struct dvb_frontend* fe)
 {
 	struct sp8870_state* state = fe->demodulator_priv;
@@ -561,14 +564,13 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
 	state->initialised = 0;
 
 	/* check if the demod is there */
 	if (sp8870_readreg(state, 0x0200) < 0) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -597,6 +599,7 @@
 
 	.init = sp8870_init,
 	.sleep = sp8870_sleep,
+	.i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
 
 	.set_frontend = sp8870_set_frontend,
 	.get_tune_settings = sp8870_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index f3b555d..93afbb9 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -31,10 +31,6 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
 	/* request firmware for device */
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index eb8a602..b0a2b02 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -24,7 +24,6 @@
 
 struct sp887x_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct sp887x_config* config;
 	struct dvb_frontend frontend;
 
@@ -208,15 +207,6 @@
 	/* bit 0x010: enable data valid signal */
 	sp887x_writereg(state, 0xd00, 0x010);
 	sp887x_writereg(state, 0x0d1, 0x000);
-
-	/* setup the PLL */
-	if (state->config->pll_init) {
-		sp887x_writereg(state, 0x206, 0x001);
-		state->config->pll_init(fe);
-		sp887x_writereg(state, 0x206, 0x000);
-	}
-
-	printk ("done.\n");
 	return 0;
 };
 
@@ -362,9 +352,16 @@
 	sp887x_microcontroller_stop(state);
 
 	/* setup the PLL */
-	sp887x_writereg(state, 0x206, 0x001);
-	actual_freq = state->config->pll_set(fe, p);
-	sp887x_writereg(state, 0x206, 0x000);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+	if (fe->ops.tuner_ops.get_frequency) {
+		fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	} else {
+		actual_freq = p->frequency;
+	}
 
 	/* read status reg in order to clear <pending irqs */
 	sp887x_readreg(state, 0x200);
@@ -486,6 +483,17 @@
 	return 0;
 }
 
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct sp887x_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return sp887x_writereg(state, 0x206, 0x001);
+	} else {
+		return sp887x_writereg(state, 0x206, 0x000);
+	}
+}
+
 static int sp887x_sleep(struct dvb_frontend* fe)
 {
 	struct sp887x_state* state = fe->demodulator_priv;
@@ -555,14 +563,13 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
 	state->initialised = 0;
 
 	/* check if the demod is there */
 	if (sp887x_readreg(state, 0x0200) < 0) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -589,6 +596,7 @@
 
 	.init = sp887x_init,
 	.sleep = sp887x_sleep,
+	.i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
 
 	.set_frontend = sp887x_setup_frontend_parameters,
 	.get_tune_settings = sp887x_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index 6a05d8f..c44b0eb 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -13,12 +13,6 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-
-	/* this should return the actual frequency tuned to */
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
 	/* request firmware for device */
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index eb15676..1ca6424 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -32,7 +32,6 @@
 
 struct stv0297_state {
 	struct i2c_adapter *i2c;
-	struct dvb_frontend_ops ops;
 	const struct stv0297_config *config;
 	struct dvb_frontend frontend;
 
@@ -68,19 +67,25 @@
 	int ret;
 	u8 b0[] = { reg };
 	u8 b1[] = { 0 };
-	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
-				  1},
-	{.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
-	};
+	struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+				 {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+			       };
 
 	// this device needs a STOP between the register and data
-	if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
-		return -1;
-	}
-	if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
-		return -1;
+	if (state->config->stop_during_read) {
+		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+			return -1;
+		}
+		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+			return -1;
+		}
+	} else {
+		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+			return -1;
+		}
 	}
 
 	return b1[0];
@@ -107,13 +112,20 @@
 	};
 
 	// this device needs a STOP between the register and data
-	if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
-		return -1;
-	}
-	if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
-		dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
-		return -1;
+	if (state->config->stop_during_read) {
+		if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+			return -1;
+		}
+		if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+			return -1;
+		}
+	} else {
+		if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+			dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+			return -1;
+		}
 	}
 
 	return 0;
@@ -276,12 +288,14 @@
 	return 0;
 }
 
-int stv0297_enable_plli2c(struct dvb_frontend *fe)
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
 	struct stv0297_state *state = fe->demodulator_priv;
 
-	stv0297_writereg(state, 0x87, 0x78);
-	stv0297_writereg(state, 0x86, 0xc8);
+	if (enable) {
+		stv0297_writereg(state, 0x87, 0x78);
+		stv0297_writereg(state, 0x86, 0xc8);
+	}
 
 	return 0;
 }
@@ -296,9 +310,6 @@
 		stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
 	msleep(200);
 
-	if (state->config->pll_init)
-		state->config->pll_init(fe);
-
 	return 0;
 }
 
@@ -389,7 +400,7 @@
 	case QAM_32:
 	case QAM_64:
 		delay = 100;
-		sweeprate = 1500;
+		sweeprate = 1000;
 		break;
 
 	case QAM_128:
@@ -421,7 +432,10 @@
 	}
 
 	stv0297_init(fe);
-	state->config->pll_set(fe, p);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	/* clear software interrupts */
 	stv0297_writereg(state, 0x82, 0x0);
@@ -634,7 +648,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
 	state->base_freq = 0;
 
 	/* check if the demod is there */
@@ -642,7 +655,7 @@
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -668,6 +681,7 @@
 
 	.init = stv0297_init,
 	.sleep = stv0297_sleep,
+	.i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
 
 	.set_frontend = stv0297_set_frontend,
 	.get_frontend = stv0297_get_frontend,
@@ -684,4 +698,3 @@
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(stv0297_attach);
-EXPORT_SYMBOL(stv0297_enable_plli2c);
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 9e53f01..1da5384 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -38,13 +38,11 @@
 	/* does the "inversion" need inverted? */
 	u8 invert:1;
 
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+	/* set to 1 if the device requires an i2c STOP during reading */
+	u8 stop_during_read:1;
 };
 
 extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
 					   struct i2c_adapter* i2c);
-extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
 
 #endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 5bcd00f..96648a7 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -56,7 +56,6 @@
 
 struct stv0299_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct stv0299_config* config;
 	struct dvb_frontend frontend;
 
@@ -131,13 +130,6 @@
 	return ret == 2 ? 0 : ret;
 }
 
-int stv0299_enable_plli2c (struct dvb_frontend* fe)
-{
-	struct stv0299_state* state = fe->demodulator_priv;
-
-	return stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
-}
-
 static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
 {
 	dprintk ("%s\n", __FUNCTION__);
@@ -457,12 +449,6 @@
 	for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
 		stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
 
-	if (state->config->pll_init) {
-		stv0299_writeregI(state, 0x05, 0xb5);	/*  enable i2c repeater on stv0299  */
-		state->config->pll_init(fe, state->i2c);
-		stv0299_writeregI(state, 0x05, 0x35);	/*  disable i2c repeater on stv0299  */
-	}
-
 	return 0;
 }
 
@@ -560,9 +546,10 @@
 	if (state->config->invert) invval = (~invval) & 1;
 	stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
 
-	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 (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	stv0299_set_FEC (state, p->u.qpsk.fec_inner);
 	stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
@@ -611,6 +598,19 @@
 	return 0;
 }
 
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct stv0299_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		stv0299_writeregI(state, 0x05, 0xb5);
+	} else {
+		stv0299_writeregI(state, 0x05, 0x35);
+	}
+	udelay(1);
+	return 0;
+}
+
 static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
 	struct stv0299_state* state = fe->demodulator_priv;
@@ -647,7 +647,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
 	state->initialised = 0;
 	state->tuner_frequency = 0;
 	state->symbol_rate = 0;
@@ -664,7 +663,7 @@
 	if (id != 0xa1 && id != 0x80) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -695,6 +694,7 @@
 
 	.init = stv0299_init,
 	.sleep = stv0299_sleep,
+	.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
 
 	.set_frontend = stv0299_set_frontend,
 	.get_frontend = stv0299_get_frontend,
@@ -721,9 +721,8 @@
 
 MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
 MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
-	      "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
+	      "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(stv0299_enable_plli2c);
 EXPORT_SYMBOL(stv0299_writereg);
 EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 32c87b4..1504828 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -87,14 +87,9 @@
 
 	/* Set the symbol rate */
 	int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c);
-	int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params);
 };
 
 extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
 
 extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
 					   struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 21255ca..e83ff21 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -36,7 +36,6 @@
 
 struct tda10021_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct tda10021_config* config;
 	struct dvb_frontend frontend;
@@ -90,6 +89,14 @@
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
+int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	return tda10021_writereg(state, reg, data);
+}
+EXPORT_SYMBOL(tda10021_write_byte);
+
 static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
 {
 	u8 b0 [] = { reg };
@@ -225,13 +232,6 @@
 
 	//Activate PLL
 	tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-
-	if (state->config->pll_init) {
-		lock_tuner(state);
-		state->config->pll_init(fe);
-		unlock_tuner(state);
-	}
-
 	return 0;
 }
 
@@ -259,9 +259,10 @@
 
 	//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
 
-	lock_tuner(state);
-	state->config->pll_set(fe, p);
-	unlock_tuner(state);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 
 	tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
 	tda10021_writereg (state, 0x34, state->pwm);
@@ -376,6 +377,18 @@
 	return 0;
 }
 
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10021_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		lock_tuner(state);
+	} else {
+		unlock_tuner(state);
+	}
+	return 0;
+}
+
 static int tda10021_sleep(struct dvb_frontend* fe)
 {
 	struct tda10021_state* state = fe->demodulator_priv;
@@ -407,7 +420,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
 	state->pwm = pwm;
 	state->reg0 = tda10021_inittab[0];
 
@@ -415,7 +427,7 @@
 	if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -448,6 +460,7 @@
 
 	.init = tda10021_init,
 	.sleep = tda10021_sleep,
+	.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
 
 	.set_frontend = tda10021_set_parameters,
 	.get_frontend = tda10021_get_frontend,
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
index 53be939..b1df425 100644
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -30,13 +30,11 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
 					    struct i2c_adapter* i2c, u8 pwm);
 
+extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+
 #endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index b83dafa..59a2ed6 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -47,7 +47,6 @@
 
 struct tda1004x_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	const struct tda1004x_config* config;
 	struct dvb_frontend frontend;
 
@@ -600,13 +599,6 @@
 
 	tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
 
-	// Init the PLL
-	if (state->config->pll_init) {
-		tda1004x_enable_tuner_i2c(state);
-		state->config->pll_init(fe);
-		tda1004x_disable_tuner_i2c(state);
-	}
-
 	// tda setup
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
 	tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
@@ -635,16 +627,6 @@
 			return -EIO;
 	}
 
-	// Init the tuner PLL
-	if (state->config->pll_init) {
-		tda1004x_enable_tuner_i2c(state);
-		if (state->config->pll_init(fe)) {
-			printk(KERN_ERR "tda1004x: pll init failed\n");
-			return 	-EIO;
-		}
-		tda1004x_disable_tuner_i2c(state);
-	}
-
 	// tda setup
 	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
 	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
@@ -712,12 +694,10 @@
 	}
 
 	// set frequency
-	tda1004x_enable_tuner_i2c(state);
-	if (state->config->pll_set(fe, fe_params)) {
-		printk(KERN_ERR "tda1004x: pll set failed\n");
-		return 	-EIO;
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, fe_params);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 	}
-	tda1004x_disable_tuner_i2c(state);
 
 	// Hardcoded to use auto as much as possible on the TDA10045 as it
 	// is very unreliable if AUTO mode is _not_ used.
@@ -1183,16 +1163,6 @@
 		break;
 
 	case TDA1004X_DEMOD_TDA10046:
-		if (state->config->pll_sleep != NULL) {
-			tda1004x_enable_tuner_i2c(state);
-			state->config->pll_sleep(fe);
-			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);
-			}
-		}
 		/* set outputs to tristate */
 		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
@@ -1202,6 +1172,17 @@
 	return 0;
 }
 
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda1004x_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return tda1004x_enable_tuner_i2c(state);
+	} else {
+		return tda1004x_disable_tuner_i2c(state);
+	}
+}
+
 static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
 	fesettings->min_delay_ms = 800;
@@ -1235,6 +1216,7 @@
 
 	.init = tda10045_init,
 	.sleep = tda1004x_sleep,
+	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
 
 	.set_frontend = tda1004x_set_fe,
 	.get_frontend = tda1004x_get_fe,
@@ -1260,7 +1242,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
 	state->demod_type = TDA1004X_DEMOD_TDA10045;
 
 	/* check if the demod is there */
@@ -1270,7 +1251,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 }
@@ -1293,6 +1274,7 @@
 
 	.init = tda10046_init,
 	.sleep = tda1004x_sleep,
+	.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
 
 	.set_frontend = tda1004x_set_fe,
 	.get_frontend = tda1004x_get_fe,
@@ -1318,7 +1300,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
 	state->demod_type = TDA1004X_DEMOD_TDA10046;
 
 	/* check if the demod is there */
@@ -1328,7 +1309,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 }
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index cc0c4af..b877b23 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -66,11 +66,6 @@
 	/* AGC configuration */
 	enum tda10046_agc agc_config;
 
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	void (*pll_sleep)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
 	/* request firmware for device */
 	/* set this to NULL if the card has a firmware EEPROM */
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 91baa9c..3aa45eb 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -37,7 +37,6 @@
 
 struct tda8083_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct tda8083_config* config;
 	struct dvb_frontend frontend;
@@ -293,7 +292,11 @@
 {
 	struct tda8083_state* state = fe->demodulator_priv;
 
-	state->config->pll_set(fe, p);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
 	tda8083_set_inversion (state, p->inversion);
 	tda8083_set_fec (state, p->u.qpsk.fec_inner);
 	tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -334,8 +337,6 @@
 	for (i=0; i<44; i++)
 		tda8083_writereg (state, i, tda8083_init_tab[i]);
 
-	if (state->config->pll_init) state->config->pll_init(fe);
-
 	tda8083_writereg (state, 0x00, 0x3c);
 	tda8083_writereg (state, 0x00, 0x04);
 
@@ -395,13 +396,12 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index 4666633..e7a48f6 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -33,10 +33,6 @@
 {
 	/* the demodulator's i2c address */
 	u8 demod_address;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index ad8647a3..6bffe85 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -35,7 +35,6 @@
 
 struct ves1820_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct ves1820_config* config;
 	struct dvb_frontend frontend;
@@ -204,9 +203,6 @@
 
 	ves1820_writereg(state, 0x34, state->pwm);
 
-	if (state->config->pll_init)
-		state->config->pll_init(fe);
-
 	return 0;
 }
 
@@ -223,7 +219,11 @@
 	if (real_qam < 0 || real_qam > 4)
 		return -EINVAL;
 
-	state->config->pll_set(fe, p);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
 	ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
 	ves1820_writereg(state, 0x34, state->pwm);
 
@@ -380,7 +380,6 @@
 		goto error;
 
 	/* setup the state */
-	memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
 	state->reg0 = ves1820_inittab[0];
 	state->config = config;
 	state->i2c = i2c;
@@ -393,12 +392,12 @@
 	if (verbose)
 		printk("ves1820: pwm=0x%02x\n", state->pwm);
 
-	state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
-	state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
-
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64;      /* SACLK/64 == (XIN/2)/64 */
+	state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4;       /* SACLK/4 */
 	state->frontend.demodulator_priv = state;
+
 	return &state->frontend;
 
 error:
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index 355f130..520f095 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -39,10 +39,6 @@
 
 	/* SELAGC control */
 	u8 selagc:1;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 821df8e..54d7b07 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -36,7 +36,6 @@
 
 struct ves1x93_state {
 	struct i2c_adapter* i2c;
-	struct dvb_frontend_ops ops;
 	/* configuration settings */
 	const struct ves1x93_config* config;
 	struct dvb_frontend frontend;
@@ -278,12 +277,6 @@
 		}
 	}
 
-	if (state->config->pll_init) {
-		ves1x93_writereg(state, 0x00, 0x11);
-		state->config->pll_init(fe);
-		ves1x93_writereg(state, 0x00, 0x01);
-	}
-
 	return 0;
 }
 
@@ -395,9 +388,10 @@
 {
 	struct ves1x93_state* state = fe->demodulator_priv;
 
-	ves1x93_writereg(state, 0x00, 0x11);
-	state->config->pll_set(fe, p);
-	ves1x93_writereg(state, 0x00, 0x01);
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
 	ves1x93_set_inversion (state, p->inversion);
 	ves1x93_set_fec (state, p->u.qpsk.fec_inner);
 	ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -442,6 +436,17 @@
 	kfree(state);
 }
 
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct ves1x93_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		return ves1x93_writereg(state, 0x00, 0x11);
+	} else {
+		return ves1x93_writereg(state, 0x00, 0x01);
+	}
+}
+
 static struct dvb_frontend_ops ves1x93_ops;
 
 struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
@@ -457,7 +462,6 @@
 	/* setup the state */
 	state->config = config;
 	state->i2c = i2c;
-	memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
 	state->inversion = INVERSION_OFF;
 
 	/* check if the demod is there + identify it */
@@ -492,7 +496,7 @@
 	}
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 
@@ -523,6 +527,7 @@
 
 	.init = ves1x93_init,
 	.sleep = ves1x93_sleep,
+	.i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
 
 	.set_frontend = ves1x93_set_frontend,
 	.get_frontend = ves1x93_get_frontend,
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index 1627e37..ba88ae0 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -38,10 +38,6 @@
 
 	/* should PWM be inverted? */
 	u8 invert_pwm:1;
-
-	/* PLL maintenance */
-	int (*pll_init)(struct dvb_frontend* fe);
-	int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
 };
 
 extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index d7d9f59..2b95e8b 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -34,7 +34,6 @@
 struct zl10353_state {
 	struct i2c_adapter *i2c;
 	struct dvb_frontend frontend;
-	struct dvb_frontend_ops ops;
 
 	struct zl10353_config config;
 };
@@ -126,6 +125,7 @@
 				  struct dvb_frontend_parameters *param)
 {
 	struct zl10353_state *state = fe->demodulator_priv;
+
 	u8 pllbuf[6] = { 0x67 };
 
 	/* These settings set "auto-everything" and start the FSM. */
@@ -142,7 +142,30 @@
 	zl10353_single_write(fe, 0x66, 0xE9);
 	zl10353_single_write(fe, 0x62, 0x0A);
 
-	state->config.pll_set(fe, param, pllbuf + 1);
+	// if there is no attached secondary tuner, we call set_params to program
+	// a potential tuner attached somewhere else
+	if (state->config.no_tuner) {
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe, param);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+	}
+
+	// if pllbuf is defined, retrieve the settings
+	if (fe->ops.tuner_ops.calc_regs) {
+		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+		pllbuf[1] <<= 1;
+	} else {
+		// fake pllbuf settings
+		pllbuf[1] = 0x61 << 1;
+		pllbuf[2] = 0;
+		pllbuf[3] = 0;
+		pllbuf[3] = 0;
+		pllbuf[4] = 0;
+	}
+
+	// there is no call to _just_ start decoding, so we send the pllbuf anyway
+	// even if there isn't a PLL attached to the secondary bus
 	zl10353_write(fe, pllbuf, sizeof(pllbuf));
 
 	zl10353_single_write(fe, 0x70, 0x01);
@@ -254,14 +277,13 @@
 	/* setup the state */
 	state->i2c = i2c;
 	memcpy(&state->config, config, sizeof(struct zl10353_config));
-	memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
 
 	/* check if the demod is there */
 	if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
 		goto error;
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	return &state->frontend;
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 5cc4ae71..9770cb8 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -29,10 +29,8 @@
 	/* demodulator's I2C address */
 	u8 demod_address;
 
-	/* function which configures the PLL buffer (for secondary I2C
-	 * connected tuner) or tunes the PLL (for direct connected tuner) */
-	int (*pll_set)(struct dvb_frontend *fe,
-		       struct dvb_frontend_parameters *params, u8 *pllbuf);
+	/* set if no pll is connected to the secondary i2c bus */
+	int no_tuner;
 };
 
 extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 1c5316e..acabea0 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -424,8 +424,8 @@
 }
 
 /* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
-				struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
+					 struct dvb_frontend_parameters *p)
 {
 	struct pluto *pluto = frontend_to_pluto(fe);
 	struct i2c_msg msg;
@@ -473,6 +473,8 @@
 	msg.buf = buf;
 	msg.len = sizeof(buf);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
 	if (ret < 0)
 		return ret;
@@ -497,8 +499,6 @@
 	.xtal_freq = TDA10046_XTAL_16M,
 	.agc_config = TDA10046_AGC_DEFAULT,
 	.if_freq = TDA10046_FREQ_3617,
-	.pll_set = lg_tdtpe001p_pll_set,
-	.pll_sleep = NULL,
 	.request_firmware = pluto2_request_firmware,
 };
 
@@ -511,11 +511,12 @@
 		dev_err(&pluto->pdev->dev, "could not attach frontend\n");
 		return -ENODEV;
 	}
+	pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
 
 	ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
 	if (ret < 0) {
-		if (pluto->fe->ops->release)
-			pluto->fe->ops->release(pluto->fe);
+		if (pluto->fe->ops.release)
+			pluto->fe->ops.release(pluto->fe);
 		return ret;
 	}
 
@@ -647,7 +648,7 @@
 		goto err_pluto_hw_exit;
 
 	/* dvb */
-	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+	ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
 	if (ret < 0)
 		goto err_i2c_bit_del_bus;
 
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index b5ac7df..987881f 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -10,6 +10,7 @@
 	select DVB_SP8870
 	select DVB_STV0297
 	select DVB_L64781
+	select DVB_LNBP21
 	help
 	  Support for SAA7146 and AV7110 based DVB cards as produced
 	  by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -67,6 +68,7 @@
 	select DVB_TDA8083
 	select DVB_TDA10021
 	select DVB_S5H1420
+	select DVB_LNBP21
 	help
 	  Support for simple SAA7146 based DVB cards
 	  (so called Budget- or Nova-PCI cards) without onboard
@@ -84,6 +86,7 @@
 	select DVB_STV0297
 	select DVB_STV0299
 	select DVB_TDA1004X
+	select DVB_LNBP21
 	help
 	  Support for simple SAA7146 based DVB cards
 	  (so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index a690730..aa85ecd 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -15,9 +15,9 @@
 
 hostprogs-y	:= fdump
 
-ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
+ifeq ($(CONFIG_DVB_AV7110_FIRMWARE),y)
+$(obj)/av7110.o: $(obj)/av7110_firm.h
 
-$(obj)/av7110_firm.h:
+$(obj)/av7110_firm.h: $(obj)/fdump
 	$(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
 endif
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index d028245..7a5c99c 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -152,13 +152,9 @@
 	/* remaining inits according to card and frontend type */
 	av7110->analog_tuner_flags = 0;
 	av7110->current_input = 0;
-	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
-		printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
-			av7110->dvb_adapter.num);
-		av7110->adac_type = DVB_ADAC_MSP34x5;
+	if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a)
 		av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
-	}
-	else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+	if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
 		printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
 			av7110->dvb_adapter.num);
 		av7110->adac_type = DVB_ADAC_CRYSTAL;
@@ -1552,7 +1548,7 @@
 #endif
 
 
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 	u8 pwr = 0;
@@ -1575,6 +1571,8 @@
 	// NOTE: since we're using a prescaler of 2, we set the
 	// divisor frequency to 62.5kHz and divide by 125 above
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -1584,10 +1582,9 @@
 	.demod_address = 0x08,
 	.xin = 90100000UL,
 	.invert_pwm = 0,
-	.pll_set = alps_bsrv2_pll_set,
 };
 
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 	u32 div;
@@ -1601,6 +1598,8 @@
 	data[2] = 0x85 | ((div >> 10) & 0x60);
 	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -1611,14 +1610,12 @@
 	.xin = 57840000UL,
 	.invert = 1,
 	.selagc = VES1820_SELAGC_SIGNAMPERR,
-	.pll_set = alps_tdbe2_pll_set,
 };
 
 
 
 
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
-				     struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 	u32 div;
@@ -1631,6 +1628,8 @@
 	data[2] = 0x8e;
 	data[3] = 0x00;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -1638,13 +1637,11 @@
 
 static struct tda8083_config grundig_29504_451_config = {
 	.demod_address = 0x68,
-	.pll_set = grundig_29504_451_pll_set,
 };
 
 
 
-static int philips_cd1516_pll_set(struct dvb_frontend* fe,
-				  struct dvb_frontend_parameters* params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 	u32 div;
@@ -1659,6 +1656,8 @@
 	data[2] = 0x8e;
 	data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -1669,12 +1668,11 @@
 	.xin = 57840000UL,
 	.invert = 1,
 	.selagc = VES1820_SELAGC_SIGNAMPERR,
-	.pll_set = philips_cd1516_pll_set,
 };
 
 
 
-static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 	u32 div, pwr;
@@ -1693,6 +1691,8 @@
 	data[2] = 0x85;
 	data[3] = pwr << 6;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -1708,7 +1708,6 @@
 static struct sp8870_config alps_tdlb7_config = {
 
 	.demod_address = 0x71,
-	.pll_set = alps_tdlb7_pll_set,
 	.request_firmware = alps_tdlb7_request_firmware,
 };
 
@@ -1806,7 +1805,7 @@
 	0xff, 0xff,
 };
 
-static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = fe->dvb->priv;
 	u32 div;
@@ -1832,7 +1831,8 @@
 	else
 		return -EINVAL;
 
-	stv0297_enable_plli2c(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
 		printk("nexusca: pll transfer failed!\n");
 		return -EIO;
@@ -1840,8 +1840,8 @@
 
 	// wait for PLL lock
 	for(i = 0; i < 20; i++) {
-
-		stv0297_enable_plli2c(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
 		if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
 			if (data[0] & 0x40) break;
 		msleep(10);
@@ -1855,12 +1855,12 @@
 	.demod_address = 0x1C,
 	.inittab = nexusca_stv0297_inittab,
 	.invert = 1,
-	.pll_set = nexusca_stv0297_pll_set,
+	.stop_during_read = 1,
 };
 
 
 
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
 {
 	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 	u32 div;
@@ -1887,13 +1887,14 @@
 	data[2] = ((div >> 10) & 0x60) | cfg;
 	data[3] = (cpump << 6) | band_select;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
 static struct l64781_config grundig_29504_401_config = {
 	.demod_address = 0x55,
-	.pll_set = grundig_29504_401_pll_set,
 };
 
 
@@ -2079,6 +2080,9 @@
 		case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
 			av7110->fe = ves1820_attach(&philips_cd1516_config,
 						    &av7110->i2c_adap, read_pwm(av7110));
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+			}
 			break;
 		}
 
@@ -2091,9 +2095,10 @@
 			// try the ALPS BSRV2 first of all
 			av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
 				av7110->recover = dvb_s_recover;
 				break;
 			}
@@ -2101,9 +2106,12 @@
 			// try the ALPS BSRU6 now
 			av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+				av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
 				av7110->recover = dvb_s_recover;
 				break;
 			}
@@ -2111,9 +2119,10 @@
 			// Try the grundig 29504-451
 			av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
 				av7110->recover = dvb_s_recover;
 				break;
 			}
@@ -2124,11 +2133,17 @@
 				/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
 				av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
 							read_pwm(av7110));
+				if (av7110->fe) {
+					av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+				}
 				break;
 			case 0x0003:
 				/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
 				av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
 							read_pwm(av7110));
+				if (av7110->fe) {
+					av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+				}
 				break;
 			}
 			break;
@@ -2137,20 +2152,27 @@
 
 			// ALPS TDLB7
 			av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+			}
 			break;
 
 		case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
 
 			av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+			}
 			break;
 
 		case 0x0004: // Galaxis DVB-S rev1.3
 			/* ALPS BSRV2 */
 			av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
 				av7110->recover = dvb_s_recover;
 			}
 			break;
@@ -2159,9 +2181,10 @@
 			/* Grundig 29504-451 */
 			av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
-				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
-				av7110->fe->ops->set_tone = av7110_set_tone;
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+				av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops.set_tone = av7110_set_tone;
 				av7110->recover = dvb_s_recover;
 			}
 			break;
@@ -2169,12 +2192,17 @@
 		case 0x0008: // Hauppauge/TT DVB-T
 
 			av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+			}
 			break;
 
 		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
 
 			av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
 			if (av7110->fe) {
+				av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
 				/* set TDA9819 into DVB mode */
 				saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
 				saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
@@ -2189,13 +2217,16 @@
 			/* ALPS BSBE1 */
 			av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
 			if (av7110->fe) {
-				if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+				av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+				av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+				if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
 					printk("dvb-ttpci: LNBP21 not found!\n");
-					if (av7110->fe->ops->release)
-						av7110->fe->ops->release(av7110->fe);
+					if (av7110->fe->ops.release)
+						av7110->fe->ops.release(av7110->fe);
 					av7110->fe = NULL;
 				} else {
-					av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+					av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
 					av7110->recover = dvb_s_recover;
 				}
 			}
@@ -2212,21 +2243,21 @@
 		       av7110->dev->pci->subsystem_vendor,
 		       av7110->dev->pci->subsystem_device);
 	} else {
-		FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
-		FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
-		FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+		FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
 		ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
 		if (ret < 0) {
 			printk("av7110: Frontend registration failed!\n");
-			if (av7110->fe->ops->release)
-				av7110->fe->ops->release(av7110->fe);
+			if (av7110->fe->ops.release)
+				av7110->fe->ops.release(av7110->fe);
 			av7110->fe = NULL;
 		}
 	}
@@ -2413,7 +2444,7 @@
 		goto err_kfree_0;
 
 	ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
-				   THIS_MODULE);
+				   THIS_MODULE, &dev->pci->dev);
 	if (ret < 0)
 		goto err_put_firmware_1;
 
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 2eff09f..0f3a044 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -318,7 +318,17 @@
 		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
 		msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
 		return 0;
+
+	case DVB_ADAC_MSP34x5:
+		vol = (volleft > volright) ? volleft : volright;
+		val = (vol * 0x73 / 255) << 8;
+		if (vol > 0)
+			balance = ((volright - volleft) * 127) / vol;
+		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
+		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
+		return 0;
 	}
+
 	return 0;
 }
 
@@ -1267,23 +1277,32 @@
 		switch(av7110->audiostate.channel_select) {
 		case AUDIO_STEREO:
 			ret = audcom(av7110, AUDIO_CMD_STEREO);
-			if (!ret)
+			if (!ret) {
 				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
 					i2c_writereg(av7110, 0x20, 0x02, 0x49);
+				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
+			}
 			break;
 
 		case AUDIO_MONO_LEFT:
 			ret = audcom(av7110, AUDIO_CMD_MONO_L);
-			if (!ret)
+			if (!ret) {
 				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
 					i2c_writereg(av7110, 0x20, 0x02, 0x4a);
+				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
+			}
 			break;
 
 		case AUDIO_MONO_RIGHT:
 			ret = audcom(av7110, AUDIO_CMD_MONO_R);
-			if (!ret)
+			if (!ret) {
 				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
 					i2c_writereg(av7110, 0x20, 0x02, 0x45);
+				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
+			}
 			break;
 
 		default:
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 603a22e..6405546 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -42,7 +42,18 @@
 int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
 {
 	u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
-	struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg };
+	struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
+
+	switch (av7110->adac_type) {
+	case DVB_ADAC_MSP34x0:
+		msgs.addr = 0x40;
+		break;
+	case DVB_ADAC_MSP34x5:
+		msgs.addr = 0x42;
+		break;
+	default:
+		return 0;
+	}
 
 	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
 		dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
@@ -57,10 +68,23 @@
 	u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
 	u8 msg2[2];
 	struct i2c_msg msgs[2] = {
-		{ .flags = 0,	     .addr = 0x40, .len = 3, .buf = msg1 },
-		{ .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 }
+		{ .flags = 0	   , .len = 3, .buf = msg1 },
+		{ .flags = I2C_M_RD, .len = 2, .buf = msg2 }
 	};
 
+	switch (av7110->adac_type) {
+	case DVB_ADAC_MSP34x0:
+		msgs[0].addr = 0x40;
+		msgs[1].addr = 0x40;
+		break;
+	case DVB_ADAC_MSP34x5:
+		msgs[0].addr = 0x42;
+		msgs[1].addr = 0x42;
+		break;
+	default:
+		return 0;
+	}
+
 	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
 		dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
 		       av7110->dvb_adapter.num, reg);
@@ -678,17 +702,23 @@
 {
 	u16 version1, version2;
 
-	if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1
-	    || i2c_writereg(av7110, 0x80, 0x0, 0) != 1)
+	if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
+	    i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
+		printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_MSP34x0;
+	} else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
+		   i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
+		printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n",
+			av7110->dvb_adapter.num);
+		av7110->adac_type = DVB_ADAC_MSP34x5;
+	} else
 		return -ENODEV;
 
-	printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
-		av7110->dvb_adapter.num);
-	av7110->adac_type = DVB_ADAC_MSP34x0;
 	msleep(100); // the probing above resets the msp...
 	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
 	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
-	dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n",
+	dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
 		av7110->dvb_adapter.num, version1, version2);
 	msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
 	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
@@ -697,7 +727,7 @@
 	msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
 	msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
 	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
-	msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART
+	msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
 
 	if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
 		INFO(("saa7113 not accessible.\n"));
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8a7cd7d..6163cb0 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -50,6 +50,12 @@
 
 #define DEBICICAM		0x02420000
 
+#define SLOTSTATUS_NONE         1
+#define SLOTSTATUS_PRESENT      2
+#define SLOTSTATUS_RESET        4
+#define SLOTSTATUS_READY        8
+#define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
 struct budget_av {
 	struct budget budget;
 	struct video_device *vd;
@@ -58,8 +64,15 @@
 	struct tasklet_struct ciintf_irq_tasklet;
 	int slot_status;
 	struct dvb_ca_en50221 ca;
+	u8 reinitialise_demod:1;
+	u8 tda10021_poclkp:1;
+	u8 tda10021_ts_enabled;
+	int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
 };
 
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+
+
 /* GPIO Connections:
  * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
  * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
@@ -129,9 +142,10 @@
 	udelay(1);
 
 	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
-
-	if (result == -ETIMEDOUT)
-		budget_av->slot_status = 0;
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		printk(KERN_INFO "budget-av: cam ejected 1\n");
+	}
 	return result;
 }
 
@@ -147,9 +161,10 @@
 	udelay(1);
 
 	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
-
-	if (result == -ETIMEDOUT)
-		budget_av->slot_status = 0;
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		printk(KERN_INFO "budget-av: cam ejected 2\n");
+	}
 	return result;
 }
 
@@ -165,9 +180,11 @@
 	udelay(1);
 
 	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-
-	if (result == -ETIMEDOUT)
-		budget_av->slot_status = 0;
+	if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) {
+		ciintf_slot_shutdown(ca, slot);
+		printk(KERN_INFO "budget-av: cam ejected 3\n");
+		return -ETIMEDOUT;
+	}
 	return result;
 }
 
@@ -183,9 +200,10 @@
 	udelay(1);
 
 	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
-
-	if (result == -ETIMEDOUT)
-		budget_av->slot_status = 0;
+	if (result == -ETIMEDOUT) {
+		ciintf_slot_shutdown(ca, slot);
+		printk(KERN_INFO "budget-av: cam ejected 5\n");
+	}
 	return result;
 }
 
@@ -193,12 +211,12 @@
 {
 	struct budget_av *budget_av = (struct budget_av *) ca->data;
 	struct saa7146_dev *saa = budget_av->budget.dev;
-	int timeout = 50; // 5 seconds (4.4.6 Ready)
 
 	if (slot != 0)
 		return -EINVAL;
 
 	dprintk(1, "ciintf_slot_reset\n");
+	budget_av->slot_status = SLOTSTATUS_RESET;
 
 	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
 
@@ -208,20 +226,17 @@
 	msleep(20); /* 20 ms Vcc settling time */
 
 	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	msleep(20);
 
-	/* This should have been based on pin 16 READY of the pcmcia port,
-	 * but AFAICS it is not routed to the saa7146 */
-	while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
-		msleep(100);
+	/* reinitialise the frontend if necessary */
+	if (budget_av->reinitialise_demod)
+		dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
 
-	/* reinitialise the frontend */
-	dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
-
-	if (timeout <= 0)
-	{
-		printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
-		saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
-		return -ETIMEDOUT;
+	/* set tda10021 back to original clock configuration on reset */
+	if (budget_av->tda10021_poclkp) {
+		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+		budget_av->tda10021_ts_enabled = 0;
 	}
 
 	return 0;
@@ -238,7 +253,13 @@
 	dprintk(1, "ciintf_slot_shutdown\n");
 
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
-	budget_av->slot_status = 0;
+	budget_av->slot_status = SLOTSTATUS_NONE;
+
+	/* set tda10021 back to original clock configuration when cam removed */
+	if (budget_av->tda10021_poclkp) {
+		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+		budget_av->tda10021_ts_enabled = 0;
+	}
 	return 0;
 }
 
@@ -253,6 +274,13 @@
 	dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
 
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+
+	/* tda10021 seems to need a different TS clock config when data is routed to the CAM */
+	if (budget_av->tda10021_poclkp) {
+		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+		budget_av->tda10021_ts_enabled = 1;
+	}
+
 	return 0;
 }
 
@@ -260,50 +288,61 @@
 {
 	struct budget_av *budget_av = (struct budget_av *) ca->data;
 	struct saa7146_dev *saa = budget_av->budget.dev;
-	int cam_present = 0;
+	int result;
 
 	if (slot != 0)
 		return -EINVAL;
 
-	if (!budget_av->slot_status)
-	{
-		// first of all test the card detect line
+	/* test the card detect line - needs to be done carefully
+	 * since it never goes high for some CAMs on this interface (e.g. topuptv) */
+	if (budget_av->slot_status == SLOTSTATUS_NONE) {
 		saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
 		udelay(1);
-		if (saa7146_read(saa, PSR) & MASK_06)
-		{
-			cam_present = 1;
-		}
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
-
-		// that is unreliable however, so try and read from IO memory
-		if (!cam_present)
-		{
-			saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-			if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
-			{
-				cam_present = 1;
+		if (saa7146_read(saa, PSR) & MASK_06) {
+			if (budget_av->slot_status == SLOTSTATUS_NONE) {
+				budget_av->slot_status = SLOTSTATUS_PRESENT;
+				printk(KERN_INFO "budget-av: cam inserted A\n");
 			}
 		}
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+	}
 
-		// did we find something?
-		if (cam_present) {
-			printk(KERN_INFO "budget-av: cam inserted\n");
-			budget_av->slot_status = 1;
-		}
-	} else if (!open) {
+	/* We also try and read from IO memory to work round the above detection bug. If
+	 * there is no CAM, we will get a timeout. Only done if there is no cam
+	 * present, since this test actually breaks some cams :(
+	 *
+	 * if the CI interface is not open, we also do the above test since we
+	 * don't care if the cam has problems - we'll be resetting it on open() anyway */
+	if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
 		saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
-		if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
-		{
-			printk(KERN_INFO "budget-av: cam ejected\n");
-			saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
-			budget_av->slot_status = 0;
+		result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
+		if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
+			budget_av->slot_status = SLOTSTATUS_PRESENT;
+			printk(KERN_INFO "budget-av: cam inserted B\n");
+		} else if (result < 0) {
+			if (budget_av->slot_status != SLOTSTATUS_NONE) {
+				ciintf_slot_shutdown(ca, slot);
+				printk(KERN_INFO "budget-av: cam ejected 5\n");
+				return 0;
+			}
 		}
 	}
 
-	if (budget_av->slot_status == 1)
-		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+	/* read from attribute memory in reset/ready state to know when the CAM is ready */
+	if (budget_av->slot_status == SLOTSTATUS_RESET) {
+		result = ciintf_read_attribute_mem(ca, slot, 0);
+		if (result == 0x1d) {
+			budget_av->slot_status = SLOTSTATUS_READY;
+		}
+	}
 
+	/* work out correct return code */
+	if (budget_av->slot_status != SLOTSTATUS_NONE) {
+		if (budget_av->slot_status & SLOTSTATUS_READY) {
+			return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+		}
+		return DVB_CA_EN50221_POLL_CAM_PRESENT;
+	}
 	return 0;
 }
 
@@ -333,6 +372,8 @@
 	budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
 	budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
 	budget_av->ca.data = budget_av;
+	budget_av->budget.ci_present = 1;
+	budget_av->slot_status = SLOTSTATUS_NONE;
 
 	if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
 					  &budget_av->ca, 0, 1)) != 0) {
@@ -341,7 +382,6 @@
 	}
 
 	printk(KERN_INFO "budget-av: ci interface initialised.\n");
-	budget_av->budget.ci_present = 1;
 	return 0;
 
 error:
@@ -472,12 +512,12 @@
 	return 0;
 }
 
-static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c,
-					struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
+						 struct dvb_frontend_parameters *params)
 {
 	u32 div;
 	u8 buf[4];
+	struct budget *budget = (struct budget *) fe->dvb->priv;
 	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
 	if ((params->frequency < 950000) || (params->frequency > 2150000))
@@ -501,7 +541,9 @@
 	else if (params->frequency < 2150000)
 		buf[3] |= 0xC0;
 
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -509,9 +551,8 @@
 #define MIN2(a,b) ((a) < (b) ? (a) : (b))
 #define MIN3(a,b,c) MIN2(MIN2(a,b),c)
 
-static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
-					struct i2c_adapter *i2c,
-					struct dvb_frontend_parameters *params)
+static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
+						      struct dvb_frontend_parameters *params)
 {
 	u8 reg0 [2] = { 0x00, 0x00 };
 	u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
@@ -521,6 +562,7 @@
 	int R, A, N, P, M;
 	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
 	int freq = params->frequency;
+	struct budget *budget = (struct budget *) fe->dvb->priv;
 
 	first_ZF = (freq) / 1000;
 
@@ -620,21 +662,25 @@
 	reg0[1] |= 0x03;
 
 	/* already enabled - do not reenable i2c repeater or TX fails */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	msg.buf = reg0;
 	msg.len = sizeof(reg0);
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
-	stv0299_enable_plli2c(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	msg.buf = reg1;
 	msg.len = sizeof(reg1);
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
-	stv0299_enable_plli2c(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	msg.buf = reg2;
 	msg.len = sizeof(reg2);
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
 	return 0;
@@ -692,7 +738,6 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-	.pll_set = philips_su1278_ty_ci_pll_set,
 };
 
 
@@ -706,7 +751,6 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-	.pll_set = philips_su1278_ty_ci_pll_set,
 };
 
 static struct stv0299_config cinergy_1200s_1894_0010_config = {
@@ -719,10 +763,9 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
-	.pll_set = philips_su1278sh2_tua6100_pll_set,
 };
 
-static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
 	u8 buf[4];
@@ -738,6 +781,8 @@
 	buf[3] = (params->frequency < 150000000 ? 0x01 :
 		  params->frequency < 445000000 ? 0x02 : 0x04);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -745,19 +790,20 @@
 
 static struct tda10021_config philips_cu1216_config = {
 	.demod_address = 0x0c,
-	.pll_set = philips_cu1216_pll_set,
 };
 
 
 
 
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
 {
 	struct budget *budget = (struct budget *) 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 (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 	msleep(1);
@@ -765,7 +811,7 @@
 	return 0;
 }
 
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
 	u8 tuner_buf[4];
@@ -839,6 +885,8 @@
 	tuner_buf[2] = 0xca;
 	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
@@ -862,9 +910,6 @@
 	.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_sleep = NULL,
 	.request_firmware = philips_tu1216_request_firmware,
 };
 
@@ -911,13 +956,13 @@
 	0xff, 0xff
 };
 
-static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
-		struct i2c_adapter *i2c,
-		struct dvb_frontend_parameters *params)
+static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
+						   struct dvb_frontend_parameters *params)
 {
 	u8              buf[4];
 	int             rc;
 	struct i2c_msg  tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
+	struct budget *budget = (struct budget *) fe->dvb->priv;
 
 	if((params->frequency < 950000) || (params->frequency > 2150000))
 		return -EINVAL;
@@ -926,7 +971,9 @@
 			params->frequency, 0);
 	if(rc < 0) return rc;
 
-	if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
     return 0;
@@ -969,7 +1016,7 @@
 
 static struct stv0299_config philips_sd1878_config = {
 	.demod_address = 0x68,
-	.inittab = philips_sd1878_inittab,
+     .inittab = philips_sd1878_inittab,
 	.mclk = 88000000UL,
 	.invert = 0,
 	.skip_reinit = 0,
@@ -977,7 +1024,6 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
 	.min_delay_ms = 100,
 	.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
-	.pll_set = philips_sd1878_tda8261_pll_set,
 };
 
 static u8 read_pwm(struct budget_av *budget_av)
@@ -1003,6 +1049,7 @@
 
 #define SUBID_DVBS_TV_STAR	0x0014
 #define SUBID_DVBS_TV_STAR_CI	0x0016
+#define SUBID_DVBS_EASYWATCH_1  0x001a
 #define SUBID_DVBS_EASYWATCH	0x001e
 #define SUBID_DVBC_KNC1		0x0020
 #define SUBID_DVBC_KNC1_PLUS	0x0021
@@ -1012,17 +1059,36 @@
 #define SUBID_DVBT_KNC1		0x0030
 #define SUBID_DVBT_CINERGY1200	0x1157
 
+
+static int tda10021_set_frontend(struct dvb_frontend *fe,
+				 struct dvb_frontend_parameters *p)
+{
+	struct budget_av* budget_av = fe->dvb->priv;
+	int result;
+
+	result = budget_av->tda10021_set_frontend(fe, p);
+	if (budget_av->tda10021_ts_enabled) {
+		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+	} else {
+		tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+	}
+
+	return result;
+}
+
 static void frontend_init(struct budget_av *budget_av)
 {
 	struct saa7146_dev * saa = budget_av->budget.dev;
 	struct dvb_frontend * fe = NULL;
 
+	/* Enable / PowerON Frontend */
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+
+	/* additional setup necessary for the PLUS cards */
 	switch (saa->pci->subsystem_device) {
 		case SUBID_DVBS_KNC1_PLUS:
 		case SUBID_DVBC_KNC1_PLUS:
 		case SUBID_DVBT_KNC1_PLUS:
-			// Enable / PowerON Frontend
-			saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
 			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
 			break;
 	}
@@ -1030,12 +1096,19 @@
 	switch (saa->pci->subsystem_device) {
 
 	case SUBID_DVBS_KNC1:
+	case SUBID_DVBS_EASYWATCH_1:
 		if (saa->pci->subsystem_vendor == 0x1894) {
 			fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
 					     &budget_av->budget.i2c_adap);
+			if (fe) {
+				fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+			}
 		} else {
 			fe = stv0299_attach(&typhoon_config,
 					     &budget_av->budget.i2c_adap);
+			if (fe) {
+				fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+			}
 		}
 		break;
 
@@ -1045,41 +1118,53 @@
 	case SUBID_DVBS_EASYWATCH:
 		fe = stv0299_attach(&philips_sd1878_config,
 				&budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+		}
 		break;
 
 	case SUBID_DVBS_KNC1_PLUS:
 	case SUBID_DVBS_TYPHOON:
 		fe = stv0299_attach(&typhoon_config,
 				    &budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+		}
 		break;
 
 	case SUBID_DVBS_CINERGY1200:
 		fe = stv0299_attach(&cinergy_1200s_config,
 				    &budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+		}
 		break;
 
 	case SUBID_DVBC_KNC1:
 	case SUBID_DVBC_KNC1_PLUS:
+	case SUBID_DVBC_CINERGY1200:
+		budget_av->reinitialise_demod = 1;
 		fe = tda10021_attach(&philips_cu1216_config,
 				     &budget_av->budget.i2c_adap,
 				     read_pwm(budget_av));
+		if (fe) {
+			budget_av->tda10021_poclkp = 1;
+			budget_av->tda10021_set_frontend = fe->ops.set_frontend;
+			fe->ops.set_frontend = tda10021_set_frontend;
+			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+		}
 		break;
 
 	case SUBID_DVBT_KNC1:
 	case SUBID_DVBT_KNC1_PLUS:
-		fe = tda10046_attach(&philips_tu1216_config,
-				     &budget_av->budget.i2c_adap);
-		break;
-
-	case SUBID_DVBC_CINERGY1200:
-		fe = tda10021_attach(&philips_cu1216_config,
-				     &budget_av->budget.i2c_adap,
-				     read_pwm(budget_av));
-		break;
-
 	case SUBID_DVBT_CINERGY1200:
+		budget_av->reinitialise_demod = 1;
 		fe = tda10046_attach(&philips_tu1216_config,
 				     &budget_av->budget.i2c_adap);
+		if (fe) {
+			fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+			fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
+		}
 		break;
 	}
 
@@ -1098,8 +1183,8 @@
 	if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
 				  budget_av->budget.dvb_frontend)) {
 		printk(KERN_ERR "budget-av: Frontend registration failed!\n");
-		if (budget_av->budget.dvb_frontend->ops->release)
-			budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+		if (budget_av->budget.dvb_frontend->ops.release)
+			budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
 		budget_av->budget.dvb_frontend = NULL;
 	}
 }
@@ -1293,6 +1378,7 @@
 MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1309,6 +1395,7 @@
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
 	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+	MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
 	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
 	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index e64a609..4b966ee 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -620,10 +620,10 @@
 	return 0;
 }
 
-static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
-				     struct i2c_adapter *i2c,
-				     struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
+					   struct dvb_frontend_parameters *params)
 {
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
 	u32 div;
 	u8 buf[4];
 	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
@@ -649,7 +649,9 @@
 	else if (params->frequency < 2150000)
 		buf[3] |= 0xC0;
 
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
 		return -EIO;
 	return 0;
 }
@@ -665,12 +667,11 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 50,
 	.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
-	.pll_set = philips_su1278_tt_pll_set,
 };
 
 
 
-static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
 {
 	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
 	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -679,6 +680,8 @@
 			sizeof(td1316_init) };
 
 	// setup PLL configuration
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 	msleep(1);
@@ -687,14 +690,18 @@
 	tuner_msg.addr = 0x65;
 	tuner_msg.buf = disable_mc44BC374c;
 	tuner_msg.len = sizeof(disable_mc44BC374c);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
 		i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
 	}
 
 	return 0;
 }
 
-static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
 	u8 tuner_buf[4];
@@ -770,6 +777,8 @@
 	tuner_buf[2] = 0xca;
 	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
@@ -793,13 +802,10 @@
 	.xtal_freq = TDA10046_XTAL_4M,
 	.agc_config = TDA10046_AGC_DEFAULT,
 	.if_freq = TDA10046_FREQ_3617,
-	.pll_init = philips_tdm1316l_pll_init,
-	.pll_set = philips_tdm1316l_pll_set,
-	.pll_sleep = NULL,
 	.request_firmware = philips_tdm1316l_request_firmware,
 };
 
-static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
 	u8 tuner_buf[5];
@@ -857,13 +863,15 @@
 	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 	tuner_buf[4] = 0x80;
 
-	stv0297_enable_plli2c(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
 	msleep(50);
 
-	stv0297_enable_plli2c(fe);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
@@ -969,7 +977,7 @@
 	.demod_address = 0x1c,
 	.inittab = dvbc_philips_tdm1316l_inittab,
 	.invert = 0,
-	.pll_set = dvbc_philips_tdm1316l_pll_set,
+	.stop_during_read = 1,
 };
 
 
@@ -982,6 +990,8 @@
 		budget_ci->budget.dvb_frontend =
 			stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
 			break;
 		}
 		break;
@@ -990,6 +1000,7 @@
 		budget_ci->budget.dvb_frontend =
 			stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
 			break;
 		}
 		break;
@@ -999,6 +1010,7 @@
 		budget_ci->budget.dvb_frontend =
 			stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
 			break;
 		}
 		break;
@@ -1008,6 +1020,8 @@
 		budget_ci->budget.dvb_frontend =
 			tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
 			break;
 		}
 		break;
@@ -1017,6 +1031,8 @@
 		budget_ci->budget.dvb_frontend =
 			tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
 			break;
 		}
 		break;
@@ -1024,11 +1040,14 @@
 	case 0x1017:		// TT S-1500 PCI
 		budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
 		if (budget_ci->budget.dvb_frontend) {
-			budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
-			if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+			budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+			budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+			budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+			if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
 				printk("%s: No LNBP21 found!\n", __FUNCTION__);
-				if (budget_ci->budget.dvb_frontend->ops->release)
-					budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+				if (budget_ci->budget.dvb_frontend->ops.release)
+					budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
 				budget_ci->budget.dvb_frontend = NULL;
 			}
 		}
@@ -1046,8 +1065,8 @@
 		if (dvb_register_frontend
 		    (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
 			printk("budget-ci: Frontend registration failed!\n");
-			if (budget_ci->budget.dvb_frontend->ops->release)
-				budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+			if (budget_ci->budget.dvb_frontend->ops.release)
+				budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
 			budget_ci->budget.dvb_frontend = NULL;
 		}
 	}
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index ea2066d..e4cf777 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -400,7 +400,9 @@
 		budget->dev->name, budget->buffer_width, budget->buffer_height);
 	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
-	dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
+	if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
+		return ret;
+	}
 
 	/* set dd1 stream a & b */
 	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 1b3aaac..ee60ce9 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -258,7 +258,7 @@
 	return 0;
 }
 
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 	u8 pwr = 0;
@@ -281,7 +281,10 @@
 	// NOTE: since we're using a prescaler of 2, we set the
 	// divisor frequency to 62.5kHz and divide by 125 above
 
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
 	return 0;
 }
 
@@ -289,10 +292,9 @@
 	.demod_address = 0x08,
 	.xin = 90100000UL,
 	.invert_pwm = 0,
-	.pll_set = alps_bsrv2_pll_set,
 };
 
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 	u32 div;
@@ -305,13 +307,15 @@
 	data[2] = 0x8e;
 	data[3] = 0x00;
 
-	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
 	return 0;
 }
 
 static struct tda8083_config grundig_29504_451_config = {
 	.demod_address = 0x68,
-	.pll_set = grundig_29504_451_pll_set,
 };
 
 static void frontend_init(struct budget_patch* budget)
@@ -323,27 +327,32 @@
 		// try the ALPS BSRV2 first of all
 		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
 			break;
 		}
 
 		// try the ALPS BSRU6 now
 		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_set_tone;
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
 			break;
 		}
 
 		// Try the grundig 29504-451
 		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_set_tone;
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
 			break;
 		}
 		break;
@@ -358,8 +367,8 @@
 	} else {
 		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
 			printk("budget-av: Frontend registration failed!\n");
-			if (budget->dvb_frontend->ops->release)
-				budget->dvb_frontend->ops->release(budget->dvb_frontend);
+			if (budget->dvb_frontend->ops.release)
+				budget->dvb_frontend->ops.release(budget->dvb_frontend);
 			budget->dvb_frontend = NULL;
 		}
 	}
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index c23c02d..35761f1 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -186,7 +186,7 @@
 	return 0;
 }
 
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 	u8 pwr = 0;
@@ -209,6 +209,8 @@
 	// NOTE: since we're using a prescaler of 2, we set the
 	// divisor frequency to 62.5kHz and divide by 125 above
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
@@ -218,10 +220,9 @@
 	.demod_address = 0x08,
 	.xin = 90100000UL,
 	.invert_pwm = 0,
-	.pll_set = alps_bsrv2_pll_set,
 };
 
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 	u32 div;
@@ -235,6 +236,8 @@
 	data[2] = 0x85 | ((div >> 10) & 0x60);
 	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
@@ -244,10 +247,9 @@
 	.xin = 57840000UL,
 	.invert = 1,
 	.selagc = VES1820_SELAGC_SIGNAMPERR,
-	.pll_set = alps_tdbe2_pll_set,
 };
 
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 	u32 div;
@@ -274,16 +276,17 @@
 	data[2] = ((div >> 10) & 0x60) | cfg;
 	data[3] = (cpump << 6) | band_select;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
 static struct l64781_config grundig_29504_401_config = {
 	.demod_address = 0x55,
-	.pll_set = grundig_29504_401_pll_set,
 };
 
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 	u32 div;
@@ -296,16 +299,17 @@
 	data[2] = 0x8e;
 	data[3] = 0x00;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
 static struct tda8083_config grundig_29504_451_config = {
 	.demod_address = 0x68,
-	.pll_set = grundig_29504_451_pll_set,
 };
 
-static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct budget* budget = (struct budget*) fe->dvb->priv;
 	u32 div;
@@ -326,16 +330,16 @@
 	else
 		data[3] = 0xc0;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 
-	*freqout = div * 1000;
 	return 0;
 }
 
 static struct s5h1420_config s5h1420_config = {
 	.demod_address = 0x53,
 	.invert = 1,
-	.pll_set = s5h1420_pll_set,
 };
 
 static u8 read_pwm(struct budget* budget)
@@ -359,18 +363,21 @@
 		// try the ALPS BSRV2 first of all
 		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_set_tone;
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
 			break;
 		}
 
 		// try the ALPS BSRU6 now
 		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
-			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
-			budget->dvb_frontend->ops->set_tone = budget_set_tone;
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops.set_tone = budget_set_tone;
 			break;
 		}
 		break;
@@ -378,35 +385,45 @@
 	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
 
 		budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
-		if (budget->dvb_frontend) break;
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+			break;
+		}
 		break;
 
 	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
 
 		budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
-		if (budget->dvb_frontend) break;
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+			break;
+		}
 		break;
 
 	case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
 		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-			budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+			budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
 		}
 		break;
 
 	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
 		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
-			budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+			budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
 		}
 		break;
 
 	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
 		budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
 		if (budget->dvb_frontend) {
-			if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+			budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+			if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
 				printk("%s: No LNBP21 found!\n", __FUNCTION__);
 				goto error_out;
 			}
@@ -428,8 +445,8 @@
 
 error_out:
 	printk("budget: Frontend registration failed!\n");
-	if (budget->dvb_frontend->ops->release)
-		budget->dvb_frontend->ops->release(budget->dvb_frontend);
+	if (budget->dvb_frontend->ops.release)
+		budget->dvb_frontend->ops.release(budget->dvb_frontend);
 	budget->dvb_frontend = NULL;
 	return;
 }
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 914587d..92c7cdc 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -6,6 +6,8 @@
 	select DVB_VES1820
 	select DVB_TDA8083
 	select DVB_STV0299
+	select DVB_STV0297
+	select DVB_LNBP21
 	help
 	  Support for external USB adapters designed by Technotrend and
 	  produced by Hauppauge, shipped under the brand name 'Nova-USB'.
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 6ceae38..14559ef 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -30,6 +30,8 @@
 #include "tda1004x.h"
 #include "stv0299.h"
 #include "tda8083.h"
+#include "stv0297.h"
+#include "lnbp21.h"
 
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/dmx.h>
@@ -486,31 +488,6 @@
 }
 #endif
 
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-	struct  ttusb* ttusb = (struct ttusb*)  fe->dvb->priv;
-	int ret;
-	u8 data[1];
-	struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
-	switch(voltage) {
-	case SEC_VOLTAGE_OFF:
-		data[0] = 0x00;
-		break;
-	case SEC_VOLTAGE_13:
-		data[0] = 0x44;
-		break;
-	case SEC_VOLTAGE_18:
-		data[0] = 0x4c;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
-	return (ret != 1) ? -EIO : 0;
-}
-
 static int ttusb_update_lnb(struct ttusb *ttusb)
 {
 	u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -1048,7 +1025,7 @@
 
 
 
-static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 data[4];
@@ -1062,20 +1039,21 @@
 	data[2] = ((div >> 10) & 0x60) | 0x85;
 	data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
 static struct cx22700_config alps_tdmb7_config = {
 	.demod_address = 0x43,
-	.pll_set = alps_tdmb7_pll_set,
 };
 
 
 
 
 
-static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -1083,6 +1061,8 @@
 	struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
 
 	// setup PLL configuration
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
 	msleep(1);
 
@@ -1090,6 +1070,8 @@
 	tuner_msg.addr = 0x65;
 	tuner_msg.buf = disable_mc44BC374c;
 	tuner_msg.len = sizeof(disable_mc44BC374c);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
 		i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
 	}
@@ -1097,7 +1079,7 @@
 	return 0;
 }
 
-static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 tuner_buf[4];
@@ -1157,6 +1139,8 @@
 	tuner_buf[2] = 0xca;
 	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
@@ -1176,8 +1160,6 @@
 	.demod_address = 0x8,
 	.invert = 1,
 	.invert_oclk = 0,
-	.pll_init = philips_tdm1316l_pll_init,
-	.pll_set = philips_tdm1316l_pll_set,
 	.request_firmware = philips_tdm1316l_request_firmware,
 };
 
@@ -1299,7 +1281,7 @@
 	return 0;
 }
 
-static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 buf[4];
@@ -1322,7 +1304,9 @@
 	if (ttusb->revision == TTUSB_REV_2_2)
 		buf[3] |= 0x20;
 
-	if (i2c_transfer(i2c, &msg, 1) != 1)
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
 	return 0;
@@ -1338,10 +1322,9 @@
 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
 	.min_delay_ms = 100,
 	.set_symbol_rate = alps_stv0299_set_symbol_rate,
-	.pll_set = philips_tsa5059_pll_set,
 };
 
-static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 buf[4];
@@ -1355,6 +1338,8 @@
 	buf[2] = 0x8e;
 	buf[3] = 0x00;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
@@ -1364,10 +1349,9 @@
 static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
 
 	.demod_address = 0x68,
-	.pll_set = ttusb_novas_grundig_29504_491_pll_set,
 };
 
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
 	struct ttusb* ttusb = fe->dvb->priv;
 	u32 div;
@@ -1381,6 +1365,8 @@
 	data[2] = 0x85 | ((div >> 10) & 0x60);
 	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
@@ -1393,7 +1379,6 @@
 	.xin = 57840000UL,
 	.invert = 1,
 	.selagc = VES1820_SELAGC_SIGNAMPERR,
-	.pll_set = alps_tdbe2_pll_set,
 };
 
 static u8 read_pwm(struct ttusb* ttusb)
@@ -1410,6 +1395,174 @@
 }
 
 
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
+	u8 tuner_buf[5];
+	struct i2c_msg tuner_msg = {.addr = 0x60,
+				    .flags = 0,
+				    .buf = tuner_buf,
+				    .len = sizeof(tuner_buf) };
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	// determine charge pump
+	tuner_frequency = params->frequency;
+	if      (tuner_frequency <  87000000) {return -EINVAL;}
+	else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
+	else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
+	else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
+	else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
+	else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
+	else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
+	else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
+	else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
+	else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
+	else {return -EINVAL;}
+
+	// assume PLL filter should always be 8MHz for the moment.
+	filter = 1;
+
+	// calculate divisor
+	// (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
+	tuner_frequency = ((params->frequency + 36125000) / 62500);
+
+	// setup tuner buffer
+	tuner_buf[0] = tuner_frequency >> 8;
+	tuner_buf[1] = tuner_frequency & 0xff;
+	tuner_buf[2] = 0xc8;
+	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+	tuner_buf[4] = 0x80;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+		printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
+		return -EIO;
+	}
+
+	msleep(50);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+		printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
+		return -EIO;
+	}
+
+	msleep(1);
+
+	return 0;
+}
+
+static u8 dvbc_philips_tdm1316l_inittab[] = {
+	0x80, 0x21,
+	0x80, 0x20,
+	0x81, 0x01,
+	0x81, 0x00,
+	0x00, 0x09,
+	0x01, 0x69,
+	0x03, 0x00,
+	0x04, 0x00,
+	0x07, 0x00,
+	0x08, 0x00,
+	0x20, 0x00,
+	0x21, 0x40,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x24, 0x40,
+	0x25, 0x88,
+	0x30, 0xff,
+	0x31, 0x00,
+	0x32, 0xff,
+	0x33, 0x00,
+	0x34, 0x50,
+	0x35, 0x7f,
+	0x36, 0x00,
+	0x37, 0x20,
+	0x38, 0x00,
+	0x40, 0x1c,
+	0x41, 0xff,
+	0x42, 0x29,
+	0x43, 0x20,
+	0x44, 0xff,
+	0x45, 0x00,
+	0x46, 0x00,
+	0x49, 0x04,
+	0x4a, 0xff,
+	0x4b, 0x7f,
+	0x52, 0x30,
+	0x55, 0xae,
+	0x56, 0x47,
+	0x57, 0xe1,
+	0x58, 0x3a,
+	0x5a, 0x1e,
+	0x5b, 0x34,
+	0x60, 0x00,
+	0x63, 0x00,
+	0x64, 0x00,
+	0x65, 0x00,
+	0x66, 0x00,
+	0x67, 0x00,
+	0x68, 0x00,
+	0x69, 0x00,
+	0x6a, 0x02,
+	0x6b, 0x00,
+	0x70, 0xff,
+	0x71, 0x00,
+	0x72, 0x00,
+	0x73, 0x00,
+	0x74, 0x0c,
+	0x80, 0x00,
+	0x81, 0x00,
+	0x82, 0x00,
+	0x83, 0x00,
+	0x84, 0x04,
+	0x85, 0x80,
+	0x86, 0x24,
+	0x87, 0x78,
+	0x88, 0x00,
+	0x89, 0x00,
+	0x90, 0x01,
+	0x91, 0x01,
+	0xa0, 0x00,
+	0xa1, 0x00,
+	0xa2, 0x00,
+	0xb0, 0x91,
+	0xb1, 0x0b,
+	0xc0, 0x4b,
+	0xc1, 0x00,
+	0xc2, 0x00,
+	0xd0, 0x00,
+	0xd1, 0x00,
+	0xd2, 0x00,
+	0xd3, 0x00,
+	0xd4, 0x00,
+	0xd5, 0x00,
+	0xde, 0x00,
+	0xdf, 0x00,
+	0x61, 0x38,
+	0x62, 0x0a,
+	0x53, 0x13,
+	0x59, 0x08,
+	0x55, 0x00,
+	0x56, 0x40,
+	0x57, 0x08,
+	0x58, 0x3d,
+	0x88, 0x10,
+	0xa0, 0x00,
+	0xa0, 0x00,
+	0xa0, 0x00,
+	0xa0, 0x04,
+	0xff, 0xff,
+};
+
+static struct stv0297_config dvbc_philips_tdm1316l_config = {
+	.demod_address = 0x1c,
+	.inittab = dvbc_philips_tdm1316l_inittab,
+	.invert = 0,
+};
+
 static void frontend_init(struct ttusb* ttusb)
 {
 	switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
@@ -1417,11 +1570,13 @@
 		// try the stv0299 based first
 		ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
+			ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
+
 			if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
 				alps_stv0299_config.inittab = alps_bsbe1_inittab;
-				ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+				lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
 			} else { // ALPS BSRU6
-				ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+				ttusb->fe->ops.set_voltage = ttusb_set_voltage;
 			}
 			break;
 		}
@@ -1429,28 +1584,41 @@
 		// Grundig 29504-491
 		ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
 		if (ttusb->fe != NULL) {
-			ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+			ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
+			ttusb->fe->ops.set_voltage = ttusb_set_voltage;
 			break;
 		}
-
 		break;
 
 	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
 		ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
-		if (ttusb->fe != NULL)
+		if (ttusb->fe != NULL) {
+			ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
 			break;
+		}
+
+		ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+		if (ttusb->fe != NULL) {
+			ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
+			break;
+		}
 		break;
 
 	case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
 		// try the ALPS TDMB7 first
 		ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL)
+		if (ttusb->fe != NULL) {
+			ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
 			break;
+		}
 
 		// Philips td1316
 		ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
-		if (ttusb->fe != NULL)
+		if (ttusb->fe != NULL) {
+			ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+			ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
 			break;
+		}
 		break;
 	}
 
@@ -1461,8 +1629,8 @@
 	} else {
 		if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
 			printk("dvb-ttusb-budget: Frontend registration failed!\n");
-			if (ttusb->fe->ops->release)
-				ttusb->fe->ops->release(ttusb->fe);
+			if (ttusb->fe->ops.release)
+				ttusb->fe->ops.release(ttusb->fe);
 			ttusb->fe = NULL;
 		}
 	}
@@ -1507,7 +1675,7 @@
 
 	mutex_unlock(&ttusb->semi2c);
 
-	if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) {
+	if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) {
 		ttusb_free_iso_urbs(ttusb);
 		kfree(ttusb);
 		return result;
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 44dea32..6c1cb77 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1432,7 +1432,7 @@
 	dprintk("%s\n", __FUNCTION__);
 
 	if ((result = dvb_register_adapter(&dec->adapter,
-					   dec->model_name, THIS_MODULE)) < 0) {
+					   dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
 		printk("%s: dvb_register_adapter failed: error %d\n",
 		       __FUNCTION__, result);
 
@@ -1657,8 +1657,8 @@
 	} else {
 		if (dvb_register_frontend(&dec->adapter, dec->fe)) {
 			printk("budget-ci: Frontend registration failed!\n");
-			if (dec->fe->ops->release)
-				dec->fe->ops->release(dec->fe);
+			if (dec->fe->ops.release)
+				dec->fe->ops.release(dec->fe);
 			dec->fe = NULL;
 		}
 	}
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index a5a4617..42f39a8 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -28,8 +28,6 @@
 
 struct ttusbdecfe_state {
 
-	struct dvb_frontend_ops ops;
-
 	/* configuration settings */
 	const struct ttusbdecfe_config* config;
 
@@ -203,10 +201,9 @@
 
 	/* setup the state */
 	state->config = config;
-	memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 }
@@ -226,10 +223,9 @@
 	state->config = config;
 	state->voltage = 0;
 	state->hi_band = 0;
-	memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
 
 	/* create dvb_frontend */
-	state->frontend.ops = &state->ops;
+	memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
 }
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 3fff757..de3128a 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -136,7 +136,7 @@
 	  Choose Y here if you have this PCI FM radio card.
 
 	  In order to control your radio card, you will need to use programs
-	  that are compatible with the Video for Linux API.  Information on 
+	  that are compatible with the Video for Linux API.  Information on
 	  this API and pointers to "v4l" programs may be found at
 	  <file:Documentation/video4linux/API.html>.
 
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 8b35194..e95b680 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -20,3 +20,5 @@
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+
+EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index dc292da..c4312fa 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -16,13 +16,14 @@
 
 /* What ever you think about the ACI, version 0x07 is not very well!
  * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions...                Robert 
+ * conditions...                Robert
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/videodev.h>
-#include "../../../sound/oss/aci.h"
+#include <media/v4l2-common.h>
+#include "oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 static int radio_nr = -1;
@@ -123,7 +124,7 @@
 	struct video_device *dev = video_devdata(file);
 	struct pcm20_device *pcm20 = dev->priv;
 	int i;
-	
+
 	switch(cmd)
 	{
 		case VIDIOCGCAP:
@@ -139,7 +140,7 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 			v->rangelow=87*16000;
 			v->rangehigh=108*16000;
@@ -172,7 +173,7 @@
 			return i;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags=VIDEO_AUDIO_MUTABLE;
@@ -183,12 +184,12 @@
 				v->mode|=VIDEO_SOUND_MONO;
 			/* v->step=2048; */
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
 
 			pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
@@ -237,7 +238,7 @@
 {
 	if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 		goto video_register_device;
-		
+
 	if(attach_aci_rds()<0)
 		goto attach_aci_rds;
 
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
index b602c73..9428d8b 100644
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ b/drivers/media/radio/miropcm20-rds-core.c
@@ -21,7 +21,7 @@
 #include <linux/mutex.h>
 
 #include <asm/io.h>
-#include "../../../sound/oss/aci.h"
+#include "oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 #define DEBUG 0
@@ -33,24 +33,24 @@
 #define RDS_BUSYMASK        0x10   /* Bit 4 */
 #define RDS_CLOCKMASK       0x08   /* Bit 3 */
 
-#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1) 
+#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
 
 
 #if DEBUG
 static void print_matrix(char array[], unsigned int length)
 {
-        int i, j;
+	int i, j;
 
-        for (i=0; i<length; i++) {
-                printk(KERN_DEBUG "aci-rds: ");
-                for (j=7; j>=0; j--) {
-                        printk("%d", (array[i] >> j) & 0x1);
-                }
-                if (i%8 == 0)
-                        printk(" byte-border\n");
-                else
-                        printk("\n");
-        }
+	for (i=0; i<length; i++) {
+		printk(KERN_DEBUG "aci-rds: ");
+		for (j=7; j>=0; j--) {
+			printk("%d", (array[i] >> j) & 0x1);
+		}
+		if (i%8 == 0)
+			printk(" byte-border\n");
+		else
+			printk("\n");
+	}
 }
 #endif /* DEBUG */
 
@@ -114,7 +114,7 @@
 {
 	unsigned char sendbuffer[8];
 	int i;
-	
+
 	if (byte2trans(cmd, sendbuffer, 8) != 0){
 		return -1;
 	} else {
@@ -151,7 +151,7 @@
 	   I have to waitread() here */
 	if (rds_waitread() < 0)
 		return -1;
-	
+
 	memset(databuffer, 0, datasize);
 
 	for (i=0; i< READSIZE; i++)
@@ -194,7 +194,7 @@
 		ret = 0;
 
 	mutex_unlock(&aci_rds_mutex);
-	
+
 	return ret;
 }
 EXPORT_SYMBOL(aci_rds_cmd);
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
index e092140..87b37b7 100644
--- a/drivers/media/radio/miropcm20-rds.c
+++ b/drivers/media/radio/miropcm20-rds.c
@@ -48,7 +48,7 @@
 
 static void print_matrix(char *ch, char out[])
 {
-        int j;
+	int j;
 
 	for (j=7; j>=0; j--) {
 		 out[7-j] = ((*ch >> j) & 0x1) + '0';
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 557fb5c..df22a58 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -24,7 +24,7 @@
  *   out(port, start_increasing_volume);
  *   wait(a_wee_while);
  *   out(port, stop_changing_the_volume);
- *  
+ *
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -34,6 +34,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_RTRACK_PORT 	*/
 #include <asm/semaphore.h>	/* Lock for the I/O 		*/
 
@@ -41,7 +42,7 @@
 #define CONFIG_RADIO_RTRACK_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK_PORT; 
+static int io = CONFIG_RADIO_RTRACK_PORT;
 static int radio_nr = -1;
 static struct mutex lock;
 
@@ -93,12 +94,12 @@
 	int i;
 
 	mutex_lock(&lock);
-	
+
 	if(vol == dev->curvol) {	/* requested volume = current */
 		if (dev->muted) {	/* user is unmuting the card  */
 			dev->muted = 0;
 			outb (0xd8, io);	/* enable card */
-		}	
+		}
 		mutex_unlock(&lock);
 		return 0;
 	}
@@ -114,10 +115,10 @@
 
 	dev->muted = 0;
 	if(vol > dev->curvol)
-		for(i = dev->curvol; i < vol; i++) 
+		for(i = dev->curvol; i < vol; i++)
 			rt_incvol();
 	else
-		for(i = dev->curvol; i > vol; i--) 
+		for(i = dev->curvol; i > vol; i--)
 			rt_decvol();
 
 	dev->curvol = vol;
@@ -125,7 +126,7 @@
 	return 0;
 }
 
-/* the 128+64 on these outb's is to keep the volume stable while tuning 
+/* the 128+64 on these outb's is to keep the volume stable while tuning
  * without them, the volume _will_ creep up with each frequency change
  * and bit 4 (+16) is to keep the signal strength meter enabled
  */
@@ -140,7 +141,7 @@
 		outb_p(128+64+16+8+  1, port);  /* on + wr-enable + data low */
 		outb_p(128+64+16+8+2+1, port);  /* clock */
 	}
-	sleep_delay(1000); 
+	sleep_delay(1000);
 }
 
 static void send_1_byte(int port, struct rt_device *dev)
@@ -148,13 +149,13 @@
 	if ((dev->curvol == 0) || (dev->muted)) {
 		outb_p(128+64+16+4  +1, port);   /* wr-enable+data high */
 		outb_p(128+64+16+4+2+1, port);   /* clock */
-	} 
+	}
 	else {
 		outb_p(128+64+16+8+4  +1, port); /* on+wr-enable+data high */
 		outb_p(128+64+16+8+4+2+1, port); /* clock */
 	}
 
-	sleep_delay(1000); 
+	sleep_delay(1000);
 }
 
 static int rt_setfreq(struct rt_device *dev, unsigned long freq)
@@ -167,9 +168,9 @@
 
 	freq += 171200;			/* Add 10.7 MHz IF 		*/
 	freq /= 800;			/* Convert to 50 kHz units	*/
-	
+
 	mutex_lock(&lock);			/* Stop other ops interfering */
-	 
+
 	send_0_byte (io, dev);		/*  0: LSB of frequency		*/
 
 	for (i = 0; i < 13; i++)	/*   : frequency bits (1-13)	*/
@@ -195,7 +196,7 @@
 		outb (0xd0, io);	/* volume steady + sigstr */
 	else
 		outb (0xd8, io);	/* volume steady + sigstr + on */
-		
+
 	mutex_unlock(&lock);
 
 	return 0;
@@ -213,7 +214,7 @@
 {
 	struct video_device *dev = video_devdata(file);
 	struct rt_device *rt=dev->priv;
-	
+
 	switch(cmd)
 	{
 		case VIDIOCGCAP:
@@ -229,7 +230,7 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 			v->rangelow=(87*16000);
 			v->rangehigh=(108*16000);
@@ -261,21 +262,21 @@
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
 			v->volume=rt->curvol * 6554;
 			v->step=6554;
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
-			if(v->flags&VIDEO_AUDIO_MUTE) 
+			if(v->flags&VIDEO_AUDIO_MUTE)
 				rt_mute(rt);
 			else
 				rt_setvol(rt,v->volume/6554);
@@ -298,7 +299,7 @@
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl	        = rt_ioctl,
+	.ioctl		= rt_ioctl,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -320,14 +321,14 @@
 		return -EINVAL;
 	}
 
-	if (!request_region(io, 2, "rtrack")) 
+	if (!request_region(io, 2, "rtrack"))
 	{
 		printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
 		return -EBUSY;
 	}
 
 	rtrack_radio.priv=&rtrack_unit;
-	
+
 	if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 2);
@@ -336,10 +337,10 @@
 	printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
 
 	/* Set up the I/O locking */
-	
+
 	mutex_init(&lock);
-	
- 	/* mute card - prevents noisy bootups */
+
+	/* mute card - prevents noisy bootups */
 
 	/* this ensures that the volume is all the way down  */
 	outb(0x48, io);		/* volume down but still "on"	*/
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 83bdae2..95e6322 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,11 +1,11 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2 
+/* radio-aztech.c - Aztech radio card driver for Linux 2.2
  *
- * Adapted to support the Video for Linux API by 
+ * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  *
  * Quay Ly
  * Donald Song
- * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
+ * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
@@ -31,6 +31,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_AZTECH_PORT 	*/
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -39,7 +40,7 @@
 #define CONFIG_RADIO_AZTECH_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_AZTECH_PORT; 
+static int io = CONFIG_RADIO_AZTECH_PORT;
 static int radio_nr = -1;
 static int radio_wait_time = 1000;
 static struct mutex lock;
@@ -53,15 +54,15 @@
 
 static int volconvert(int level)
 {
-	level>>=14;	 	/* Map 16bits down to 2 bit */
- 	level&=3;
-	
+	level>>=14;		/* Map 16bits down to 2 bit */
+	level&=3;
+
 	/* convert to card-friendly values */
-	switch (level) 
+	switch (level)
 	{
-		case 0: 
+		case 0:
 			return 0;
-		case 1: 
+		case 1:
 			return 1;
 		case 2:
 			return 4;
@@ -121,9 +122,9 @@
 
 	frequency += 171200;		/* Add 10.7 MHz IF		*/
 	frequency /= 800;		/* Convert to 50 kHz units	*/
-					
+
 	mutex_lock(&lock);
-	
+
 	send_0_byte (dev);		/*  0: LSB of frequency       */
 
 	for (i = 0; i < 13; i++)	/*   : frequency bits (1-13)  */
@@ -151,7 +152,7 @@
 
 	udelay (radio_wait_time);
 	outb_p(128+64+volconvert(dev->curvol), io);
-	
+
 	mutex_unlock(&lock);
 
 	return 0;
@@ -162,7 +163,7 @@
 {
 	struct video_device *dev = video_devdata(file);
 	struct az_device *az = dev->priv;
-	
+
 	switch(cmd)
 	{
 		case VIDIOCGCAP:
@@ -178,7 +179,7 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 			v->rangelow=(87*16000);
 			v->rangehigh=(108*16000);
@@ -211,7 +212,7 @@
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
@@ -222,17 +223,17 @@
 			v->volume=az->curvol;
 			v->step=16384;
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
 			az->curvol=v->volume;
 
 			az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
-			if(v->flags&VIDEO_AUDIO_MUTE) 
+			if(v->flags&VIDEO_AUDIO_MUTE)
 				az_setvol(az,0);
 			else
 				az_setvol(az,az->curvol);
@@ -277,7 +278,7 @@
 		return -EINVAL;
 	}
 
-	if (!request_region(io, 2, "aztech")) 
+	if (!request_region(io, 2, "aztech"))
 	{
 		printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
 		return -EBUSY;
@@ -285,13 +286,13 @@
 
 	mutex_init(&lock);
 	aztech_radio.priv=&aztech_unit;
-	
+
 	if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io,2);
 		return -EINVAL;
 	}
-		
+
 	printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
 	/* mute card - prevents noisy bootups */
 	outb (0, io);
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index f1b5ac8..8641aec 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -8,7 +8,7 @@
  * Russell Kroll    (rkroll@exploits.org)
  * Quay Ly
  * Donald Song
- * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
+ * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
@@ -34,6 +34,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/param.h>
 #include <linux/pnp.h>
 
@@ -55,29 +56,29 @@
 
 /*
  * Signal Strength Threshold Values
- * The V4L API spec does not define any particular unit for the signal 
+ * The V4L API spec does not define any particular unit for the signal
  * strength value.  These values are in microvolts of RF at the tuner's input.
  */
 static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
 
 static int cadet_getrds(void)
 {
-        int rdsstat=0;
+	int rdsstat=0;
 
 	spin_lock(&cadet_io_lock);
-        outb(3,io);                 /* Select Decoder Control/Status */
+	outb(3,io);                 /* Select Decoder Control/Status */
 	outb(inb(io+1)&0x7f,io+1);  /* Reset RDS detection */
 	spin_unlock(&cadet_io_lock);
-	
+
 	msleep(100);
 
-	spin_lock(&cadet_io_lock);	
-        outb(3,io);                 /* Select Decoder Control/Status */
+	spin_lock(&cadet_io_lock);
+	outb(3,io);                 /* Select Decoder Control/Status */
 	if((inb(io+1)&0x80)!=0) {
-	        rdsstat|=VIDEO_TUNER_RDS_ON;
+		rdsstat|=VIDEO_TUNER_RDS_ON;
 	}
 	if((inb(io+1)&0x10)!=0) {
-	        rdsstat|=VIDEO_TUNER_MBS_ON;
+		rdsstat|=VIDEO_TUNER_MBS_ON;
 	}
 	spin_unlock(&cadet_io_lock);
 	return rdsstat;
@@ -86,49 +87,49 @@
 static int cadet_getstereo(void)
 {
 	int ret = 0;
-        if(curtuner != 0)	/* Only FM has stereo capability! */
-	        return 0;
+	if(curtuner != 0)	/* Only FM has stereo capability! */
+		return 0;
 
 	spin_lock(&cadet_io_lock);
-        outb(7,io);          /* Select tuner control */
+	outb(7,io);          /* Select tuner control */
 	if( (inb(io+1) & 0x40) == 0)
-        	ret = 1;
-        spin_unlock(&cadet_io_lock);
-        return ret;
+		ret = 1;
+	spin_unlock(&cadet_io_lock);
+	return ret;
 }
 
 static unsigned cadet_gettune(void)
 {
-        int curvol,i;
+	int curvol,i;
 	unsigned fifo=0;
 
-        /*
-         * Prepare for read
-         */
+	/*
+	 * Prepare for read
+	 */
 
 	spin_lock(&cadet_io_lock);
-	
-        outb(7,io);       /* Select tuner control */
-        curvol=inb(io+1); /* Save current volume/mute setting */
-        outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
+
+	outb(7,io);       /* Select tuner control */
+	curvol=inb(io+1); /* Save current volume/mute setting */
+	outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
 	tunestat=0xffff;
 
-        /*
-         * Read the shift register
-         */
-        for(i=0;i<25;i++) {
-                fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
-                if(i<24) {
-                        outb(0x01,io+1);
+	/*
+	 * Read the shift register
+	 */
+	for(i=0;i<25;i++) {
+		fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
+		if(i<24) {
+			outb(0x01,io+1);
 			tunestat&=inb(io+1);
-                        outb(0x00,io+1);
-                }
-        }
+			outb(0x00,io+1);
+		}
+	}
 
-        /*
-         * Restore volume/mute setting
-         */
-        outb(curvol,io+1);
+	/*
+	 * Restore volume/mute setting
+	 */
+	outb(curvol,io+1);
 	spin_unlock(&cadet_io_lock);
 
 	return fifo;
@@ -136,43 +137,43 @@
 
 static unsigned cadet_getfreq(void)
 {
-        int i;
-        unsigned freq=0,test,fifo=0;
+	int i;
+	unsigned freq=0,test,fifo=0;
 
 	/*
 	 * Read current tuning
 	 */
 	fifo=cadet_gettune();
 
-        /*
-         * Convert to actual frequency
-         */
+	/*
+	 * Convert to actual frequency
+	 */
 	if(curtuner==0) {    /* FM */
-	        test=12500;
-                for(i=0;i<14;i++) {
-                        if((fifo&0x01)!=0) {
-                                freq+=test;
-                        }
-                        test=test<<1;
-                        fifo=fifo>>1;
-                }
-                freq-=10700000;           /* IF frequency is 10.7 MHz */
-                freq=(freq*16)/1000000;   /* Make it 1/16 MHz */
+		test=12500;
+		for(i=0;i<14;i++) {
+			if((fifo&0x01)!=0) {
+				freq+=test;
+			}
+			test=test<<1;
+			fifo=fifo>>1;
+		}
+		freq-=10700000;           /* IF frequency is 10.7 MHz */
+		freq=(freq*16)/1000000;   /* Make it 1/16 MHz */
 	}
 	if(curtuner==1) {    /* AM */
-	        freq=((fifo&0x7fff)-2010)*16;
+		freq=((fifo&0x7fff)-2010)*16;
 	}
 
-        return freq;
+	return freq;
 }
 
 static void cadet_settune(unsigned fifo)
 {
-        int i;
-	unsigned test;  
+	int i;
+	unsigned test;
 
 	spin_lock(&cadet_io_lock);
-	
+
 	outb(7,io);                /* Select tuner control */
 	/*
 	 * Write the shift register
@@ -183,7 +184,7 @@
 	outb(7,io);                /* Select tuner control */
 	outb(test,io+1);           /* Initialize for write */
 	for(i=0;i<25;i++) {
-   	        test|=0x01;              /* Toggle SCK High */
+		test|=0x01;              /* Toggle SCK High */
 		outb(test,io+1);
 		test&=0xfe;              /* Toggle SCK Low */
 		outb(test,io+1);
@@ -196,57 +197,57 @@
 
 static void cadet_setfreq(unsigned freq)
 {
-        unsigned fifo;
-        int i,j,test;
-        int curvol;
+	unsigned fifo;
+	int i,j,test;
+	int curvol;
 
-        /* 
-         * Formulate a fifo command
-         */
+	/*
+	 * Formulate a fifo command
+	 */
 	fifo=0;
 	if(curtuner==0) {    /* FM */
-        	test=102400;
-                freq=(freq*1000)/16;       /* Make it kHz */
-                freq+=10700;               /* IF is 10700 kHz */
-                for(i=0;i<14;i++) {
-                        fifo=fifo<<1;
-                        if(freq>=test) {
-                                fifo|=0x01;
-                                freq-=test;
-                        }
-                        test=test>>1;
-                }
+		test=102400;
+		freq=(freq*1000)/16;       /* Make it kHz */
+		freq+=10700;               /* IF is 10700 kHz */
+		for(i=0;i<14;i++) {
+			fifo=fifo<<1;
+			if(freq>=test) {
+				fifo|=0x01;
+				freq-=test;
+			}
+			test=test>>1;
+		}
 	}
 	if(curtuner==1) {    /* AM */
-                fifo=(freq/16)+2010;            /* Make it kHz */
+		fifo=(freq/16)+2010;            /* Make it kHz */
 		fifo|=0x100000;            /* Select AM Band */
 	}
 
-        /*
-         * Save current volume/mute setting
-         */
+	/*
+	 * Save current volume/mute setting
+	 */
 
 	spin_lock(&cadet_io_lock);
 	outb(7,io);                /* Select tuner control */
-        curvol=inb(io+1); 
-        spin_unlock(&cadet_io_lock);
+	curvol=inb(io+1);
+	spin_unlock(&cadet_io_lock);
 
 	/*
 	 * Tune the card
 	 */
 	for(j=3;j>-1;j--) {
-	        cadet_settune(fifo|(j<<16));
-	        
-	        spin_lock(&cadet_io_lock);
+		cadet_settune(fifo|(j<<16));
+
+		spin_lock(&cadet_io_lock);
 		outb(7,io);         /* Select tuner control */
 		outb(curvol,io+1);
 		spin_unlock(&cadet_io_lock);
-		
+
 		msleep(100);
 
 		cadet_gettune();
 		if((tunestat & 0x40) == 0) {   /* Tuned */
-		        sigstrength=sigtable[curtuner][j];
+			sigstrength=sigtable[curtuner][j];
 			return;
 		}
 	}
@@ -257,28 +258,28 @@
 static int cadet_getvol(void)
 {
 	int ret = 0;
-	
+
 	spin_lock(&cadet_io_lock);
-	
-        outb(7,io);                /* Select tuner control */
-        if((inb(io + 1) & 0x20) != 0)
-        	ret = 0xffff;
-        
-        spin_unlock(&cadet_io_lock);
-        return ret;
+
+	outb(7,io);                /* Select tuner control */
+	if((inb(io + 1) & 0x20) != 0)
+		ret = 0xffff;
+
+	spin_unlock(&cadet_io_lock);
+	return ret;
 }
 
 
 static void cadet_setvol(int vol)
 {
 	spin_lock(&cadet_io_lock);
-        outb(7,io);                /* Select tuner control */
-        if(vol>0)
-                outb(0x20,io+1);
-        else
-                outb(0x00,io+1);
+	outb(7,io);                /* Select tuner control */
+	if(vol>0)
+		outb(0x20,io+1);
+	else
+		outb(0x00,io+1);
 	spin_unlock(&cadet_io_lock);
-}  
+}
 
 static void cadet_handler(unsigned long data)
 {
@@ -288,15 +289,15 @@
 
 	if(spin_trylock(&cadet_io_lock))
 	{
-	        outb(0x3,io);       /* Select RDS Decoder Control */
+		outb(0x3,io);       /* Select RDS Decoder Control */
 		if((inb(io+1)&0x20)!=0) {
-		        printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+			printk(KERN_CRIT "cadet: RDS fifo overflow\n");
 		}
 		outb(0x80,io);      /* Select RDS fifo */
 		while((inb(io)&0x80)!=0) {
-		        rdsbuf[rdsin]=inb(io+1);
+			rdsbuf[rdsin]=inb(io+1);
 			if(rdsin==rdsout)
-			        printk(KERN_WARNING "cadet: RDS buffer overflow\n");
+				printk(KERN_WARNING "cadet: RDS buffer overflow\n");
 			else
 				rdsin++;
 		}
@@ -307,9 +308,9 @@
 	 * Service pending read
 	 */
 	if( rdsin!=rdsout)
-	        wake_up_interruptible(&read_queue);
+		wake_up_interruptible(&read_queue);
 
-	/* 
+	/*
 	 * Clean up and exit
 	 */
 	init_timer(&readtimer);
@@ -324,12 +325,12 @@
 static ssize_t cadet_read(struct file *file, char __user *data,
 			  size_t count, loff_t *ppos)
 {
-        int i=0;
+	int i=0;
 	unsigned char readbuf[RDS_BUFFER];
 
-        if(rdsstat==0) {
+	if(rdsstat==0) {
 		spin_lock(&cadet_io_lock);
-	        rdsstat=1;
+		rdsstat=1;
 		outb(0x80,io);        /* Select RDS fifo */
 		spin_unlock(&cadet_io_lock);
 		init_timer(&readtimer);
@@ -339,15 +340,15 @@
 		add_timer(&readtimer);
 	}
 	if(rdsin==rdsout) {
-  	        if (file->f_flags & O_NONBLOCK)
-		        return -EWOULDBLOCK;
-	        interruptible_sleep_on(&read_queue);
-	}		
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		interruptible_sleep_on(&read_queue);
+	}
 	while( i<count && rdsin!=rdsout)
-	        readbuf[i++]=rdsbuf[rdsout++];
+		readbuf[i++]=rdsbuf[rdsout++];
 
 	if (copy_to_user(data,readbuf,i))
-	        return -EFAULT;
+		return -EFAULT;
 	return i;
 }
 
@@ -375,29 +376,29 @@
 				return -EINVAL;
 			}
 			switch(v->tuner) {
-			        case 0:
-			        strcpy(v->name,"FM");
-			        v->rangelow=1400;     /* 87.5 MHz */
-			        v->rangehigh=1728;    /* 108.0 MHz */
-			        v->flags=0;
-			        v->mode=0;
-			        v->mode|=VIDEO_MODE_AUTO;
-			        v->signal=sigstrength;
-			        if(cadet_getstereo()==1) {
-				        v->flags|=VIDEO_TUNER_STEREO_ON;
-			        }
+				case 0:
+				strcpy(v->name,"FM");
+				v->rangelow=1400;     /* 87.5 MHz */
+				v->rangehigh=1728;    /* 108.0 MHz */
+				v->flags=0;
+				v->mode=0;
+				v->mode|=VIDEO_MODE_AUTO;
+				v->signal=sigstrength;
+				if(cadet_getstereo()==1) {
+					v->flags|=VIDEO_TUNER_STEREO_ON;
+				}
 				v->flags|=cadet_getrds();
-			        break;
-			        case 1:
-			        strcpy(v->name,"AM");
-			        v->rangelow=8320;      /* 520 kHz */
-			        v->rangehigh=26400;    /* 1650 kHz */
-			        v->flags=0;
-			        v->flags|=VIDEO_TUNER_LOW;
-			        v->mode=0;
-			        v->mode|=VIDEO_MODE_AUTO;
-			        v->signal=sigstrength;
-			        break;
+				break;
+				case 1:
+				strcpy(v->name,"AM");
+				v->rangelow=8320;      /* 520 kHz */
+				v->rangehigh=26400;    /* 1650 kHz */
+				v->flags=0;
+				v->flags|=VIDEO_TUNER_LOW;
+				v->mode=0;
+				v->mode|=VIDEO_MODE_AUTO;
+				v->signal=sigstrength;
+				break;
 			}
 			return 0;
 		}
@@ -407,49 +408,49 @@
 			if((v->tuner<0)||(v->tuner>1)) {
 				return -EINVAL;
 			}
-			curtuner=v->tuner;	
+			curtuner=v->tuner;
 			return 0;
 		}
 		case VIDIOCGFREQ:
 		{
-		        unsigned long *freq = arg;
+			unsigned long *freq = arg;
 			*freq = cadet_getfreq();
 			return 0;
 		}
 		case VIDIOCSFREQ:
 		{
-		        unsigned long *freq = arg;
+			unsigned long *freq = arg;
 			if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
-			        return -EINVAL;
+				return -EINVAL;
 			}
 			if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
-			        return -EINVAL;
+				return -EINVAL;
 			}
 			cadet_setfreq(*freq);
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
 			if(cadet_getstereo()==0) {
-			        v->mode=VIDEO_SOUND_MONO;
+				v->mode=VIDEO_SOUND_MONO;
 			} else {
 				v->mode=VIDEO_SOUND_STEREO;
 			}
 			v->volume=cadet_getvol();
 			v->step=0xffff;
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
 			cadet_setvol(v->volume);
-			if(v->flags&VIDEO_AUDIO_MUTE) 
+			if(v->flags&VIDEO_AUDIO_MUTE)
 				cadet_setvol(0);
 			else
 				cadet_setvol(0xffff);
@@ -539,16 +540,16 @@
 
 static int cadet_probe(void)
 {
-        static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
+	static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
 	int i;
 
 	for(i=0;i<8;i++) {
-	        io=iovals[i];
+		io=iovals[i];
 		if (request_region(io, 2, "cadet-probe")) {
-		        cadet_setfreq(1410);
+			cadet_setfreq(1410);
 			if(cadet_getfreq()==1410) {
 				release_region(io, 2);
-			        return io;
+				return io;
 			}
 			release_region(io, 2);
 		}
@@ -556,7 +557,7 @@
 	return -1;
 }
 
-/* 
+/*
  * io should only be set if the user has used something like
  * isapnp (the userspace program) to initialize this card for us
  */
@@ -564,7 +565,7 @@
 static int __init cadet_init(void)
 {
 	spin_lock_init(&cadet_io_lock);
-	
+
 	/*
 	 *	If a probe was requested then probe ISAPnP first (safest)
 	 */
@@ -579,12 +580,12 @@
 	/*
 	 *	Else we bail out
 	 */
-	 
-        if(io < 0) {
-#ifdef MODULE        
+
+	if(io < 0) {
+#ifdef MODULE
 		printk(KERN_ERR "You must set an I/O address with io=0x???\n");
 #endif
-	        goto fail;
+		goto fail;
 	}
 	if (!request_region(io,2,"cadet"))
 		goto fail;
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 8e499b8..9f249e7e 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -1,6 +1,6 @@
 /*
  ***************************************************************************
- *     
+ *
  *     radio-gemtek-pci.c - Gemtek PCI Radio driver
  *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
  *
@@ -31,7 +31,7 @@
  *     radio device driver.
  *
  *     Please, let me know if this piece of code was useful :)
- * 
+ *
  *     TODO: multiple device support and portability were not tested
  *
  ***************************************************************************
@@ -44,6 +44,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/errno.h>
 
 #include <asm/io.h>
@@ -69,18 +70,18 @@
 #define TRUE (1)
 #endif
 
-#ifndef FALSE 
+#ifndef FALSE
 #define FALSE (0)
 #endif
 
 struct gemtek_pci_card {
 	struct video_device *videodev;
-	
+
 	u32 iobase;
 	u32 length;
 	u8  chiprev;
 	u16 model;
-	
+
 	u32 current_frequency;
 	u8  mute;
 };
@@ -96,7 +97,7 @@
 	return (u8)value;
 }
 
-#define _b0( v ) *((u8 *)&v)  
+#define _b0( v ) *((u8 *)&v)
 static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
 {
 	register u8 byte = *last_byte;
@@ -104,7 +105,7 @@
 	if ( !value ) {
 		if ( !keep )
 			value = (u16)port;
-		byte &= 0xfd;	
+		byte &= 0xfd;
 	} else
 		byte |= 2;
 
@@ -116,7 +117,7 @@
 	byte &= 0xfe;
 	_b0( value ) = byte;
 	outw( value, port );
-	
+
 	*last_byte = byte;
 }
 
@@ -193,13 +194,13 @@
 			c->audios = 1;
 			strcpy( c->name, "Gemtek PCI Radio" );
 			return 0;
-		} 
+		}
 
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *t = arg;
 
-			if ( t->tuner ) 
+			if ( t->tuner )
 				return -EINVAL;
 
 			t->rangelow = GEMTEK_PCI_RANGE_LOW;
@@ -228,7 +229,7 @@
 		case VIDIOCSFREQ:
 		{
 			unsigned long *freq = arg;
-	 
+
 			if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
 			     (*freq > GEMTEK_PCI_RANGE_HIGH) )
 				return -EINVAL;
@@ -239,9 +240,9 @@
 
 			return 0;
 		}
-  
+
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *a = arg;
 
 			memset( a, 0, sizeof( *a ) );
@@ -249,17 +250,17 @@
 			a->volume = 1;
 			a->step = 65535;
 			strcpy( a->name, "Radio" );
-			return 0;			
+			return 0;
 		}
 
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *a = arg;
 
-			if ( a->audio ) 
+			if ( a->audio )
 				return -EINVAL;
 
-			if ( a->flags & VIDEO_AUDIO_MUTE ) 
+			if ( a->flags & VIDEO_AUDIO_MUTE )
 				gemtek_pci_mute( card );
 			else
 				gemtek_pci_unmute( card );
@@ -323,9 +324,9 @@
 		return -ENOMEM;
 	}
 
-	if ( pci_enable_device( pci_dev ) ) 
+	if ( pci_enable_device( pci_dev ) )
 		goto err_pci;
-	
+
 	card->iobase = pci_resource_start( pci_dev, 0 );
 	card->length = pci_resource_len( pci_dev, 0 );
 
@@ -338,7 +339,7 @@
 	pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
 
 	pci_set_drvdata( pci_dev, card );
- 
+
 	if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
 		printk( KERN_ERR "gemtek_pci: out of memory\n" );
 		goto err_video;
@@ -354,7 +355,7 @@
 	devradio->priv = card;
 	gemtek_pci_mute( card );
 
-	printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", 
+	printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
 		card->chiprev, card->iobase, card->iobase + card->length - 1 );
 
 	return 0;
@@ -364,7 +365,7 @@
 
 err_pci:
 	kfree( card );
-	return -ENODEV;        
+	return -ENODEV;
 }
 
 static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
@@ -375,12 +376,12 @@
 	kfree( card->videodev );
 
 	release_region( card->iobase, card->length );
-	
+
 	if ( mx )
 		gemtek_pci_mute( card );
 
 	kfree( card );
-	
+
 	pci_set_drvdata( pci_dev, NULL );
 }
 
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 47173be..162f37d 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -6,7 +6,7 @@
  * Besides the protocol changes, this is mostly a copy of:
  *
  *    RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- * 
+ *
  *    Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
  *    Converted to new API by Alan Cox <Alan.Cox@linux.org>
  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -22,6 +22,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_GEMTEK_PORT 	*/
 #include <linux/spinlock.h>
 
@@ -29,7 +30,7 @@
 #define CONFIG_RADIO_GEMTEK_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_GEMTEK_PORT; 
+static int io = CONFIG_RADIO_GEMTEK_PORT;
 static int radio_nr = -1;
 static spinlock_t lock;
 
@@ -48,7 +49,7 @@
  */
 static void gemtek_mute(struct gemtek_device *dev)
 {
-        if(dev->muted)
+	if(dev->muted)
 		return;
 	spin_lock(&lock);
 	outb(0x10, io);
@@ -94,20 +95,20 @@
 	freq /= 100000;
 
 	spin_lock(&lock);
-	
+
 	/* 2 start bits */
 	outb_p(0x03, io);
 	udelay(5);
 	outb_p(0x07, io);
 	udelay(5);
 
-        /* 28 frequency bits (lsb first) */
+	/* 28 frequency bits (lsb first) */
 	for (i = 0; i < 14; i++)
 		if (freq & (1 << i))
 			one();
 		else
 			zero();
-        /* 36 unknown bits */
+	/* 36 unknown bits */
 	for (i = 0; i < 11; i++)
 		zero();
 	one();
@@ -123,7 +124,7 @@
 	udelay(5);
 
 	spin_unlock(&lock);
-	
+
 	return 0;
 }
 
@@ -159,7 +160,7 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 			v->rangelow=87*16000;
 			v->rangehigh=108*16000;
@@ -193,25 +194,25 @@
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags|=VIDEO_AUDIO_MUTABLE;
 			v->volume=1;
 			v->step=65535;
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
 
-			if(v->flags&VIDEO_AUDIO_MUTE) 
+			if(v->flags&VIDEO_AUDIO_MUTE)
 				gemtek_mute(rt);
 			else
-			        gemtek_unmute(rt);
+				gemtek_unmute(rt);
 
 			return 0;
 		}
@@ -254,14 +255,14 @@
 		return -EINVAL;
 	}
 
-	if (!request_region(io, 4, "gemtek")) 
+	if (!request_region(io, 4, "gemtek"))
 	{
 		printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
 		return -EBUSY;
 	}
 
 	gemtek_radio.priv=&gemtek_unit;
-	
+
 	if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 4);
@@ -274,7 +275,7 @@
 	/* this is _maybe_ unnecessary */
 	outb(0x01, io);
 
- 	/* mute card - prevents noisy bootups */
+	/* mute card - prevents noisy bootups */
 	gemtek_unit.muted = 0;
 	gemtek_mute(&gemtek_unit);
 
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 39c1d91..fcfa6c9 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -2,7 +2,7 @@
  * (c) 2000 A. Tlalka, atlka@pg.gda.pl
  * Notes on the hardware
  *
- *  + Frequency control is done digitally 
+ *  + Frequency control is done digitally
  *  + No volume control - only mute/unmute - you have to use Aux line volume
  *  control on Maestro card to set the volume
  *  + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
@@ -26,7 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
 
 #define DRIVER_VERSION	"0.05"
 
@@ -103,7 +103,7 @@
 struct radio_device {
 	u16	io,	/* base of Maestro card radio io (GPIO_DATA)*/
 		muted,	/* VIDEO_AUDIO_MUTE */
-		stereo,	/* VIDEO_TUNER_STEREO_ON */	
+		stereo,	/* VIDEO_TUNER_STEREO_ON */
 		tuned;	/* signal strength (0 or 0xffff) */
 	struct mutex lock;
 };
@@ -122,14 +122,14 @@
 	for (l=24;l--;) {
 		outw(STR_CLK, io);		/* HI state */
 		udelay(2);
-		if(!l) 
+		if(!l)
 			dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
 		outw(0, io);			/* LO state */
 		udelay(2);
 		data <<= 1;			/* shift data */
 		rdata = inw(io);
 		if(!l)
-			dev->stereo =  rdata & STR_MOST ? 
+			dev->stereo =  rdata & STR_MOST ?
 			0 : VIDEO_TUNER_STEREO_ON;
 		else
 			if(rdata & STR_DATA)
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f0bf47b..f93d7af 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -1,15 +1,15 @@
-/* 
- * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux 
+/*
+ * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
  * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
  *
  * Based in the radio Maestro PCI driver. Actually it uses the same chip
  * for radio but different pci controller.
  *
  * I didn't have any specs I reversed engineered the protocol from
- * the windows driver (radio.dll). 
+ * the windows driver (radio.dll).
  *
  * The card uses the TEA5757 chip that includes a search function but it
- * is useless as I haven't found any way to read back the frequency. If 
+ * is useless as I haven't found any way to read back the frequency. If
  * anybody does please mail me.
  *
  * For the pdf file see:
@@ -24,7 +24,7 @@
  *     - tiding up
  *     - removed support for multiple devices as it didn't work anyway
  *
- * BUGS: 
+ * BUGS:
  *   - card unmutes if you change frequency
  *
  */
@@ -41,6 +41,7 @@
 
 #include <linux/pci.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 /* version 0.75      Sun Feb  4 22:51:27 EET 2001 */
 #define DRIVER_VERSION	"0.75"
@@ -80,7 +81,7 @@
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl	        = radio_ioctl,
+	.ioctl		= radio_ioctl,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -97,11 +98,11 @@
 {
 	__u16	io,	/* base of radio io */
 		muted,	/* VIDEO_AUDIO_MUTE */
-		stereo,	/* VIDEO_TUNER_STEREO_ON */	
+		stereo,	/* VIDEO_TUNER_STEREO_ON */
 		tuned;	/* signal strength (0 or 0xffff) */
-		
+
 	unsigned long freq;
-	
+
 	struct mutex lock;
 } radio_unit = {0, 0, 0, 0, };
 
@@ -114,7 +115,7 @@
 			outb(  power|wren|data|clk ,io); udelay(4);
 			outb(  power|wren|data     ,io); udelay(4);
 		}
-	else	
+	else
 		{
 			outb(  power|wren          ,io); udelay(4);
 			outb(  power|wren|clk      ,io); udelay(4);
@@ -132,12 +133,12 @@
 {
 	unsigned long int si;
 	int bl;
-	
+
 	/* TEA5757 shift register bits (see pdf) */
 
-	outbit(0,io); // 24  search 
+	outbit(0,io); // 24  search
 	outbit(1,io); // 23  search up/down
-	
+
 	outbit(0,io); // 22  stereo/mono
 
 	outbit(0,io); // 21  band
@@ -145,24 +146,24 @@
 
 	outbit(0,io); // 19  port ?
 	outbit(0,io); // 18  port ?
-	
+
 	outbit(0,io); // 17  search level
 	outbit(0,io); // 16  search level
- 
+
 	si = 0x8000;
 	for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
-	
+
 	outb(power,io);
 }
 
 static int get_stereo(__u16 io)
-{	
+{
 	outb(power,io); udelay(4);
 	return !(inb(io) & mo_st);
 }
 
 static int get_tune(__u16 io)
-{	
+{
 	outb(power+clk,io); udelay(4);
 	return !(inb(io) & mo_st);
 }
@@ -177,7 +178,7 @@
 	switch(cmd) {
 		case VIDIOCGCAP: {
 			struct video_capability *v = arg;
-			
+
 			memset(v,0,sizeof(*v));
 			strcpy(v->name, "Maxi Radio FM2000 radio");
 			v->type=VID_TYPE_TUNER;
@@ -186,22 +187,22 @@
 		}
 		case VIDIOCGTUNER: {
 			struct video_tuner *v = arg;
-			
+
 			if(v->tuner)
 				return -EINVAL;
-				
+
 			card->stereo = 0xffff * get_stereo(card->io);
 			card->tuned = 0xffff * get_tune(card->io);
-			
+
 			v->flags = VIDEO_TUNER_LOW | card->stereo;
 			v->signal = card->tuned;
-			
+
 			strcpy(v->name, "FM");
-			
+
 			v->rangelow = FREQ_LO;
 			v->rangehigh = FREQ_HI;
 			v->mode = VIDEO_MODE_AUTO;
-			
+
 			return 0;
 		}
 		case VIDIOCSTUNER: {
@@ -212,13 +213,13 @@
 		}
 		case VIDIOCGFREQ: {
 			unsigned long *freq = arg;
-			
+
 			*freq = card->freq;
 			return 0;
 		}
 		case VIDIOCSFREQ: {
 			unsigned long *freq = arg;
-			
+
 			if (*freq < FREQ_LO || *freq > FREQ_HI)
 				return -EINVAL;
 			card->freq = *freq;
@@ -226,18 +227,18 @@
 			msleep(125);
 			return 0;
 		}
-		case VIDIOCGAUDIO: {	
+		case VIDIOCGAUDIO: {
 			struct video_audio *v = arg;
 			memset(v,0,sizeof(*v));
 			strcpy(v->name, "Radio");
 			v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
 			v->mode=VIDEO_SOUND_STEREO;
-			return 0;		
+			return 0;
 		}
-		
+
 		case VIDIOCSAUDIO: {
 			struct video_audio *v = arg;
-			
+
 			if(v->audio)
 				return -EINVAL;
 			card->muted = v->flags & VIDEO_AUDIO_MUTE;
@@ -249,13 +250,13 @@
 		}
 		case VIDIOCGUNIT: {
 			struct video_unit *v = arg;
-			
+
 			v->video=VIDEO_NO_UNIT;
 			v->vbi=VIDEO_NO_UNIT;
 			v->radio=dev->minor;
 			v->audio=0;
 			v->teletext=VIDEO_NO_UNIT;
-			return 0;		
+			return 0;
 		}
 		default: return -ENOIOCTLCMD;
 	}
@@ -267,7 +268,7 @@
 	struct video_device *dev = video_devdata(file);
 	struct radio_device *card=dev->priv;
 	int ret;
-	
+
 	mutex_lock(&card->lock);
 	ret = video_usercopy(inode, file, cmd, arg, radio_function);
 	mutex_unlock(&card->lock);
@@ -282,21 +283,21 @@
 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	if(!request_region(pci_resource_start(pdev, 0),
-	                   pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
-	        printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
-	        goto err_out;
+			   pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+		printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+		goto err_out;
 	}
 
 	if (pci_enable_device(pdev))
-	        goto err_out_free_region;
+		goto err_out_free_region;
 
 	radio_unit.io = pci_resource_start(pdev, 0);
 	mutex_init(&radio_unit.lock);
 	maxiradio_radio.priv = &radio_unit;
 
 	if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
-	        printk("radio-maxiradio: can't register device!");
-	        goto err_out_free_region;
+		printk("radio-maxiradio: can't register device!");
+		goto err_out_free_region;
 	}
 
 	printk(KERN_INFO "radio-maxiradio: version "
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 28a47c9..5b68ac4 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -1,5 +1,5 @@
 /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- * 
+ *
  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
  * Converted to new API by Alan Cox <Alan.Cox@linux.org>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -15,6 +15,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_RTRACK2_PORT 	*/
 #include <linux/spinlock.h>
 
@@ -22,7 +23,7 @@
 #define CONFIG_RADIO_RTRACK2_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK2_PORT; 
+static int io = CONFIG_RADIO_RTRACK2_PORT;
 static int radio_nr = -1;
 static spinlock_t lock;
 
@@ -38,7 +39,7 @@
 
 static void rt_mute(struct rt_device *dev)
 {
-        if(dev->muted)
+	if(dev->muted)
 		return;
 	spin_lock(&lock);
 	outb(1, io);
@@ -58,14 +59,14 @@
 
 static void zero(void)
 {
-        outb_p(1, io);
+	outb_p(1, io);
 	outb_p(3, io);
 	outb_p(1, io);
 }
 
 static void one(void)
 {
-        outb_p(5, io);
+	outb_p(5, io);
 	outb_p(7, io);
 	outb_p(5, io);
 }
@@ -75,7 +76,7 @@
 	int i;
 
 	freq = freq / 200 + 856;
-	
+
 	spin_lock(&lock);
 
 	outb_p(0xc8, io);
@@ -94,7 +95,7 @@
 	outb_p(0xc8, io);
 	if (!dev->muted)
 		outb_p(0, io);
-		
+
 	spin_unlock(&lock);
 	return 0;
 }
@@ -127,7 +128,7 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 			v->rangelow=88*16000;
 			v->rangehigh=108*16000;
@@ -159,25 +160,25 @@
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags|=VIDEO_AUDIO_MUTABLE;
 			v->volume=1;
 			v->step=65535;
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
 
-			if(v->flags&VIDEO_AUDIO_MUTE) 
+			if(v->flags&VIDEO_AUDIO_MUTE)
 				rt_mute(rt);
 			else
-			        rt_unmute(rt);
+				rt_unmute(rt);
 
 			return 0;
 		}
@@ -219,7 +220,7 @@
 		printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
 		return -EINVAL;
 	}
-	if (!request_region(io, 4, "rtrack2")) 
+	if (!request_region(io, 4, "rtrack2"))
 	{
 		printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
 		return -EBUSY;
@@ -227,16 +228,16 @@
 
 	rtrack2_radio.priv=&rtrack2_unit;
 
-	spin_lock_init(&lock);	
+	spin_lock_init(&lock);
 	if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io, 4);
 		return -EINVAL;
 	}
-		
+
 	printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
 
- 	/* mute card - prevents noisy bootups */
+	/* mute card - prevents noisy bootups */
 	outb(1, io);
 	rtrack2_unit.muted = 1;
 
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 53073b4..efee6e3 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -12,7 +12,7 @@
  *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
  *  No volume control - only mute/unmute - you have to use line volume
  *  control on SB-part of SF16FMI
- *  
+ *
  */
 
 #include <linux/kernel.h>	/* __setup			*/
@@ -21,6 +21,7 @@
 #include <linux/ioport.h>	/* request_region		*/
 #include <linux/delay.h>	/* udelay			*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/isapnp.h>
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
@@ -29,19 +30,19 @@
 struct fmi_device
 {
 	int port;
-        int curvol; /* 1 or 0 */
-        unsigned long curfreq; /* freq in kHz */
-        __u32 flags;
+	int curvol; /* 1 or 0 */
+	unsigned long curfreq; /* freq in kHz */
+	__u32 flags;
 };
 
-static int io = -1; 
+static int io = -1;
 static int radio_nr = -1;
 static struct pnp_dev *dev = NULL;
 static struct mutex lock;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but 
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * 92.7400017 -> 92.75
  */
 #define RSF16_ENCODE(x)	((x)/800+214)
@@ -51,7 +52,7 @@
 static void outbits(int bits, unsigned int data, int port)
 {
 	while(bits--) {
- 		if(data & 1) {
+		if(data & 1) {
 			outb(5, port);
 			udelay(6);
 			outb(7, port);
@@ -101,7 +102,7 @@
 	int res;
 	int myport = dev->port;
 
-	
+
 	mutex_lock(&lock);
 	val = dev->curvol ? 0x08 : 0x00;	/* unmute/mute */
 	outb(val, myport);
@@ -109,7 +110,7 @@
 	msleep(143); 		/* was schedule_timeout(HZ/7) */
 	res = (int)inb(myport+1);
 	outb(val, myport);
-	
+
 	mutex_unlock(&lock);
 	return (res & 2) ? 0 : 0xFFFF;
 }
@@ -119,7 +120,7 @@
 {
 	struct video_device *dev = video_devdata(file);
 	struct fmi_device *fmi=dev->priv;
-	
+
 	switch(cmd)
 	{
 		case VIDIOCGCAP:
@@ -174,18 +175,18 @@
 				return -EINVAL;
 			/*rounding in steps of 800 to match th freq
 			  that will be used */
-			fmi->curfreq = (*freq/800)*800; 
+			fmi->curfreq = (*freq/800)*800;
 			fmi_setfreq(fmi);
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0,sizeof(*v));
 			v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
 			strcpy(v->name, "Radio");
 			v->mode=VIDEO_SOUND_STEREO;
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
@@ -193,19 +194,19 @@
 			if(v->audio)
 				return -EINVAL;
 			fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
-			fmi->curvol ? 
+			fmi->curvol ?
 				fmi_unmute(fmi->port) : fmi_mute(fmi->port);
 			return 0;
 		}
-	        case VIDIOCGUNIT:
+		case VIDIOCGUNIT:
 		{
-               		struct video_unit *v = arg;
+			struct video_unit *v = arg;
 			v->video=VIDEO_NO_UNIT;
 			v->vbi=VIDEO_NO_UNIT;
 			v->radio=dev->minor;
 			v->audio=0; /* How do we find out this??? */
 			v->teletext=VIDEO_NO_UNIT;
-			return 0;			
+			return 0;
 		}
 		default:
 			return -ENOIOCTLCMD;
@@ -295,14 +296,14 @@
 	fmi_unit.curfreq = 0;
 	fmi_unit.flags = VIDEO_TUNER_LOW;
 	fmi_radio.priv = &fmi_unit;
-	
+
 	mutex_init(&lock);
-	
+
 	if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
 		release_region(io, 2);
 		return -EINVAL;
 	}
-		
+
 	printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
 	/* mute card - prevents noisy bootups */
 	fmi_mute(io);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index bcebd8c..3483b2c 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -19,6 +19,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 static struct mutex lock;
@@ -202,7 +203,7 @@
 }
 
 static int fmr2_do_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, void *arg)
+		      unsigned int cmd, void *arg)
 {
 	struct video_device *dev = video_devdata(file);
 	struct fmr2_device *fmr2 = dev->priv;
@@ -344,7 +345,7 @@
 }
 
 static int fmr2_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
+		      unsigned int cmd, unsigned long arg)
  {
 	return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
 }
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index fcfde2e..dfba4ae 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -2,11 +2,11 @@
  * (c) 1999 R. Offermanns (rolf@offermanns.de)
  * based on the aimslab radio driver from M. Kirkwood
  * many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
- * 
+ *
  *
  * History:
  * 1999-05-21	First preview release
- * 
+ *
  *  Notes on the hardware:
  *  There are two "main" chips on the card:
  *  - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
@@ -20,7 +20,7 @@
  *  (as soon i have understand how to get started :)
  *  If you can help me out with that, please contact me!!
  *
- *  
+ *
  */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -30,6 +30,7 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_TERRATEC_PORT 	*/
 #include <linux/spinlock.h>
 
@@ -49,7 +50,7 @@
 #define WRT_EN		0x10
 /*******************************************************************/
 
-static int io = CONFIG_RADIO_TERRATEC_PORT; 
+static int io = CONFIG_RADIO_TERRATEC_PORT;
 static int radio_nr = -1;
 static spinlock_t lock;
 
@@ -88,15 +89,15 @@
 
 static int tt_setvol(struct tt_device *dev, int vol)
 {
-	
+
 //	printk(KERN_ERR "setvol called, vol = %d\n", vol);
 
 	if(vol == dev->curvol) {	/* requested volume = current */
 		if (dev->muted) {	/* user is unmuting the card  */
 			dev->muted = 0;
 			cardWriteVol(vol);	/* enable card */
-		}	
-	
+		}
+
 		return 0;
 	}
 
@@ -107,9 +108,9 @@
 	}
 
 	dev->muted = 0;
-	
+
 	cardWriteVol(vol);
-	 
+
 	dev->curvol = vol;
 
 	return 0;
@@ -121,13 +122,13 @@
 /* many more or less strange things are going on here, but hey, it works :) */
 
 static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
-{	
+{
 	int freq;
 	int i;
 	int p;
 	int  temp;
 	long rest;
-     
+
 	unsigned char buffer[25];		/* we have to bit shift 25 registers */
 	freq = freq1/160;			/* convert the freq. to a nice to handle value */
 	for(i=24;i>-1;i--)
@@ -142,9 +143,9 @@
 	{
 		if (rest%temp  == rest)
 			buffer[i] = 0;
-		else 
+		else
 		{
-			buffer[i] = 1; 
+			buffer[i] = 1;
 			rest = rest-temp;
 		}
 		i--;
@@ -153,10 +154,10 @@
        }
 
 	spin_lock(&lock);
-	
+
 	for (i=24;i>-1;i--)			/* bit shift the values to the radiocard */
 	{
-		if (buffer[i]==1) 
+		if (buffer[i]==1)
 		{
 			outb(WRT_EN|DATA, BASEPORT);
 			outb(WRT_EN|DATA|CLK_ON  , BASEPORT);
@@ -168,11 +169,11 @@
 			outb(WRT_EN|0x00|CLK_ON  , BASEPORT);
 		}
 	}
-	outb(0x00, BASEPORT);     
-	
+	outb(0x00, BASEPORT);
+
 	spin_unlock(&lock);
-  
-  	return 0;
+
+	return 0;
 }
 
 static int tt_getsigstr(struct tt_device *dev)		/* TODO */
@@ -190,7 +191,7 @@
 {
 	struct video_device *dev = video_devdata(file);
 	struct tt_device *tt=dev->priv;
-	
+
 	switch(cmd)
 	{
 		case VIDIOCGCAP:
@@ -206,7 +207,7 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 			v->rangelow=(87*16000);
 			v->rangehigh=(108*16000);
@@ -238,21 +239,21 @@
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 			memset(v,0, sizeof(*v));
 			v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
 			v->volume=tt->curvol * 6554;
 			v->step=6554;
 			strcpy(v->name, "Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
-			if(v->flags&VIDEO_AUDIO_MUTE) 
+			if(v->flags&VIDEO_AUDIO_MUTE)
 				tt_mute(tt);
 			else
 				tt_setvol(tt,v->volume/6554);
@@ -296,25 +297,25 @@
 		printk(KERN_ERR "You must set an I/O address with io=0x???\n");
 		return -EINVAL;
 	}
-	if (!request_region(io, 2, "terratec")) 
+	if (!request_region(io, 2, "terratec"))
 	{
 		printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
 		return -EBUSY;
 	}
 
 	terratec_radio.priv=&terratec_unit;
-	
+
 	spin_lock_init(&lock);
-	
+
 	if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
 	{
 		release_region(io,2);
 		return -EINVAL;
 	}
-		
+
 	printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
 
- 	/* mute card - prevents noisy bootups */
+	/* mute card - prevents noisy bootups */
 
 	/* this ensures that the volume is all the way down  */
 	cardWriteVol(0);
@@ -334,7 +335,7 @@
 {
 	video_unregister_device(&terratec_radio);
 	release_region(io,2);
-	printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");	
+	printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
 }
 
 module_init(terratec_init);
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 5a099a5..8da4bad 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -1,14 +1,14 @@
-/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 
+/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
  * by Eric Lammerts <eric@scintilla.utwente.nl>
  *
  * Based on radio-aztech.c. Original notes:
  *
- * Adapted to support the Video for Linux API by 
+ * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  *
  * Quay Ly
  * Donald Song
- * Jason Lewis      (jlewis@twilight.vtc.vsc.edu) 
+ * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
@@ -22,6 +22,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_TRUST_PORT 	*/
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -30,7 +31,7 @@
 #define CONFIG_RADIO_TRUST_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_TRUST_PORT; 
+static int io = CONFIG_RADIO_TRUST_PORT;
 static int radio_nr = -1;
 static int ioval = 0xf;
 static __u16 curvol;
@@ -135,7 +136,7 @@
 static int tr_getsigstr(void)
 {
 	int i, v;
-	
+
 	for(i = 0, v = 0; i < 100; i++) v |= inb(io);
 	return (v & 1)? 0 : 0xffff;
 }
@@ -175,7 +176,7 @@
 		{
 			struct video_tuner *v = arg;
 
-			if(v->tuner)	/* Only 1 tuner */ 
+			if(v->tuner)	/* Only 1 tuner */
 				return -EINVAL;
 
 			v->rangelow = 87500 * 16;
@@ -211,28 +212,28 @@
 			return 0;
 		}
 		case VIDIOCGAUDIO:
-		{	
+		{
 			struct video_audio *v = arg;
 
 			memset(v,0, sizeof(*v));
 			v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
-			          VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+				  VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
 			v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
 			v->volume = curvol * 2048;
 			v->step = 2048;
 			v->bass = curbass * 4370;
 			v->treble = curtreble * 4370;
-			
+
 			strcpy(v->name, "Trust FM Radio");
-			return 0;			
+			return 0;
 		}
 		case VIDIOCSAUDIO:
 		{
 			struct video_audio *v = arg;
 
-			if(v->audio) 
+			if(v->audio)
 				return -EINVAL;
-			tr_setvol(v->volume);					
+			tr_setvol(v->volume);
 			tr_setbass(v->bass);
 			tr_settreble(v->treble);
 			tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
@@ -292,7 +293,7 @@
 	write_i2c(2, TDA7318_ADDR, 0xe0);	/* speaker att. RR = 0 dB */
 	write_i2c(2, TDA7318_ADDR, 0x40);	/* stereo 1 input, gain = 18.75 dB */
 
-	tr_setvol(0x8000);					
+	tr_setvol(0x8000);
 	tr_setbass(0x8000);
 	tr_settreble(0x8000);
 	tr_setstereo(1);
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index e509558..edd0122 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -36,6 +36,7 @@
 #include <asm/io.h>		/* outb, outb_p                   */
 #include <asm/uaccess.h>	/* copy to/from user              */
 #include <linux/videodev.h>	/* kernel radio structs           */
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_TYPHOON_*         */
 
 #define BANNER "Typhoon Radio Card driver v0.1\n"
@@ -361,8 +362,8 @@
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
 	if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
-				    typhoon_get_info)) 
-	    	printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+				    typhoon_get_info))
+		printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
 #endif
 
 	return 0;
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 7bf1a42..59b86a6 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -1,7 +1,7 @@
 /* zoltrix radio plus driver for Linux radio support
  * (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
  *
- * BUGS  
+ * BUGS
  *  Due to the inconsistency in reading from the signal flags
  *  it is difficult to get an accurate tuned signal.
  *
@@ -14,7 +14,7 @@
  *
  * 1999-05-06 - (C. van Schaik)
  *	      - Make signal strength and stereo scans
- *	        kinder to cpu while in delay
+ *		kinder to cpu while in delay
  * 1999-01-05 - (C. van Schaik)
  *	      - Changed tuning to 1/160Mhz accuracy
  *	      - Added stereo support
@@ -33,6 +33,7 @@
 #include <asm/io.h>		/* outb, outb_p                   */
 #include <asm/uaccess.h>	/* copy to/from user              */
 #include <linux/videodev.h>	/* kernel radio structs           */
+#include <media/v4l2-common.h>
 #include <linux/config.h>	/* CONFIG_RADIO_ZOLTRIX_PORT      */
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
@@ -105,7 +106,7 @@
 	i = 45;
 
 	mutex_lock(&dev->lock);
-	
+
 	outb(0, io);
 	outb(0, io);
 	inb(io + 3);            /* Zoltrix needs to be read to confirm */
@@ -139,8 +140,8 @@
 	udelay(1000);
 	inb(io+2);
 
-        udelay(1000);
-        
+	udelay(1000);
+
 	if (dev->muted)
 	{
 		outb(0, io);
@@ -148,12 +149,12 @@
 		inb(io + 3);
 		udelay(1000);
 	}
-	
+
 	mutex_unlock(&dev->lock);
-	
+
 	if(!dev->muted)
 	{
-	        zol_setvol(dev, dev->curvol);
+		zol_setvol(dev, dev->curvol);
 	}
 	return 0;
 }
@@ -174,14 +175,14 @@
 	b = inb(io);
 
 	mutex_unlock(&dev->lock);
-	
+
 	if (a != b)
 		return (0);
 
-        if ((a == 0xcf) || (a == 0xdf)  /* I found this out by playing */
+	if ((a == 0xcf) || (a == 0xdf)  /* I found this out by playing */
 		|| (a == 0xef))       /* with a binary scanner on the card io */
 		return (1);
- 	return (0);
+	return (0);
 }
 
 static int zol_is_stereo (struct zol_device *dev)
@@ -189,7 +190,7 @@
 	int x1, x2;
 
 	mutex_lock(&dev->lock);
-	
+
 	outb(0x00, io);
 	outb(dev->curvol, io);
 	msleep(20);
@@ -199,7 +200,7 @@
 	x2 = inb(io);
 
 	mutex_unlock(&dev->lock);
-	
+
 	if ((x1 == x2) && (x1 == 0xcf))
 		return 1;
 	return 0;
@@ -226,7 +227,7 @@
 	case VIDIOCGTUNER:
 		{
 			struct video_tuner *v = arg;
-			if (v->tuner)	
+			if (v->tuner)
 				return -EINVAL;
 			strcpy(v->name, "FM");
 			v->rangelow = (int) (88.0 * 16000);
@@ -351,7 +352,7 @@
 	printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
 
 	mutex_init(&zoltrix_unit.lock);
-	
+
 	/* mute card - prevents noisy bootups */
 
 	/* this ensures that the volume is all the way down  */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6b41970..e429049 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -224,6 +224,12 @@
 	  support for the Linux Media Labs LML33R10 MJPEG capture/playback
 	  card.
 
+config VIDEO_ZORAN_AVS6EYES
+	tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+	depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+	help
+	  Support for the AverMedia 6 Eyes video surveillance card.
+
 config VIDEO_ZR36120
 	tristate "Zoran ZR36120/36125 Video For Linux"
 	depends on PCI && I2C && VIDEO_V4L1 && BROKEN
@@ -306,17 +312,6 @@
 
 source "drivers/media/video/cx88/Kconfig"
 
-config VIDEO_OVCAMCHIP
-	tristate "OmniVision Camera Chip support"
-	depends on I2C && VIDEO_V4L1
-	---help---
-	  Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
-	  This driver is intended to be used with the ov511 and w9968cf USB
-	  camera drivers.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ovcamchip.
-
 config VIDEO_M32R_AR
 	tristate "AR devices"
 	depends on M32R && VIDEO_V4L1
@@ -357,6 +352,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called cs53l32a.
 
+config VIDEO_TLV320AIC23B
+	tristate "Texas Instruments TLV320AIC23B audio codec"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Texas Instruments TLV320AIC23B audio codec.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tlv320aic23b.
+
 config VIDEO_WM8775
 	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
 	depends on VIDEO_DEV && I2C && EXPERIMENTAL
@@ -377,13 +381,25 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called wm8739.
 
+config VIDEO_CX2341X
+	tristate "Conexant CX2341x MPEG encoders"
+	depends on VIDEO_V4L2 && EXPERIMENTAL
+	---help---
+	  Support for the Conexant CX23416 MPEG encoders
+	  and CX23415 MPEG encoder/decoders.
+
+	  This module currently supports the encoding functions only.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx2341x.
+
 source "drivers/media/video/cx25840/Kconfig"
 
 config VIDEO_SAA711X
-	tristate "Philips SAA7113/4/5 video decoders (OBSOLETED)"
-	depends on VIDEO_V4L1 && I2C && EXPERIMENTAL
+	tristate "Philips SAA7113/4/5 video decoders"
+	depends on VIDEO_DEV && I2C && EXPERIMENTAL
 	---help---
-	  Old support for the Philips SAA7113/4 video decoders.
+	  Support for the Philips SAA7113/4/5 video decoders.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa7115.
@@ -447,6 +463,35 @@
 
 source "drivers/media/video/et61x251/Kconfig"
 
+config VIDEO_OVCAMCHIP
+	tristate "OmniVision Camera Chip support"
+	depends on I2C && VIDEO_V4L1
+	---help---
+	  Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
+	  This driver is intended to be used with the ov511 and w9968cf USB
+	  camera drivers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ovcamchip.
+
+config USB_W9968CF
+	tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+	depends on USB && VIDEO_V4L1 && I2C
+	select VIDEO_OVCAMCHIP
+	---help---
+	  Say Y here if you want support for cameras based on OV681 or
+	  Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
+
+	  This driver has an optional plugin, which is distributed as a
+	  separate module only (released under GPL). It allows to use higher
+	  resolutions and framerates, but cannot be included in the official
+	  Linux kernel for performance purposes.
+
+	  See <file:Documentation/video4linux/w9968cf.txt> for more info.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w9968cf.
+
 config USB_OV511
 	tristate "USB OV511 Camera support"
 	depends on USB && VIDEO_V4L1
@@ -483,24 +528,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called stv680.
 
-config USB_W9968CF
-	tristate "USB W996[87]CF JPEG Dual Mode Camera support"
-	depends on USB && VIDEO_V4L1 && I2C
-	select VIDEO_OVCAMCHIP
-	---help---
-	  Say Y here if you want support for cameras based on OV681 or
-	  Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
-	  This driver has an optional plugin, which is distributed as a
-	  separate module only (released under GPL). It allows to use higher
-	  resolutions and framerates, but cannot be included in the official
-	  Linux kernel for performance purposes.
-
-	  See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called w9968cf.
-
 source "drivers/media/video/zc0301/Kconfig"
 
 source "drivers/media/video/pwc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e5bf268..6c401b4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -6,7 +6,7 @@
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
 tuner-objs	:=	tuner-core.o tuner-types.o tuner-simple.o \
-			mt20xx.o tda8290.o tea5767.o
+			mt20xx.o tda8290.o tea5767.o tda9887.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
@@ -33,6 +33,7 @@
 	zr36016.o
 obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
 obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
 obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
@@ -48,6 +49,7 @@
 obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
@@ -58,7 +60,7 @@
 obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 obj-$(CONFIG_VIDEO_BUF)   += video-buf.o
 obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
@@ -71,6 +73,7 @@
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
 obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_DSBR)          += dsbr100.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index dbe0251..6e08e32 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -31,6 +31,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
@@ -212,7 +213,7 @@
 	ar_outl(0x0300, PLDI2CMOD); 	/* I2CMOD ACK/8b-data/7b-addr/auto */
 	ar_outl(0x1, PLDI2CACK);	/* I2CACK ACK                      */
 
-    	/* I2C CLK */
+	/* I2C CLK */
 	/* 50MH-100k */
 	if (freq == 75) {
 		ar_outl(369, PLDI2CFREQ);	/* BCLK = 75MHz */
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
new file mode 100644
index 0000000..05e42bb
--- /dev/null
+++ b/drivers/media/video/bt866.c
@@ -0,0 +1,377 @@
+/*
+    bt866 - BT866 Digital Video Encoder (Rockwell Part)
+
+    Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+    Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+    Modifications for LML33/DC10plus unified driver
+    Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+    This code was modify/ported from the saa7111 driver written
+    by Dave Perks.
+
+    This code was adapted for the bt866 by Christer Weinigel and ported
+    to 2.6 by Martin Samuelsson.
+
+    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 <linux/types.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+
+#include <linux/video_encoder.h>
+
+MODULE_LICENSE("GPL");
+
+#define	BT866_DEVNAME	"bt866"
+#define I2C_BT866	0x88
+
+MODULE_LICENSE("GPL");
+
+#define DEBUG(x)		/* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt866 {
+	struct i2c_client *i2c;
+	int addr;
+	unsigned char reg[128];
+
+	int norm;
+	int enable;
+	int bright;
+	int contrast;
+	int hue;
+	int sat;
+};
+
+static int bt866_write(struct bt866 *dev,
+			unsigned char subaddr, unsigned char data);
+
+static int bt866_do_command(struct bt866 *encoder,
+			unsigned int cmd, void *arg)
+{
+	switch (cmd) {
+	case ENCODER_GET_CAPABILITIES:
+	{
+		struct video_encoder_capability *cap = arg;
+
+		DEBUG(printk
+		      (KERN_INFO "%s: get capabilities\n",
+		       encoder->i2c->name));
+
+		cap->flags
+			= VIDEO_ENCODER_PAL
+			| VIDEO_ENCODER_NTSC
+			| VIDEO_ENCODER_CCIR;
+		cap->inputs = 2;
+		cap->outputs = 1;
+	}
+	break;
+
+	case ENCODER_SET_NORM:
+	{
+		int *iarg = arg;
+
+		DEBUG(printk(KERN_INFO "%s: set norm %d\n",
+			     encoder->i2c->name, *iarg));
+
+		switch (*iarg) {
+
+		case VIDEO_MODE_NTSC:
+			break;
+
+		case VIDEO_MODE_PAL:
+			break;
+
+		default:
+			return -EINVAL;
+
+		}
+		encoder->norm = *iarg;
+	}
+	break;
+
+	case ENCODER_SET_INPUT:
+	{
+		int *iarg = arg;
+		static const __u8 init[] = {
+			0xc8, 0xcc, /* CRSCALE */
+			0xca, 0x91, /* CBSCALE */
+			0xcc, 0x24, /* YC16 | OSDNUM */
+			0xda, 0x00, /*  */
+			0xdc, 0x24, /* SETMODE | PAL */
+			0xde, 0x02, /* EACTIVE */
+
+			/* overlay colors */
+			0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+			0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+			0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+			0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+			0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+			0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+			0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+			0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+			0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+			0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+			0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+			0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+			0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+			0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+			0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+			0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+		};
+		int i;
+		u8 val;
+
+		for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+			bt866_write(encoder, init[i], init[i+1]);
+
+		val = encoder->reg[0xdc];
+
+		if (*iarg == 0)
+			val |= 0x40; /* CBSWAP */
+		else
+			val &= ~0x40; /* !CBSWAP */
+
+		bt866_write(encoder, 0xdc, val);
+
+		val = encoder->reg[0xcc];
+		if (*iarg == 2)
+			val |= 0x01; /* OSDBAR */
+		else
+			val &= ~0x01; /* !OSDBAR */
+		bt866_write(encoder, 0xcc, val);
+
+		DEBUG(printk(KERN_INFO "%s: set input %d\n",
+			     encoder->i2c->name, *iarg));
+
+		switch (*iarg) {
+		case 0:
+			break;
+		case 1:
+			break;
+		default:
+			return -EINVAL;
+
+		}
+	}
+	break;
+
+	case ENCODER_SET_OUTPUT:
+	{
+		int *iarg = arg;
+
+		DEBUG(printk(KERN_INFO "%s: set output %d\n",
+			     encoder->i2c->name, *iarg));
+
+		/* not much choice of outputs */
+		if (*iarg != 0)
+			return -EINVAL;
+	}
+	break;
+
+	case ENCODER_ENABLE_OUTPUT:
+	{
+		int *iarg = arg;
+		encoder->enable = !!*iarg;
+
+		DEBUG(printk
+		      (KERN_INFO "%s: enable output %d\n",
+		       encoder->i2c->name, encoder->enable));
+	}
+	break;
+
+	case 4711:
+	{
+		int *iarg = arg;
+		__u8 val;
+
+		printk("bt866: square = %d\n", *iarg);
+
+		val = encoder->reg[0xdc];
+		if (*iarg)
+			val |= 1; /* SQUARE */
+		else
+			val &= ~1; /* !SQUARE */
+		bt866_write(encoder, 0xdc, val);
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bt866_write(struct bt866 *encoder,
+			unsigned char subaddr, unsigned char data)
+{
+	unsigned char buffer[2];
+	int err;
+
+	buffer[0] = subaddr;
+	buffer[1] = data;
+
+	encoder->reg[subaddr] = data;
+
+	DEBUG(printk
+	      ("%s: write 0x%02X = 0x%02X\n",
+	       encoder->i2c->name, subaddr, data));
+
+	for (err = 0; err < 3;) {
+		if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
+			break;
+		err++;
+		printk(KERN_WARNING "%s: I/O error #%d "
+		       "(write 0x%02x/0x%02x)\n",
+		       encoder->i2c->name, err, encoder->addr, subaddr);
+		schedule_timeout_interruptible(HZ/10);
+	}
+	if (err == 3) {
+		printk(KERN_WARNING "%s: giving up\n",
+		       encoder->i2c->name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter);
+static int bt866_detach(struct i2c_client *client);
+static int bt866_command(struct i2c_client *client,
+			 unsigned int cmd, void *arg);
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[]	= {I2C_BT866>>1, I2C_CLIENT_END};
+static unsigned short probe[2]		= {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2]		= {I2C_CLIENT_END, I2C_CLIENT_END};
+
+static struct i2c_client_address_data addr_data = {
+	normal_i2c,
+	probe,
+	ignore,
+};
+
+static struct i2c_driver i2c_driver_bt866 = {
+	.driver.name = BT866_DEVNAME,
+	.id = I2C_DRIVERID_BT866,
+	.attach_adapter = bt866_attach,
+	.detach_client = bt866_detach,
+	.command = bt866_command
+};
+
+
+static struct i2c_client bt866_client_tmpl =
+{
+	.name = "(nil)",
+	.addr = 0,
+	.adapter = NULL,
+	.driver = &i2c_driver_bt866,
+	.usage_count = 0
+};
+
+static int bt866_found_proc(struct i2c_adapter *adapter,
+			    int addr, int kind)
+{
+	struct bt866 *encoder;
+	struct i2c_client *client;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (client == NULL)
+		return -ENOMEM;
+	memcpy(client, &bt866_client_tmpl, sizeof(*client));
+
+	encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+	if (encoder == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, encoder);
+	client->adapter = adapter;
+	client->addr = addr;
+	sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
+
+	encoder->i2c = client;
+	encoder->addr = addr;
+	//encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
+
+	/* initialize */
+
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter)
+{
+	if (adapter->id == I2C_HW_B_ZR36067)
+		return i2c_probe(adapter, &addr_data, bt866_found_proc);
+	return 0;
+}
+
+static int bt866_detach(struct i2c_client *client)
+{
+	struct bt866 *encoder = i2c_get_clientdata(client);
+
+	i2c_detach_client(client);
+	kfree(encoder);
+	kfree(client);
+
+	return 0;
+}
+
+static int bt866_command(struct i2c_client *client,
+			 unsigned int cmd, void *arg)
+{
+	struct bt866 *encoder = i2c_get_clientdata(client);
+	return bt866_do_command(encoder, cmd, arg);
+}
+
+static int __devinit bt866_init(void)
+{
+	i2c_add_driver(&i2c_driver_bt866);
+	return 0;
+}
+
+static void __devexit bt866_exit(void)
+{
+	i2c_del_driver(&i2c_driver_bt866);
+}
+
+module_init(bt866_init);
+module_exit(bt866_exit);
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 2b64aa8..e68a6d2 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -269,7 +269,7 @@
 	{ 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
 	{ 0x18501f7f, BTTV_BOARD_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
 
-    	{ 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
+	{ 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
 	{ 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
 
 	{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
@@ -309,6 +309,7 @@
 	{ 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
 	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
 	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
+	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,	"DNTV Live! Mini "},
 
 	{ 0, -1, NULL }
 };
@@ -1903,7 +1904,7 @@
 		.no_tda7432     = 1,
 	},
 	[BTTV_BOARD_OSPREY2x0] = {
-		.name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
+		.name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
 		.video_inputs   = 2,
 		.audio_inputs   = 1,
 		.tuner          = -1,
@@ -2745,7 +2746,7 @@
 		/* Michael Krufky <mkrufky@m1k.net> */
 		.name           = "DViCO FusionHDTV 5 Lite",
 		.tuner          = 0,
-		.tuner_type     = TUNER_LG_TDVS_H062F,
+		.tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.video_inputs   = 3,
@@ -2762,7 +2763,7 @@
 	},
 		/* ---- card 0x88---------------------------------- */
 	[BTTV_BOARD_ACORP_Y878F] = {
-		/* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+		/* Mauro Carvalho Chehab <mchehab@infradead.org> */
 		.name		= "Acorp Y878F",
 		.video_inputs	= 3,
 		.audio_inputs	= 1,
@@ -3790,6 +3791,7 @@
 		       break;
 	       case 0x0060:
 	       case 0x0070:
+	       case 0x00A0:
 		       btv->c.type = BTTV_BOARD_OSPREY2x0;
 		       /* enable output on select control lines */
 		       gpio_inout(0xffffff,0x000303);
@@ -4846,7 +4848,7 @@
  *
  * The IVC120G security card has 4 i2c controlled TDA8540 matrix
  * swichers to provide 16 channels to MUX0. The TDA8540's have
- * 4 indepedant outputs and as such the IVC120G also has the
+ * 4 independent outputs and as such the IVC120G also has the
  * optional "Monitor Out" bus. This allows the card to be looking
  * at one input while the monitor is looking at another.
  *
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index c4d5e2b..ba081f6 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -118,20 +118,6 @@
 	return 0;
 }
 
-void bttv_gpio_irq(struct bttv_core *core)
-{
-	struct bttv_sub_driver *drv;
-	struct bttv_sub_device *dev;
-	struct list_head *item;
-
-	list_for_each(item,&core->subs) {
-		dev = list_entry(item,struct bttv_sub_device,list);
-		drv = to_bttv_sub_drv(dev->dev.driver);
-		if (drv && drv->gpio_irq)
-			drv->gpio_irq(dev);
-	}
-}
-
 /* ----------------------------------------------------------------------- */
 /* external: sub-driver register/unregister                                */
 
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 69efa0e..b41f81d 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -355,7 +355,7 @@
 
 	if (ir->rc5_gpio) {
 		u32 gpio;
-	    	/* enable remote irq */
+		/* enable remote irq */
 		bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
 		gpio = bttv_gpio_read(&btv->c);
 		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 3a23265..f9c9e3c 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -350,7 +350,6 @@
 	char                   wanted[BUS_ID_SIZE];
 	int                    (*probe)(struct bttv_sub_device *sub);
 	void                   (*remove)(struct bttv_sub_device *sub);
-	void                   (*gpio_irq)(struct bttv_sub_device *sub);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
 
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index ee989d2..d295601 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,6 +33,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/mutex.h>
@@ -214,7 +215,6 @@
 extern struct bus_type bttv_sub_bus_type;
 int bttv_sub_add_device(struct bttv_core *core, char *name);
 int bttv_sub_del_devices(struct bttv_core *core);
-void bttv_gpio_irq(struct bttv_core *core);
 
 
 /* ---------------------------------------------------------- */
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index cf61c59..7d0b6e5 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -73,6 +73,7 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
 
@@ -759,7 +760,7 @@
 		{
 			struct video_picture *p = arg;
 			if(p->palette!=VIDEO_PALETTE_GREY)
-			    	return -EINVAL;
+				return -EINVAL;
 			if(p->depth!=4 && p->depth!=6)
 				return -EINVAL;
 
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 22a7386..a3989bd 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -34,6 +34,7 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 85d84e8..95c5ace 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -47,13 +47,6 @@
 
 #include "cpia.h"
 
-#ifdef CONFIG_VIDEO_CPIA_PP
-extern int cpia_pp_init(void);
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-extern int cpia_usb_init(void);
-#endif
-
 static int video_nr = -1;
 
 #ifdef MODULE
@@ -67,10 +60,10 @@
 static unsigned short colorspace_conv;
 module_param(colorspace_conv, ushort, 0444);
 MODULE_PARM_DESC(colorspace_conv,
-                 " Colorspace conversion:"
-                 "\n  0 = disable, 1 = enable"
-                 "\n  Default value is 0"
-                 );
+		 " Colorspace conversion:"
+		 "\n  0 = disable, 1 = enable"
+		 "\n  Default value is 0"
+		 );
 
 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
 
@@ -4047,13 +4040,6 @@
 	proc_cpia_create();
 #endif
 
-#ifdef CONFIG_VIDEO_CPIA_PP
-	cpia_pp_init();
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-	cpia_usb_init();
-#endif
-
 	return 0;
 }
 
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index dde27a6..6eaa692 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -45,6 +45,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
 #include <linux/mutex.h>
@@ -247,7 +248,7 @@
 struct cam_data {
 	struct list_head cam_data_list;
 
-	struct mutex busy_lock;     /* guard against SMP multithreading */
+	struct mutex busy_lock;		/* guard against SMP multithreading */
 	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
 	void *lowlevel_data;		/* private data for lowlevel driver */
 	u8 *raw_image;			/* buffer for raw image data */
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index 1764991..c5ecb2b 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -33,6 +33,7 @@
 
 #include <linux/version.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
 
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 481e178..d129db5 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -343,7 +343,9 @@
 		cpia2_free_buffers(cam);
 		if (!cam->present) {
 			video_unregister_device(dev);
+			mutex_unlock(&cam->busy_lock);
 			kfree(cam);
+			return 0;
 		}
 	}
 
@@ -1167,9 +1169,9 @@
 		} else {
 		    if(cam->params.flicker_control.cam_register &
 		       CPIA2_VP_FLICKER_MODES_50HZ) {
-		    	mode = FLICKER_50;
+			mode = FLICKER_50;
 		    } else {
-		    	mode = FLICKER_60;
+			mode = FLICKER_60;
 		    }
 		}
 		for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index 0b00e60..4c89bd3 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -803,7 +803,7 @@
 	.detach = cpia_pp_detach,
 };
 
-int cpia_pp_init(void)
+static int cpia_pp_init(void)
 {
 	printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
 	       CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
@@ -860,6 +860,8 @@
 
 static int __init cpia_pp_setup(char *str)
 {
+	int err;
+
 	if (!strncmp(str, "parport", 7)) {
 		int n = simple_strtoul(str + 7, NULL, 10);
 		if (parport_ptr < PARPORT_MAX) {
@@ -873,6 +875,10 @@
 		parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
 	}
 
+	err=cpia_pp_init();
+	if (err)
+		return err;
+
 	return 1;
 }
 
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 9c49a4b..2ee34a3 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -474,12 +474,6 @@
 	return 0;
 }
 
-int cpia_usb_init(void)
-{
-	/* return -ENODEV; */
-	return 0;
-}
-
 /* Probing and initializing */
 
 static int cpia_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
new file mode 100644
index 0000000..01b22ea
--- /dev/null
+++ b/drivers/media/video/cx2341x.c
@@ -0,0 +1,932 @@
+/*
+ * cx2341x - generic code for cx23415/6 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+const u32 cx2341x_mpeg_ctrls[] = {
+	V4L2_CID_MPEG_CLASS,
+	V4L2_CID_MPEG_STREAM_TYPE,
+	V4L2_CID_MPEG_STREAM_VBI_FMT,
+	V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+	V4L2_CID_MPEG_AUDIO_ENCODING,
+	V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+	V4L2_CID_MPEG_AUDIO_MODE,
+	V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+	V4L2_CID_MPEG_AUDIO_EMPHASIS,
+	V4L2_CID_MPEG_AUDIO_CRC,
+	V4L2_CID_MPEG_VIDEO_ENCODING,
+	V4L2_CID_MPEG_VIDEO_ASPECT,
+	V4L2_CID_MPEG_VIDEO_B_FRAMES,
+	V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+	V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+	V4L2_CID_MPEG_VIDEO_PULLDOWN,
+	V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+	V4L2_CID_MPEG_VIDEO_BITRATE,
+	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+	V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+	V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+	V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+	0
+};
+
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+   struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+		struct v4l2_ext_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		ctrl->value = params->audio_sampling_freq;
+		break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		ctrl->value = params->audio_encoding;
+		break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		ctrl->value = params->audio_l2_bitrate;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE:
+		ctrl->value = params->audio_mode;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		ctrl->value = params->audio_mode_extension;
+		break;
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+		ctrl->value = params->audio_emphasis;
+		break;
+	case V4L2_CID_MPEG_AUDIO_CRC:
+		ctrl->value = params->audio_crc;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		ctrl->value = params->video_encoding;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		ctrl->value = params->video_aspect;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		ctrl->value = params->video_b_frames;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		ctrl->value = params->video_gop_size;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		ctrl->value = params->video_gop_closure;
+		break;
+	case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+		ctrl->value = params->video_pulldown;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		ctrl->value = params->video_bitrate_mode;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		ctrl->value = params->video_bitrate;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		ctrl->value = params->video_bitrate_peak;
+		break;
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		ctrl->value = params->video_temporal_decimation;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		ctrl->value = params->stream_type;
+		break;
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		ctrl->value = params->stream_vbi_fmt;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		ctrl->value = params->video_spatial_filter_mode;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		ctrl->value = params->video_spatial_filter;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		ctrl->value = params->video_luma_spatial_filter_type;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		ctrl->value = params->video_chroma_spatial_filter_type;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		ctrl->value = params->video_temporal_filter_mode;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		ctrl->value = params->video_temporal_filter;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		ctrl->value = params->video_median_filter_type;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		ctrl->value = params->video_luma_median_filter_top;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		ctrl->value = params->video_luma_median_filter_bottom;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		ctrl->value = params->video_chroma_median_filter_top;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		ctrl->value = params->video_chroma_median_filter_bottom;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+   struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+		struct v4l2_ext_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		params->audio_sampling_freq = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		params->audio_encoding = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		params->audio_l2_bitrate = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE:
+		params->audio_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		params->audio_mode_extension = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+		params->audio_emphasis = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_AUDIO_CRC:
+		params->audio_crc = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		params->video_aspect = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+		int b = ctrl->value + 1;
+		int gop = params->video_gop_size;
+		params->video_b_frames = ctrl->value;
+		params->video_gop_size = b * ((gop + b - 1) / b);
+		/* Max GOP size = 34 */
+		while (params->video_gop_size > 34)
+			params->video_gop_size -= b;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+		int b = params->video_b_frames + 1;
+		int gop = ctrl->value;
+		params->video_gop_size = b * ((gop + b - 1) / b);
+		/* Max GOP size = 34 */
+		while (params->video_gop_size > 34)
+			params->video_gop_size -= b;
+		ctrl->value = params->video_gop_size;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		params->video_gop_closure = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+		params->video_pulldown = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		/* MPEG-1 only allows CBR */
+		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
+		    ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			return -EINVAL;
+		params->video_bitrate_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		params->video_bitrate = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		params->video_bitrate_peak = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		params->video_temporal_decimation = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		params->stream_type = ctrl->value;
+		params->video_encoding =
+			(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+			 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+			/* MPEG-1 implies CBR */
+			params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+		}
+		break;
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		params->stream_vbi_fmt = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		params->video_spatial_filter_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		params->video_spatial_filter = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		params->video_luma_spatial_filter_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		params->video_chroma_spatial_filter_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		params->video_temporal_filter_mode = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		params->video_temporal_filter = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		params->video_median_filter_type = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		params->video_luma_median_filter_top = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		params->video_luma_median_filter_bottom = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		params->video_chroma_median_filter_top = ctrl->value;
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		params->video_chroma_median_filter_bottom = ctrl->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+	const char *name;
+
+	qctrl->flags = 0;
+	switch (qctrl->id) {
+	/* MPEG controls */
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		name = "Spatial Filter Mode";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		name = "Spatial Filter";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		name = "Spatial Luma Filter Type";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		name = "Spatial Chroma Filter Type";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		name = "Temporal Filter Mode";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		name = "Temporal Filter";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		name = "Median Filter Type";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		name = "Median Luma Filter Maximum";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		name = "Median Luma Filter Minimum";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		name = "Median Chroma Filter Maximum";
+		break;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		name = "Median Chroma Filter Minimum";
+		break;
+
+	default:
+		return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+	}
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		qctrl->type = V4L2_CTRL_TYPE_MENU;
+		min = 0;
+		step = 1;
+		break;
+	default:
+		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+		break;
+	}
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+		break;
+	}
+	qctrl->minimum = min;
+	qctrl->maximum = max;
+	qctrl->step = step;
+	qctrl->default_value = def;
+	qctrl->reserved[0] = qctrl->reserved[1] = 0;
+	snprintf(qctrl->name, sizeof(qctrl->name), name);
+	return 0;
+}
+
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+{
+	int err;
+
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+				V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+		return -EINVAL;
+
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		err = v4l2_ctrl_query_fill_std(qctrl);
+		if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		/* this setting is read-only for the cx2341x since the
+		   V4L2_CID_MPEG_STREAM_TYPE really determines the
+		   MPEG-1/2 setting */
+		err = v4l2_ctrl_query_fill_std(qctrl);
+		if (err == 0)
+			qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+		return err;
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		err = v4l2_ctrl_query_fill_std(qctrl);
+		if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		err = v4l2_ctrl_query_fill_std(qctrl);
+		if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return err;
+
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+			return v4l2_ctrl_query_fill_std(qctrl);
+		return cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE);
+
+	/* CX23415/6 specific */
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		return cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
+				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
+				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		return cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		return cx2341x_ctrl_query_fill(qctrl,
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		return 0;
+
+	default:
+		return v4l2_ctrl_query_fill_std(qctrl);
+
+	}
+}
+
+const char **cx2341x_ctrl_get_menu(u32 id)
+{
+	static const char *mpeg_stream_type[] = {
+		"MPEG-2 Program Stream",
+		"",
+		"MPEG-1 System Stream",
+		"MPEG-2 DVD-compatible Stream",
+		"MPEG-1 VCD-compatible Stream",
+		"MPEG-2 SVCD-compatible Stream",
+		NULL
+	};
+
+	static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+		"Manual",
+		"Auto",
+		NULL
+	};
+
+	static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+		"Off",
+		"1D Horizontal",
+		"1D Vertical",
+		"2D H/V Separable",
+		"2D Symmetric non-separable",
+		NULL
+	};
+
+	static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+		"Off",
+		"1D Horizontal",
+		NULL
+	};
+
+	static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+		"Manual",
+		"Auto",
+		NULL
+	};
+
+	static const char *cx2341x_video_median_filter_type_menu[] = {
+		"Off",
+		"Horizontal",
+		"Vertical",
+		"Horizontal/Vertical",
+		"Diagonal",
+		NULL
+	};
+
+	switch (id) {
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return mpeg_stream_type;
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+		return NULL;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+		return cx2341x_video_spatial_filter_mode_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+		return cx2341x_video_luma_spatial_filter_type_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+		return cx2341x_video_chroma_spatial_filter_type_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+		return cx2341x_video_temporal_filter_mode_menu;
+	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+		return cx2341x_video_median_filter_type_menu;
+	default:
+		return v4l2_ctrl_get_menu(id);
+	}
+}
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+	params->audio_properties = (params->audio_sampling_freq << 0) |
+		((3 - params->audio_encoding) << 2) |
+		((1 + params->audio_l2_bitrate) << 4) |
+		(params->audio_mode << 8) |
+		(params->audio_mode_extension << 10) |
+		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
+		  3 :
+		  params->audio_emphasis) << 12) |
+		(params->audio_crc << 14);
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+		  struct v4l2_ext_controls *ctrls, int cmd)
+{
+	int err = 0;
+	int i;
+
+	if (cmd == VIDIOC_G_EXT_CTRLS) {
+		for (i = 0; i < ctrls->count; i++) {
+			struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+			err = cx2341x_get_ctrl(params, ctrl);
+			if (err) {
+				ctrls->error_idx = i;
+				break;
+			}
+		}
+		return err;
+	}
+	for (i = 0; i < ctrls->count; i++) {
+		struct v4l2_ext_control *ctrl = ctrls->controls + i;
+		struct v4l2_queryctrl qctrl;
+		const char **menu_items = NULL;
+
+		qctrl.id = ctrl->id;
+		err = cx2341x_ctrl_query(params, &qctrl);
+		if (err)
+			break;
+		if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+			menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+		err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+		if (err)
+			break;
+		err = cx2341x_set_ctrl(params, ctrl);
+		if (err)
+			break;
+	}
+	if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+			params->video_bitrate_peak < params->video_bitrate) {
+		err = -ERANGE;
+		ctrls->error_idx = ctrls->count;
+	}
+	if (err) {
+		ctrls->error_idx = i;
+	}
+	else {
+		cx2341x_calc_audio_properties(params);
+	}
+	return err;
+}
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+	static struct cx2341x_mpeg_params default_params = {
+	/* misc */
+	.capabilities = 0,
+	.port = CX2341X_PORT_MEMORY,
+	.width = 720,
+	.height = 480,
+	.is_50hz = 0,
+
+	/* stream */
+	.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+	.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+
+	/* audio */
+	.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+	.audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+	.audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+	.audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+	.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+	.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+	.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+
+	/* video */
+	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+	.video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+	.video_b_frames = 2,
+	.video_gop_size = 12,
+	.video_gop_closure = 1,
+	.video_pulldown = 0,
+	.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+	.video_bitrate = 6000000,
+	.video_bitrate_peak = 8000000,
+	.video_temporal_decimation = 0,
+
+	/* encoding filters */
+	.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+	.video_spatial_filter = 0,
+	.video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+	.video_temporal_filter = 0,
+	.video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+	.video_luma_median_filter_top = 255,
+	.video_luma_median_filter_bottom = 0,
+	.video_chroma_median_filter_top = 255,
+	.video_chroma_median_filter_bottom = 0,
+	};
+
+	*p = default_params;
+	cx2341x_calc_audio_properties(p);
+}
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i;
+
+	va_start(vargs, args);
+
+	for (i = 0; i < args; i++) {
+		data[i] = va_arg(vargs, int);
+	}
+	va_end(vargs);
+	return func(priv, cmd, args, 0, data);
+}
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+		const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+{
+	static int mpeg_stream_type[] = {
+		0,	/* MPEG-2 PS */
+		1,	/* MPEG-2 TS */
+		2,	/* MPEG-1 SS */
+		14,	/* DVD */
+		11,	/* VCD */
+		12,	/* SVCD */
+	};
+
+	int err = 0;
+
+	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+	if (old == NULL || old->is_50hz != new->is_50hz) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+		if (err) return err;
+	}
+
+	if (old == NULL || old->width != new->width || old->height != new->height ||
+			old->video_encoding != new->video_encoding) {
+		u16 w = new->width;
+		u16 h = new->height;
+
+		if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+			w /= 2;
+			h /= 2;
+		}
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+		if (err) return err;
+	}
+
+	if (old == NULL || old->stream_type != new->stream_type) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_aspect != new->video_aspect) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_b_frames != new->video_b_frames ||
+		old->video_gop_size != new->video_gop_size) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+				new->video_gop_size, new->video_b_frames + 1);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_pulldown != new->video_pulldown) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
+		if (err) return err;
+	}
+	if (old == NULL || old->audio_properties != new->audio_properties) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
+		old->video_bitrate != new->video_bitrate ||
+		old->video_bitrate_peak != new->video_bitrate_peak) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+				new->video_bitrate_mode, new->video_bitrate,
+				new->video_bitrate_peak / 400, 0, 0);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
+		old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
+		old->video_median_filter_type != new->video_median_filter_type) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+				new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+				new->video_median_filter_type);
+		if (err) return err;
+	}
+	if (old == NULL ||
+		old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
+		old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
+		old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
+		old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+				new->video_luma_median_filter_bottom,
+				new->video_luma_median_filter_top,
+				new->video_chroma_median_filter_bottom,
+				new->video_chroma_median_filter_top);
+		if (err) return err;
+	}
+	if (old == NULL ||
+		old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
+		old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+			new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+		if (err) return err;
+	}
+	if (old == NULL ||
+		old->video_spatial_filter != new->video_spatial_filter ||
+		old->video_temporal_filter != new->video_temporal_filter) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+			new->video_spatial_filter, new->video_temporal_filter);
+		if (err) return err;
+	}
+	if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
+			new->video_temporal_decimation);
+		if (err) return err;
+	}
+	return 0;
+}
+
+static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+{
+	const char **menu = cx2341x_ctrl_get_menu(id);
+	struct v4l2_ext_control ctrl;
+
+	if (menu == NULL)
+		goto invalid;
+	ctrl.id = id;
+	if (cx2341x_get_ctrl(p, &ctrl))
+		goto invalid;
+	while (ctrl.value-- && *menu) menu++;
+	if (*menu == NULL)
+		goto invalid;
+	return *menu;
+
+invalid:
+	return "<invalid>";
+}
+
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
+{
+	int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+	/* Stream */
+	printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
+		card_id,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+
+	/* Video */
+	printk(KERN_INFO "cx2341x-%d: Video:  %dx%d, %d fps\n",
+		card_id,
+		p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+		p->is_50hz ? 25 : 30);
+	printk(KERN_INFO "cx2341x-%d: Video:  %s, %s, %s, %d",
+		card_id,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+		p->video_bitrate);
+	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+		printk(", Peak %d", p->video_bitrate_peak);
+	}
+	printk("\n");
+	printk(KERN_INFO "cx2341x-%d: Video:  GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+		card_id,
+		p->video_gop_size, p->video_b_frames,
+		p->video_gop_closure ? "" : "No ",
+		p->video_pulldown ? "" : "No ");
+	if (p->video_temporal_decimation) {
+		printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
+			card_id, p->video_temporal_decimation);
+	}
+
+	/* Audio */
+	printk(KERN_INFO "cx2341x-%d: Audio:  %s, %s, %s, %s",
+		card_id,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
+		printk(", %s",
+			cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+	}
+	printk(", %s, %s\n",
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+	/* Encoding filters */
+	printk(KERN_INFO "cx2341x-%d: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
+		card_id,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+		p->video_spatial_filter);
+	printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
+		card_id,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+		p->video_temporal_filter);
+	printk(KERN_INFO "cx2341x-%d: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+		card_id,
+		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+		p->video_luma_median_filter_bottom,
+		p->video_luma_median_filter_top,
+		p->video_chroma_median_filter_bottom,
+		p->video_chroma_median_filter_top);
+}
+
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+EXPORT_SYMBOL(cx2341x_update);
+EXPORT_SYMBOL(cx2341x_log_status);
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 9a4b813..f897c1e 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -30,9 +30,6 @@
 	if (freq != 32000 && freq != 44100 && freq != 48000)
 		return -EINVAL;
 
-	/* assert soft reset */
-	cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
 	/* common for all inputs and rates */
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
 	cx25840_write(client, 0x127, 0x50);
@@ -46,6 +43,9 @@
 			/* AUX_PLL_FRAC */
 			cx25840_write4(client, 0x110, 0xee39bb01);
 
+			if (state->is_cx25836)
+				break;
+
 			/* src3/4/6_ctl = 0x0801f77f */
 			cx25840_write4(client, 0x900, 0x7ff70108);
 			cx25840_write4(client, 0x904, 0x7ff70108);
@@ -59,6 +59,9 @@
 			/* AUX_PLL_FRAC */
 			cx25840_write4(client, 0x110, 0xd66bec00);
 
+			if (state->is_cx25836)
+				break;
+
 			/* src3/4/6_ctl = 0x08016d59 */
 			cx25840_write4(client, 0x900, 0x596d0108);
 			cx25840_write4(client, 0x904, 0x596d0108);
@@ -72,6 +75,9 @@
 			/* AUX_PLL_FRAC */
 			cx25840_write4(client, 0x110, 0xe5d69800);
 
+			if (state->is_cx25836)
+				break;
+
 			/* src3/4/6_ctl = 0x08014faa */
 			cx25840_write4(client, 0x900, 0xaa4f0108);
 			cx25840_write4(client, 0x904, 0xaa4f0108);
@@ -87,6 +93,9 @@
 			/* AUX_PLL_FRAC */
 			cx25840_write4(client, 0x110, 0x69082a01);
 
+			if (state->is_cx25836)
+				break;
+
 			/* src1_ctl = 0x08010000 */
 			cx25840_write4(client, 0x8f8, 0x00000108);
 
@@ -106,6 +115,9 @@
 			/* AUX_PLL_FRAC */
 			cx25840_write4(client, 0x110, 0xd66bec00);
 
+			if (state->is_cx25836)
+				break;
+
 			/* src1_ctl = 0x08010000 */
 			cx25840_write4(client, 0x8f8, 0xcd600108);
 
@@ -122,6 +134,9 @@
 			/* AUX_PLL_FRAC */
 			cx25840_write4(client, 0x110, 0xe5d69800);
 
+			if (state->is_cx25836)
+				break;
+
 			/* src1_ctl = 0x08010000 */
 			cx25840_write4(client, 0x8f8, 0x00800108);
 
@@ -133,9 +148,6 @@
 		}
 	}
 
-	/* deassert soft reset */
-	cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
 	state->audclk_freq = freq;
 
 	return 0;
@@ -148,6 +160,10 @@
 	/* stop microcontroller */
 	cx25840_and_or(client, 0x803, ~0x10, 0);
 
+	/* assert soft reset */
+	if (!state->is_cx25836)
+		cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
 	/* Mute everything to prevent the PFFT! */
 	cx25840_write(client, 0x8d3, 0x1f);
 
@@ -161,13 +177,19 @@
 	} else {
 		/* Set Path1 to Analog Demod Main Channel */
 		cx25840_write4(client, 0x8d0, 0x7038061f);
+	}
 
+	set_audclk_freq(client, state->audclk_freq);
+
+	/* deassert soft reset */
+	if (!state->is_cx25836)
+		cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		/* When the microcontroller detects the
 		 * audio format, it will unmute the lines */
 		cx25840_and_or(client, 0x803, ~0x10, 0x10);
 	}
-
-	set_audclk_freq(client, state->audclk_freq);
 }
 
 static int get_volume(struct i2c_client *client)
@@ -291,11 +313,25 @@
 
 int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	struct v4l2_control *ctrl = arg;
+	int retval;
 
 	switch (cmd) {
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-		return set_audclk_freq(client, *(u32 *)arg);
+		if (state->aud_input != CX25840_AUDIO_SERIAL) {
+			cx25840_and_or(client, 0x803, ~0x10, 0);
+			cx25840_write(client, 0x8d3, 0x1f);
+		}
+		if (!state->is_cx25836)
+			cx25840_and_or(client, 0x810, ~0x1, 1);
+		retval = set_audclk_freq(client, *(u32 *)arg);
+		if (!state->is_cx25836)
+			cx25840_and_or(client, 0x810, ~0x1, 0);
+		if (state->aud_input != CX25840_AUDIO_SERIAL) {
+			cx25840_and_or(client, 0x803, ~0x10, 0x10);
+		}
+		return retval;
 
 	case VIDIOC_G_CTRL:
 		switch (ctrl->id) {
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index a961bb2..5c2036b 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -10,6 +10,9 @@
  *
  * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
  *
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
@@ -43,7 +46,7 @@
 static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
 
 
-static int cx25840_debug;
+int cx25840_debug;
 
 module_param_named(debug,cx25840_debug, int, 0644);
 
@@ -105,7 +108,7 @@
 	    (buffer[2] << 8) | buffer[3];
 }
 
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
 		   u8 or_value)
 {
 	return cx25840_write(client, addr,
@@ -117,7 +120,8 @@
 
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
 						enum cx25840_audio_input aud_input);
-static void log_status(struct i2c_client *client);
+static void log_audio_status(struct i2c_client *client);
+static void log_video_status(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 
@@ -147,6 +151,33 @@
 	cx25840_write(client, 0x15d, 0xe1);
 }
 
+static void cx25836_initialize(struct i2c_client *client)
+{
+	/* reset configuration is described on page 3-77 of the CX25836 datasheet */
+	/* 2. */
+	cx25840_and_or(client, 0x000, ~0x01, 0x01);
+	cx25840_and_or(client, 0x000, ~0x01, 0x00);
+	/* 3a. */
+	cx25840_and_or(client, 0x15a, ~0x70, 0x00);
+	/* 3b. */
+	cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
+	/* 3c. */
+	cx25840_and_or(client, 0x159, ~0x02, 0x02);
+	/* 3d. */
+	/* There should be a 10-us delay here, but since the
+	   i2c bus already has a 10-us delay we don't need to do
+	   anything */
+	/* 3e. */
+	cx25840_and_or(client, 0x159, ~0x02, 0x00);
+	/* 3f. */
+	cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
+	/* 3g. */
+	cx25840_and_or(client, 0x159, ~0x01, 0x00);
+	cx25840_and_or(client, 0x159, ~0x01, 0x01);
+	/* 3h. */
+	cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
+}
+
 static void cx25840_initialize(struct i2c_client *client, int loadfw)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
@@ -220,17 +251,7 @@
 	cx25840_and_or(client, 0x401, ~0x60, 0);
 	cx25840_and_or(client, 0x401, ~0x60, 0x60);
 
-	/* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC
-	   instead of V4L2_STD_PAL. Someone needs to test this. */
-	if (std & V4L2_STD_PAL) {
-		/* Follow tuner change procedure for PAL */
-		cx25840_write(client, 0x808, 0xff);
-		cx25840_write(client, 0x80b, 0x10);
-	} else if (std & V4L2_STD_SECAM) {
-		/* Select autodetect for SECAM */
-		cx25840_write(client, 0x808, 0xff);
-		cx25840_write(client, 0x80b, 0x10);
-	} else if (std & V4L2_STD_NTSC) {
+	if (std & V4L2_STD_525_60) {
 		/* Certain Hauppauge PVR150 models have a hardware bug
 		   that causes audio to drop out. For these models the
 		   audio standard must be set explicitly.
@@ -249,6 +270,14 @@
 			cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
 		}
 		cx25840_write(client, 0x80b, 0x00);
+	} else if (std & V4L2_STD_PAL) {
+		/* Follow tuner change procedure for PAL */
+		cx25840_write(client, 0x808, 0xff);
+		cx25840_write(client, 0x80b, 0x10);
+	} else if (std & V4L2_STD_SECAM) {
+		/* Select autodetect for SECAM */
+		cx25840_write(client, 0x808, 0xff);
+		cx25840_write(client, 0x80b, 0x10);
 	}
 
 	if (cx25840_read(client, 0x803) & 0x10) {
@@ -319,8 +348,10 @@
 
 	state->vid_input = vid_input;
 	state->aud_input = aud_input;
-	cx25840_audio_set_path(client);
-	input_change(client);
+	if (!state->is_cx25836) {
+		cx25840_audio_set_path(client);
+		input_change(client);
+	}
 	return 0;
 }
 
@@ -354,6 +385,8 @@
 		}
 	}
 
+	v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+
 	/* Follow step 9 of section 3.16 in the cx25840 datasheet.
 	   Without this PAL may display a vertical ghosting effect.
 	   This happens for example with the Yuan MPC622. */
@@ -370,6 +403,7 @@
 
 v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	/* check VID_FMT_SEL first */
 	u8 fmt = cx25840_read(client, 0x400) & 0xf;
 
@@ -383,7 +417,7 @@
 	{
 		/* if the audio std is A2-M, then this is the South Korean
 		   NTSC standard */
-		if (cx25840_read(client, 0x805) == 2)
+		if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
 			return V4L2_STD_NTSC_M_KR;
 		return V4L2_STD_NTSC_M;
 	}
@@ -456,6 +490,8 @@
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
+		if (state->is_cx25836)
+			return -EINVAL;
 		return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
 
 	default:
@@ -490,6 +526,8 @@
 	case V4L2_CID_AUDIO_TREBLE:
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_MUTE:
+		if (state->is_cx25836)
+			return -EINVAL;
 		return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
 	default:
 		return -EINVAL;
@@ -579,91 +617,6 @@
 
 /* ----------------------------------------------------------------------- */
 
-static struct v4l2_queryctrl cx25840_qctrl[] = {
-	{
-		.id            = V4L2_CID_BRIGHTNESS,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Brightness",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = 128,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_CONTRAST,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Contrast",
-		.minimum       = 0,
-		.maximum       = 127,
-		.step          = 1,
-		.default_value = 64,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_SATURATION,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Saturation",
-		.minimum       = 0,
-		.maximum       = 127,
-		.step          = 1,
-		.default_value = 64,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_HUE,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Hue",
-		.minimum       = -128,
-		.maximum       = 127,
-		.step          = 1,
-		.default_value = 0,
-		.flags 	       = 0,
-	}, {
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 58880,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_AUDIO_BALANCE,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Balance",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 32768,
-		.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_AUDIO_BASS,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Bass",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 32768,
-	}, {
-		.id            = V4L2_CID_AUDIO_TREBLE,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Treble",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 32768,
-	},
-};
-
-/* ----------------------------------------------------------------------- */
-
 static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 			   void *arg)
 {
@@ -706,8 +659,8 @@
 
 	case VIDIOC_STREAMON:
 		v4l_dbg(1, cx25840_debug, client, "enable output\n");
-		cx25840_write(client, 0x115, 0x8c);
-		cx25840_write(client, 0x116, 0x07);
+		cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
+		cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
 		break;
 
 	case VIDIOC_STREAMOFF:
@@ -717,7 +670,9 @@
 		break;
 
 	case VIDIOC_LOG_STATUS:
-		log_status(client);
+		log_video_status(client);
+		if (!state->is_cx25836)
+			log_audio_status(client);
 		break;
 
 	case VIDIOC_G_CTRL:
@@ -729,13 +684,29 @@
 	case VIDIOC_QUERYCTRL:
 	{
 		struct v4l2_queryctrl *qc = arg;
-		int i;
 
-		for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
-			if (qc->id && qc->id == cx25840_qctrl[i].id) {
-				memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
-				return 0;
-			}
+		switch (qc->id) {
+			case V4L2_CID_BRIGHTNESS:
+			case V4L2_CID_CONTRAST:
+			case V4L2_CID_SATURATION:
+			case V4L2_CID_HUE:
+				return v4l2_ctrl_query_fill_std(qc);
+			default:
+				break;
+		}
+		if (state->is_cx25836)
+			return -EINVAL;
+
+		switch (qc->id) {
+			case V4L2_CID_AUDIO_VOLUME:
+			case V4L2_CID_AUDIO_MUTE:
+			case V4L2_CID_AUDIO_BALANCE:
+			case V4L2_CID_AUDIO_BASS:
+			case V4L2_CID_AUDIO_TREBLE:
+				return v4l2_ctrl_query_fill_std(qc);
+			default:
+				return -EINVAL;
+		}
 		return -EINVAL;
 	}
 
@@ -760,31 +731,41 @@
 		return set_input(client, route->input, state->aud_input);
 
 	case VIDIOC_INT_G_AUDIO_ROUTING:
+		if (state->is_cx25836)
+			return -EINVAL;
 		route->input = state->aud_input;
 		route->output = 0;
 		break;
 
 	case VIDIOC_INT_S_AUDIO_ROUTING:
+		if (state->is_cx25836)
+			return -EINVAL;
 		return set_input(client, state->vid_input, route->input);
 
 	case VIDIOC_S_FREQUENCY:
-		input_change(client);
+		if (!state->is_cx25836) {
+			input_change(client);
+		}
 		break;
 
 	case VIDIOC_G_TUNER:
 	{
-		u8 mode = cx25840_read(client, 0x804);
-		u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+		u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+		u8 mode;
 		int val = 0;
 
 		if (state->radio)
 			break;
 
+		vt->signal = vpres ? 0xffff : 0x0;
+		if (state->is_cx25836)
+			break;
+
 		vt->capability |=
 		    V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
 		    V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
 
-		vt->signal = vpres ? 0xffff : 0x0;
+		mode = cx25840_read(client, 0x804);
 
 		/* get rxsubchans and audmode */
 		if ((mode & 0xf) == 1)
@@ -804,7 +785,7 @@
 	}
 
 	case VIDIOC_S_TUNER:
-		if (state->radio)
+		if (state->radio || state->is_cx25836)
 			break;
 
 		switch (vt->audmode) {
@@ -846,12 +827,14 @@
 		return set_v4lfmt(client, (struct v4l2_format *)arg);
 
 	case VIDIOC_INT_RESET:
-		cx25840_initialize(client, 0);
+		if (state->is_cx25836)
+			cx25836_initialize(client);
+		else
+			cx25840_initialize(client, 0);
 		break;
 
 	case VIDIOC_INT_G_CHIP_IDENT:
-		*(enum v4l2_chip_ident *)arg =
-			V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+		*(enum v4l2_chip_ident *)arg = state->id;
 		break;
 
 	default:
@@ -870,6 +853,7 @@
 {
 	struct i2c_client *client;
 	struct cx25840_state *state;
+	enum v4l2_chip_ident id;
 	u16 device_id;
 
 	/* Check if the adapter supports the needed features
@@ -878,10 +862,11 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
 		return 0;
 
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
+	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+	if (state == 0)
 		return -ENOMEM;
 
+	client = &state->c;
 	client->addr = address;
 	client->adapter = adapter;
 	client->driver = &i2c_driver_cx25840;
@@ -893,10 +878,18 @@
 	device_id |= cx25840_read(client, 0x100);
 
 	/* The high byte of the device ID should be
-	 * 0x84 if chip is present */
-	if ((device_id & 0xff00) != 0x8400) {
+	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
+	if ((device_id & 0xff00) == 0x8300) {
+		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+		state->is_cx25836 = 1;
+	}
+	else if ((device_id & 0xff00) == 0x8400) {
+		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+		state->is_cx25836 = 0;
+	}
+	else {
 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
-		kfree(client);
+		kfree(state);
 		return 0;
 	}
 
@@ -905,21 +898,19 @@
 		    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
 		    address << 1, adapter->name);
 
-	state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
-		return -ENOMEM;
-	}
-
 	i2c_set_clientdata(client, state);
-	memset(state, 0, sizeof(struct cx25840_state));
 	state->vid_input = CX25840_COMPOSITE7;
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
 	state->pvr150_workaround = 0;
 	state->audmode = V4L2_TUNER_MODE_LANG1;
+	state->vbi_line_offset = 8;
+	state->id = id;
 
-	cx25840_initialize(client, 1);
+	if (state->is_cx25836)
+		cx25836_initialize(client);
+	else
+		cx25840_initialize(client, 1);
 
 	i2c_attach_client(client);
 
@@ -944,7 +935,6 @@
 	}
 
 	kfree(state);
-	kfree(client);
 
 	return 0;
 }
@@ -977,7 +967,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-static void log_status(struct i2c_client *client)
+static void log_video_status(struct i2c_client *client)
 {
 	static const char *const fmt_strs[] = {
 		"0x0",
@@ -989,9 +979,36 @@
 	};
 
 	struct cx25840_state *state = i2c_get_clientdata(client);
-	u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
 	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
 	u8 gen_stat1 = cx25840_read(client, 0x40d);
+	u8 gen_stat2 = cx25840_read(client, 0x40e);
+	int vid_input = state->vid_input;
+
+	v4l_info(client, "Video signal:              %spresent\n",
+		    (gen_stat2 & 0x20) ? "" : "not ");
+	v4l_info(client, "Detected format:           %s\n",
+		    fmt_strs[gen_stat1 & 0xf]);
+
+	v4l_info(client, "Specified standard:        %s\n",
+		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+	if (vid_input >= CX25840_COMPOSITE1 &&
+	    vid_input <= CX25840_COMPOSITE8) {
+		v4l_info(client, "Specified video input:     Composite %d\n",
+			vid_input - CX25840_COMPOSITE1 + 1);
+	} else {
+		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+	}
+
+	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	u8 download_ctl = cx25840_read(client, 0x803);
 	u8 mod_det_stat0 = cx25840_read(client, 0x804);
 	u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -999,15 +1016,9 @@
 	u8 pref_mode = cx25840_read(client, 0x809);
 	u8 afc0 = cx25840_read(client, 0x80b);
 	u8 mute_ctl = cx25840_read(client, 0x8d3);
-	int vid_input = state->vid_input;
 	int aud_input = state->aud_input;
 	char *p;
 
-	v4l_info(client, "Video signal:              %spresent\n",
-		    (microctrl_vidfmt & 0x10) ? "" : "not ");
-	v4l_info(client, "Detected format:           %s\n",
-		    fmt_strs[gen_stat1 & 0xf]);
-
 	switch (mod_det_stat0) {
 	case 0x00: p = "mono"; break;
 	case 0x01: p = "stereo"; break;
@@ -1107,25 +1118,12 @@
 		v4l_info(client, "Configured audio system:   %s\n", p);
 	}
 
-	v4l_info(client, "Specified standard:        %s\n",
-		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
-	if (vid_input >= CX25840_COMPOSITE1 &&
-	    vid_input <= CX25840_COMPOSITE8) {
-		v4l_info(client, "Specified video input:     Composite %d\n",
-			vid_input - CX25840_COMPOSITE1 + 1);
-	} else {
-		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
-			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
-	}
 	if (aud_input) {
 		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
 	} else {
 		v4l_info(client, "Specified audio input:     External\n");
 	}
 
-	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-
 	switch (pref_mode & 0xf) {
 	case 0: p = "mono/language A"; break;
 	case 1: p = "language B"; break;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 1736929..2804906 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -24,6 +24,8 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
+extern int cx25840_debug;
+
 /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
    present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
    certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
@@ -33,12 +35,16 @@
 #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
 
 struct cx25840_state {
+	struct i2c_client c;
 	int pvr150_workaround;
 	int radio;
 	enum cx25840_video_input vid_input;
 	enum cx25840_audio_input aud_input;
 	u32 audclk_freq;
 	int audmode;
+	int vbi_line_offset;
+	enum v4l2_chip_ident id;
+	int is_cx25836;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -47,7 +53,7 @@
 int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
 u8 cx25840_read(struct i2c_client *client, u16 addr);
 u32 cx25840_read4(struct i2c_client *client, u16 addr);
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
 v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 57feca2..6cc8bf2 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -84,67 +84,140 @@
 
 void cx25840_vbi_setup(struct i2c_client *client)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	v4l2_std_id std = cx25840_get_v4lstd(client);
+	int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
+	int luma_lpf,uv_lpf, comb;
+	u32 pll_int,pll_frac,pll_post;
 
+	/* datasheet startup, step 8d */
 	if (std & ~V4L2_STD_NTSC) {
-		/* datasheet startup, step 8d */
 		cx25840_write(client, 0x49f, 0x11);
-
-		cx25840_write(client, 0x470, 0x84);
-		cx25840_write(client, 0x471, 0x00);
-		cx25840_write(client, 0x472, 0x2d);
-		cx25840_write(client, 0x473, 0x5d);
-
-		cx25840_write(client, 0x474, 0x24);
-		cx25840_write(client, 0x475, 0x40);
-		cx25840_write(client, 0x476, 0x24);
-		cx25840_write(client, 0x477, 0x28);
-
-		cx25840_write(client, 0x478, 0x1f);
-		cx25840_write(client, 0x479, 0x02);
-
-		if (std & V4L2_STD_SECAM) {
-			cx25840_write(client, 0x47a, 0x80);
-			cx25840_write(client, 0x47b, 0x00);
-			cx25840_write(client, 0x47c, 0x5f);
-			cx25840_write(client, 0x47d, 0x42);
-		} else {
-			cx25840_write(client, 0x47a, 0x90);
-			cx25840_write(client, 0x47b, 0x20);
-			cx25840_write(client, 0x47c, 0x63);
-			cx25840_write(client, 0x47d, 0x82);
-		}
-
-		cx25840_write(client, 0x47e, 0x0a);
-		cx25840_write(client, 0x47f, 0x01);
 	} else {
-		/* datasheet startup, step 8d */
 		cx25840_write(client, 0x49f, 0x14);
+	}
 
-		cx25840_write(client, 0x470, 0x7a);
-		cx25840_write(client, 0x471, 0x00);
-		cx25840_write(client, 0x472, 0x2d);
-		cx25840_write(client, 0x473, 0x5b);
+	if (std & V4L2_STD_625_50) {
+		hblank=0x084;
+		hactive=0x2d0;
+		burst=0x5d;
+		vblank=0x024;
+		vactive=0x244;
+		vblank656=0x28;
+		src_decimation=0x21f;
 
-		cx25840_write(client, 0x474, 0x1a);
-		cx25840_write(client, 0x475, 0x70);
-		cx25840_write(client, 0x476, 0x1e);
-		cx25840_write(client, 0x477, 0x1e);
+		luma_lpf=2;
+		if (std & V4L2_STD_SECAM) {
+			uv_lpf=0;
+			comb=0;
+			sc=0x0a425f;
+		} else {
+			uv_lpf=1;
+			comb=0x20;
+			sc=0x0a8263;
+		}
+	} else {
+		hactive=720;
+		hblank=122;
+		vactive=487;
+		luma_lpf=1;
+		uv_lpf=1;
 
-		cx25840_write(client, 0x478, 0x1f);
-		cx25840_write(client, 0x479, 0x02);
-		cx25840_write(client, 0x47a, 0x50);
-		cx25840_write(client, 0x47b, 0x66);
+		src_decimation=0x21f;
+		if (std == V4L2_STD_PAL_M) {
+			vblank=20;
+			vblank656=24;
+			burst=0x61;
+			comb=0x20;
 
-		cx25840_write(client, 0x47c, 0x1f);
-		cx25840_write(client, 0x47d, 0x7c);
-		cx25840_write(client, 0x47e, 0x08);
+			sc=555452;
+		} else {
+			vblank=26;
+			vblank656=26;
+			burst=0x5b;
+			comb=0x66;
+			sc=556063;
+		}
+	}
+
+	/* DEBUG: Displays configured PLL frequency */
+	pll_int=cx25840_read(client, 0x108);
+	pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff;
+	pll_post=cx25840_read(client, 0x109);
+	v4l_dbg(1, cx25840_debug, client,
+				"PLL regs = int: %u, frac: %u, post: %u\n",
+				pll_int,pll_frac,pll_post);
+
+	if (pll_post) {
+		int fin, fsc;
+		int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L;
+
+		pll/=pll_post;
+		v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+						pll/1000000, pll%1000000);
+		v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+						pll/8000000, (pll/8)%1000000);
+
+		fin=((u64)src_decimation*pll)>>12;
+		v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = "
+						"%d.%06d MHz\n",
+						fin/1000000,fin%1000000);
+
+		fsc= (((u64)sc)*pll) >> 24L;
+		v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = "
+						"%d.%06d MHz\n",
+						fsc/1000000,fsc%1000000);
+
+		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+			" sc 0x%06x\n",
+			hblank, hactive, vblank, vactive, vblank656,
+			src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+	}
+
+	/* Sets horizontal blanking delay and active lines */
+	cx25840_write(client, 0x470, hblank);
+	cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4)));
+	cx25840_write(client, 0x472, hactive>>4);
+
+	/* Sets burst gate delay */
+	cx25840_write(client, 0x473, burst);
+
+	/* Sets vertical blanking delay and active duration */
+	cx25840_write(client, 0x474, vblank);
+	cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4)));
+	cx25840_write(client, 0x476, vactive>>4);
+	cx25840_write(client, 0x477, vblank656);
+
+	/* Sets src decimation rate */
+	cx25840_write(client, 0x478, 0xff&src_decimation);
+	cx25840_write(client, 0x479, 0xff&(src_decimation>>8));
+
+	/* Sets Luma and UV Low pass filters */
+	cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30));
+
+	/* Enables comb filters */
+	cx25840_write(client, 0x47b, comb);
+
+	/* Sets SC Step*/
+	cx25840_write(client, 0x47c, sc);
+	cx25840_write(client, 0x47d, 0xff&sc>>8);
+	cx25840_write(client, 0x47e, 0xff&sc>>16);
+
+	/* Sets VBI parameters */
+	if (std & V4L2_STD_625_50) {
+		cx25840_write(client, 0x47f, 0x01);
+		state->vbi_line_offset = 5;
+	} else {
 		cx25840_write(client, 0x47f, 0x00);
+		state->vbi_line_offset = 8;
 	}
 }
 
 int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	struct v4l2_format *fmt;
 	struct v4l2_sliced_vbi_format *svbi;
 
@@ -182,7 +255,7 @@
 
 	case VIDIOC_S_FMT:
 	{
-		int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+		int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
 		int vbi_offset = is_pal ? 1 : 0;
 		int i, x;
 		u8 lcr[24];
@@ -211,7 +284,7 @@
 		cx25840_vbi_setup(client);
 
 		/* Sliced VBI */
-		cx25840_write(client, 0x404, 0x36);	/* Ancillery data */
+		cx25840_write(client, 0x404, 0x32);	/* Ancillary data */
 		cx25840_write(client, 0x406, 0x13);
 		cx25840_write(client, 0x47f, vbi_offset);
 
@@ -248,8 +321,18 @@
 			}
 		}
 
-		for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
-			cx25840_write(client, i, lcr[6 + x]);
+		if (is_pal) {
+			for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+				cx25840_write(client, i, lcr[6 + x]);
+			}
+		}
+		else {
+			for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+				cx25840_write(client, i, lcr[9 + x]);
+			}
+			for (i = 0x431; i <= 0x434; i++) {
+				cx25840_write(client, i, 0);
+			}
 		}
 
 		cx25840_write(client, 0x43c, 0x16);
@@ -257,7 +340,7 @@
 		if (is_pal) {
 			cx25840_write(client, 0x474, 0x2a);
 		} else {
-			cx25840_write(client, 0x474, 0x1a + 6);
+			cx25840_write(client, 0x474, 0x22);
 		}
 		break;
 	}
@@ -278,7 +361,7 @@
 		id1 = p[-1];
 		id2 = p[0] & 0xf;
 		l = p[2] & 0x3f;
-		l += 5;
+		l += state->vbi_line_offset;
 		p += 4;
 
 		switch (id2) {
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 6302739..80e23ee 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -35,13 +35,25 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called cx88-alsa.
 
+config VIDEO_CX88_BLACKBIRD
+	tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
+	depends on VIDEO_CX88
+	select VIDEO_CX2341X
+	---help---
+	  This adds support for MPEG encoder cards based on the
+	  Blackbird reference design, using the Conexant 2388x
+	  and 23416 chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx88-blackbird.
+
 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.
+	  Conexant 2388x chip.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called cx88-dvb.
@@ -61,6 +73,7 @@
 	select DVB_LGDT330X
 	select DVB_NXT200X
 	select DVB_CX24123
+	select DVB_ISL6421
 	---help---
 	  This builds cx88-dvb with all currently supported frontend
 	  demodulators.  If you wish to tweak your configuration, and
@@ -139,6 +152,7 @@
 	default y
 	depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
 	select DVB_CX24123
+	select DVB_ISL6421
 	---help---
 	  This adds DVB-S support for cards based on the
 	  Connexant 2388x chip and the CX24123 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 0dcd09b..352b919 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -3,9 +3,10 @@
 cx8800-objs	:= cx88-video.o cx88-vbi.o
 cx8802-objs	:= cx88-mpeg.o
 
-obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
-obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o
 obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
+obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
 obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
 
 EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 320b3d9..2194cbe 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -4,7 +4,7 @@
  *  PCI function #1 of the cx2388x.
  *
  *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
- *    (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ *    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
  *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
  *    Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
  *
@@ -111,7 +111,7 @@
 
 MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Ricardo Cerqueira");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
 			"{{Conexant,23882},"
@@ -696,7 +696,6 @@
 	chip->irq = -1;
 	spin_lock_init(&chip->reg_lock);
 
-	cx88_reset(core);
 	chip->core = core;
 
 	/* get irq */
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e100d8e..78df666 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -30,9 +30,10 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
 
 #include "cx88.h"
-#include <media/v4l2-common.h>
 
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
 MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -53,7 +54,6 @@
 
 /* ------------------------------------------------------------------ */
 
-#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
 #define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
 
 /* defines below are from ivtv-driver.h */
@@ -63,8 +63,6 @@
 /* Firmware API commands */
 #define IVTV_API_STD_TIMEOUT 500
 
-#define BLACKBIRD_API_PING               0x80
-#define BLACKBIRD_API_BEGIN_CAPTURE      0x81
 enum blackbird_capture_type {
 	BLACKBIRD_MPEG_CAPTURE,
 	BLACKBIRD_RAW_CAPTURE,
@@ -78,205 +76,29 @@
 	BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
 	BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE  = 0x10
 };
-#define BLACKBIRD_API_END_CAPTURE        0x82
 enum blackbird_capture_end {
 	BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
 	BLACKBIRD_END_NOW, /* stop immediately, no irq */
 };
-#define BLACKBIRD_API_SET_AUDIO_ID       0x89
-#define BLACKBIRD_API_SET_VIDEO_ID       0x8B
-#define BLACKBIRD_API_SET_PCR_ID         0x8D
-#define BLACKBIRD_API_SET_FRAMERATE      0x8F
 enum blackbird_framerate {
 	BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
 	BLACKBIRD_FRAMERATE_PAL_25   /* PAL: 25fps */
 };
-#define BLACKBIRD_API_SET_RESOLUTION     0x91
-#define BLACKBIRD_API_SET_VIDEO_BITRATE  0x95
-enum blackbird_video_bitrate_type {
-	BLACKBIRD_VIDEO_VBR,
-	BLACKBIRD_VIDEO_CBR
-};
-#define BLACKBIRD_PEAK_RATE_DIVISOR 400
-enum blackbird_mux_rate {
-	BLACKBIRD_MUX_RATE_DEFAULT,
-	 /* dvd mux rate: multiply by 400 to get the actual rate */
-	BLACKBIRD_MUX_RATE_DVD = 25200
-};
-#define BLACKBIRD_API_SET_GOP_STRUCTURE  0x97
-#define BLACKBIRD_API_SET_ASPECT_RATIO   0x99
-enum blackbird_aspect_ratio {
-	BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
-	BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
-	BLACKBIRD_ASPECT_RATIO_4_3,
-	BLACKBIRD_ASPECT_RATIO_16_9,
-	BLACKBIRD_ASPECT_RATIO_221_100,
-	BLACKBIRD_ASPECT_RATIO_RESERVED
-};
-#define BLACKBIRD_API_SET_DNR_MODE       0x9B
-enum blackbird_dnr_bits {
-	BLACKBIRD_DNR_BITS_MANUAL,
-	BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
-	BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
-	BLACKBIRD_DNR_BITS_AUTO
-};
-enum blackbird_median_filter {
-	BLACKBIRD_MEDIAN_FILTER_DISABLED,
-	BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
-	BLACKBIRD_MEDIAN_FILTER_VERTICAL,
-	BLACKBIRD_MEDIAN_FILTER_HV,
-	BLACKBIRD_MEDIAN_FILTER_DIAGONAL
-};
-#define BLACKBIRD_API_SET_MANUAL_DNR     0x9D
-#define BLACKBIRD_API_SET_DNR_MEDIAN     0x9F
-#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
-enum blackbird_spatial_filter_luma {
-	BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
-	BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
-	BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
-	BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
-	BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
-};
-enum blackbird_spatial_filter_chroma {
-	BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
-	BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
-};
-#define BLACKBIRD_API_SET_3_2_PULLDOWN   0xB1
-enum blackbird_pulldown {
-	BLACKBIRD_3_2_PULLDOWN_DISABLED,
-	BLACKBIRD_3_2_PULLDOWN_ENABLED
-};
-#define BLACKBIRD_API_SET_VBI_LINE_NO    0xB7
-enum blackbird_vbi_line_bits {
-	BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
-	BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
-	BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
-};
-enum blackbird_vbi_line {
-	BLACKBIRD_VBI_LINE_DISABLED,
-	BLACKBIRD_VBI_LINE_ENABLED
-};
-enum blackbird_vbi_slicing {
-	BLACKBIRD_VBI_SLICING_NONE,
-	BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
-};
-#define BLACKBIRD_API_SET_STREAM_TYPE    0xB9
-enum blackbird_stream_type {
-	BLACKBIRD_STREAM_PROGRAM,
-	BLACKBIRD_STREAM_TRANSPORT,
-	BLACKBIRD_STREAM_MPEG1,
-	BLACKBIRD_STREAM_PES_AV,
-	BLACKBIRD_STREAM_UNKNOWN4,
-	BLACKBIRD_STREAM_PES_VIDEO,
-	BLACKBIRD_STREAM_UNKNOWN6,
-	BLACKBIRD_STREAM_PES_AUDIO,
-	BLACKBIRD_STREAM_UNKNOWN8,
-	BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
-	BLACKBIRD_STREAM_DVD,
-	BLACKBIRD_STREAM_VCD,
-	BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
-};
-#define BLACKBIRD_API_SET_OUTPUT_PORT    0xBB
 enum blackbird_stream_port {
 	BLACKBIRD_OUTPUT_PORT_MEMORY,
 	BLACKBIRD_OUTPUT_PORT_STREAMING,
 	BLACKBIRD_OUTPUT_PORT_SERIAL
 };
-#define BLACKBIRD_API_SET_AUDIO_PARAMS   0xBD
-enum blackbird_audio_bits_sample_rate {
-	BLACKBIRD_AUDIO_BITS_44100HZ,
-	BLACKBIRD_AUDIO_BITS_48000HZ,
-	BLACKBIRD_AUDIO_BITS_32000HZ,
-	BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
-};
-enum blackbird_audio_bits_encoding {
-	BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
-	BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
-};
-enum blackbird_audio_bits_bitrate_layer_1 {
-	BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_32  = 0x01 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_64  = 0x02 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_96  = 0x03 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
-};
-enum blackbird_audio_bits_bitrate_layer_2 {
-	BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_32  = 0x01 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_48  = 0x02 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_56  = 0x03 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_64  = 0x04 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_80  = 0x05 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_96  = 0x06 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
-	BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
-};
-enum blackbird_audio_bits_mode {
-	BLACKBIRD_AUDIO_BITS_STEREO,
-	BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
-	BLACKBIRD_AUDIO_BITS_DUAL         = 0x2 << 8,
-	BLACKBIRD_AUDIO_BITS_MONO         = 0x3 << 8,
-};
-enum blackbird_audio_bits_mode_extension {
-	BLACKBIRD_AUDIO_BITS_BOUND_4,
-	BLACKBIRD_AUDIO_BITS_BOUND_8  = 0x1 << 10,
-	BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
-	BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
-};
-enum blackbird_audio_bits_emphasis {
-	BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
-	BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15     = 0x1 << 12,
-	BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED  = 0x2 << 12,
-	BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
-};
-enum blackbird_audio_bits_crc {
-	BLACKBIRD_AUDIO_BITS_CRC_OFF,
-	BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
-};
-enum blackbird_audio_bits_copyright {
-	BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
-	BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
-};
-enum blackbird_audio_bits_original {
-	BLACKBIRD_AUDIO_BITS_COPY,
-	BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
-};
-#define BLACKBIRD_API_HALT               0xC3
-#define BLACKBIRD_API_GET_VERSION        0xC4
-#define BLACKBIRD_API_SET_GOP_CLOSURE    0xC5
-enum blackbird_gop_closure {
-	BLACKBIRD_GOP_CLOSURE_OFF,
-	BLACKBIRD_GOP_CLOSURE_ON,
-};
-#define BLACKBIRD_API_DATA_XFER_STATUS   0xC6
 enum blackbird_data_xfer_status {
 	BLACKBIRD_MORE_BUFFERS_FOLLOW,
 	BLACKBIRD_LAST_BUFFER,
 };
-#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
 enum blackbird_picture_mask {
 	BLACKBIRD_PICTURE_MASK_NONE,
 	BLACKBIRD_PICTURE_MASK_I_FRAMES,
 	BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
 	BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
 };
-#define BLACKBIRD_API_SET_VBI_PARAMS     0xC8
 enum blackbird_vbi_mode_bits {
 	BLACKBIRD_VBI_BITS_SLICED,
 	BLACKBIRD_VBI_BITS_RAW,
@@ -288,33 +110,23 @@
 	BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
 	BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
 };
-#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
 enum blackbird_dma_unit {
 	BLACKBIRD_DMA_BYTES,
 	BLACKBIRD_DMA_FRAMES,
 };
-#define BLACKBIRD_API_DMA_TRANSFER_INFO  0xCA
-#define BLACKBIRD_API_DMA_TRANSFER_STAT  0xCB
 enum blackbird_dma_transfer_status_bits {
 	BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
 	BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
 	BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
 };
-#define BLACKBIRD_API_SET_DMA2HOST_ADDR  0xCC
-#define BLACKBIRD_API_INIT_VIDEO_INPUT   0xCD
-#define BLACKBIRD_API_SET_FRAMESKIP      0xD0
-#define BLACKBIRD_API_PAUSE              0xD2
 enum blackbird_pause {
 	BLACKBIRD_PAUSE_ENCODING,
 	BLACKBIRD_RESUME_ENCODING,
 };
-#define BLACKBIRD_API_REFRESH_INPUT      0xD3
-#define BLACKBIRD_API_SET_COPYRIGHT      0xD4
 enum blackbird_copyright {
 	BLACKBIRD_COPYRIGHT_OFF,
 	BLACKBIRD_COPYRIGHT_ON,
 };
-#define BLACKBIRD_API_SET_NOTIFICATION   0xD5
 enum blackbird_notification_type {
 	BLACKBIRD_NOTIFICATION_REFRESH,
 };
@@ -325,7 +137,6 @@
 enum blackbird_notification_mailbox {
 	BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
 };
-#define BLACKBIRD_API_SET_CAPTURE_LINES  0xD6
 enum blackbird_field1_lines {
 	BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
 	BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
@@ -336,12 +147,10 @@
 	BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
 	BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
 };
-#define BLACKBIRD_API_SET_CUSTOM_DATA    0xD7
 enum blackbird_custom_data_type {
 	BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
 	BLACKBIRD_CUSTOM_PRIVATE_PACKET,
 };
-#define BLACKBIRD_API_MUTE_VIDEO         0xD9
 enum blackbird_mute {
 	BLACKBIRD_UNMUTE,
 	BLACKBIRD_MUTE,
@@ -356,7 +165,6 @@
 	BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
 	BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
 };
-#define BLACKBIRD_API_MUTE_AUDIO         0xDA
 
 /* Registers */
 #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
@@ -498,15 +306,12 @@
 
 /* ------------------------------------------------------------------ */
 
-/* We don't need to call the API often, so using just one mailbox will probably suffice */
-static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
-			     u32 inputcnt, u32 outputcnt, ...)
+static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
 {
+	struct cx8802_dev *dev = priv;
 	unsigned long timeout;
 	u32 value, flag, retval;
 	int i;
-	va_list args;
-	va_start(args, outputcnt);
 
 	dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
 
@@ -530,12 +335,11 @@
 	/* write command + args + fill remaining with zeros */
 	memory_write(dev->core, dev->mailbox + 1, command); /* command code */
 	memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
-	for (i = 0; i < inputcnt ; i++) {
-		value = va_arg(args, int);
-		memory_write(dev->core, dev->mailbox + 4 + i, value);
-		dprintk(1, "API Input %d = %d\n", i, value);
+	for (i = 0; i < in; i++) {
+		memory_write(dev->core, dev->mailbox + 4 + i, data[i]);
+		dprintk(1, "API Input %d = %d\n", i, data[i]);
 	}
-	for (; i < 16 ; i++)
+	for (; i < CX2341X_MBOX_MAX_DATA; i++)
 		memory_write(dev->core, dev->mailbox + 4 + i, 0);
 
 	flag |= 3; /* tell 'em we're done writing */
@@ -555,12 +359,10 @@
 	}
 
 	/* read output values */
-	for (i = 0; i < outputcnt ; i++) {
-		int *vptr = va_arg(args, int *);
-		memory_read(dev->core, dev->mailbox + 4 + i, vptr);
-		dprintk(1, "API Output %d = %d\n", i, *vptr);
+	for (i = 0; i < out; i++) {
+		memory_read(dev->core, dev->mailbox + 4 + i, data + i);
+		dprintk(1, "API Output %d = %d\n", i, data[i]);
 	}
-	va_end(args);
 
 	memory_read(dev->core, dev->mailbox + 2, &retval);
 	dprintk(1, "API result = %d\n",retval);
@@ -569,7 +371,29 @@
 	memory_write(dev->core, dev->mailbox, flag);
 	return retval;
 }
+/* ------------------------------------------------------------------ */
 
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+			     u32 inputcnt, u32 outputcnt, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list vargs;
+	int i, err;
+
+	va_start(vargs, outputcnt);
+
+	for (i = 0; i < inputcnt; i++) {
+		data[i] = va_arg(vargs, int);
+	}
+	err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);
+	for (i = 0; i < outputcnt; i++) {
+		int *vptr = va_arg(vargs, int *);
+		*vptr = data[i];
+	}
+	va_end(vargs);
+	return err;
+}
 
 static int blackbird_find_mailbox(struct cx8802_dev *dev)
 {
@@ -614,13 +438,13 @@
 	if (retval < 0)
 		dprintk(0, "Error with register_write\n");
 
-	retval = request_firmware(&firmware, BLACKBIRD_FIRM_ENC_FILENAME,
+	retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
 				  &dev->pci->dev);
 
 
 	if (retval != 0) {
 		dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
-			BLACKBIRD_FIRM_ENC_FILENAME);
+			CX2341X_FIRM_ENC_FILENAME);
 		dprintk(0, "Please fix your hotplug setup, the board will "
 			"not work without firmware loaded!\n");
 		return -1;
@@ -686,12 +510,19 @@
 *DB: "DirectBurn"
 */
 
-static struct blackbird_dnr default_dnr_params = {
-	.mode     = BLACKBIRD_DNR_BITS_MANUAL,
-	.type     = BLACKBIRD_MEDIAN_FILTER_DISABLED,
-	.spatial  = 0,
-	.temporal = 0
-};
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+	/* assign frame size */
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+				dev->height, dev->width);
+
+	dev->params.width = dev->width;
+	dev->params.height = dev->height;
+	dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+
+	cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
+}
+
 static struct v4l2_mpeg_compression default_mpeg_params = {
 	.st_type          = V4L2_MPEG_PS_2,
 	.st_bitrate       = {
@@ -712,7 +543,7 @@
 		.target   = 224,
 		.max      = 224
 	},
-	.au_sample_rate    = 44100,
+	.au_sample_rate    = 48000,
 	.au_pesid          = 0,
 	.vi_type           = V4L2_MPEG_VI_2,
 	.vi_aspect_ratio   = V4L2_MPEG_ASPECT_4_3,
@@ -723,524 +554,13 @@
 		.max       = 6000
 	},
 	.vi_frame_rate     = 25,
-	.vi_frames_per_gop = 15,
+	.vi_frames_per_gop = 12,
 	.vi_bframes_count  = 2,
 	.vi_pesid          = 0,
-	.closed_gops       = 0,
+	.closed_gops       = 1,
 	.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)
-{
-	struct v4l2_mpeg_compression *params = &dev->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;
-	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;
-		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 */
-	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, 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, 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;
-	}
-	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 */
-	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,
-				dev->dnr_params.mode,
-				dev->dnr_params.type
-			);
-
-	/* assign dnr filter props*/
-	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
-			);
-
-	/* 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)
 {
 	struct cx88_core *core = dev->core;
@@ -1248,7 +568,7 @@
 	int retval;
 
 	dprintk(1,"Initialize codec\n");
-	retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+	retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
 	if (retval < 0) {
 		/* ping was not successful, reset and upload firmware */
 		cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
@@ -1263,13 +583,13 @@
 		if (dev->mailbox < 0)
 			return -1;
 
-		retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+		retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
 		if (retval < 0) {
 			dprintk(0, "ERROR: Firmware ping failed!\n");
 			return -1;
 		}
 
-		retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
+		retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version);
 		if (retval < 0) {
 			dprintk(0, "ERROR: Firmware get encoder version failed!\n");
 			return -1;
@@ -1289,35 +609,35 @@
 	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
 	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
 	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
 			BLACKBIRD_FIELD1_SAA7115,
-			BLACKBIRD_FIELD1_SAA7115
+			BLACKBIRD_FIELD2_SAA7115
 		);
 
 	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
-	blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+	blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
 			BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
 	/* initialize the video input */
-	blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0);
+	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
 
 	msleep(1);
 
-	blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
+	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
 	msleep(1);
-	blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
+	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
 	msleep(1);
 
 	/* start capturing to the host interface */
-	/* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */
-	blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+	/* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
+	blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
 			BLACKBIRD_MPEG_CAPTURE,
 			BLACKBIRD_RAW_BITS_NONE
 		);
 	msleep(10);
 
-	blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
+	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
 	return 0;
 }
 
@@ -1485,27 +805,61 @@
 	{
 		struct v4l2_mpeg_compression *f = arg;
 
-		memcpy(f,&dev->params,sizeof(*f));
+		printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+				    "Replace with VIDIOC_G_EXT_CTRLS!");
+		memcpy(f,&default_mpeg_params,sizeof(*f));
 		return 0;
 	}
 	case VIDIOC_S_MPEGCOMP:
+		printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+				    "Replace with VIDIOC_S_EXT_CTRLS!");
+		return 0;
+	case VIDIOC_G_EXT_CTRLS:
 	{
-		struct v4l2_mpeg_compression *f = arg;
+		struct v4l2_ext_controls *f = arg;
 
-		blackbird_set_params(dev, f);
+		if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		return cx2341x_ext_ctrls(&dev->params, f, cmd);
+	}
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *f = arg;
+		struct cx2341x_mpeg_params p;
+		int err;
+
+		if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		p = dev->params;
+		err = cx2341x_ext_ctrls(&p, f, cmd);
+		if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+			err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+			dev->params = p;
+		}
+		return err;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+				  BLACKBIRD_END_NOW,
+				  BLACKBIRD_MPEG_CAPTURE,
+				  BLACKBIRD_RAW_BITS_NONE);
+
+		cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+
+		blackbird_initialize_codec(dev);
+		cx88_set_scale(dev->core, dev->width, dev->height,
+			       fh->mpegq.field);
 		return 0;
 	}
 
 	default:
-		return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
+		return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
 	}
 	return 0;
 }
 
-int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
-			unsigned int cmd, void *arg);
-unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
-
 static unsigned int mpeg_translate_ioctl(unsigned int cmd)
 {
 	return cmd;
@@ -1514,8 +868,8 @@
 static int mpeg_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
-	cmd = cx88_ioctl_translator( cmd );
-	return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
+	cmd = mpeg_translate_ioctl( cmd );
+	return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
 }
 
 static int mpeg_open(struct inode *inode, struct file *file)
@@ -1562,13 +916,14 @@
 {
 	struct cx8802_fh  *fh  = file->private_data;
 
-	/* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
-	blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+	/* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
 			BLACKBIRD_END_NOW,
 			BLACKBIRD_MPEG_CAPTURE,
 			BLACKBIRD_RAW_BITS_NONE
 		);
 
+	cx8802_cancel_buffers(fh->dev);
 	/* stop mpeg capture */
 	if (fh->mpegq.streaming)
 		videobuf_streamoff(&fh->mpegq);
@@ -1683,19 +1038,13 @@
 	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));
+	cx2341x_fill_defaults(&dev->params);
+	dev->params.port = CX2341X_PORT_STREAMING;
 
-	if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
-
-		if (core->tuner_formats & V4L2_STD_525_60) {
-			dev->height = 480;
-			dev->params.vi_frame_rate = 30;
-		} else {
-			dev->height = 576;
-			dev->params.vi_frame_rate = 25;
-		}
-
+	if (core->tvnorm->id & V4L2_STD_525_60) {
+		dev->height = 480;
+	} else {
+		dev->height = 576;
 	}
 
 	err = cx8802_init_common(dev);
@@ -1766,8 +1115,6 @@
 	printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
 	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
 #endif
-	cx88_ioctl_hook = mpeg_do_ioctl;
-	cx88_ioctl_translator = mpeg_translate_ioctl;
 	return pci_register_driver(&blackbird_pci_driver);
 }
 
@@ -1779,11 +1126,6 @@
 module_init(blackbird_init);
 module_exit(blackbird_fini);
 
-EXPORT_SYMBOL(cx88_ioctl_hook);
-EXPORT_SYMBOL(cx88_ioctl_translator);
-EXPORT_SYMBOL(blackbird_set_params);
-EXPORT_SYMBOL(blackbird_set_dnr_params);
-
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index f80154b..f9d68f2 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -114,7 +114,7 @@
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xff10,
-		 },
+		},
 	},
 	[CX88_BOARD_ATI_WONDER_PRO] = {
 		.name           = "ATI TV Wonder Pro",
@@ -267,7 +267,7 @@
 			.gpio1  = 0x00007004,
 			.gpio2  = 0x0035d700,
 			.gpio3  = 0x02000000,
-		 },
+		},
 	},
 	[CX88_BOARD_LEADTEK_PVR2000] = {
 		// gpio values for PAL version from regspy by DScaler
@@ -413,7 +413,7 @@
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000027df,
-		 },{
+		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000027df,
@@ -536,7 +536,7 @@
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000027df,
-		 },{
+		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000027df,
@@ -759,7 +759,7 @@
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
 		.name           = "DViCO FusionHDTV 5 Gold",
-		.tuner_type     = TUNER_LG_TDVS_H062F,
+		.tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
@@ -1050,11 +1050,7 @@
 		.dvb            = 1,
 	},
 	[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
-		/* FIXME: Standard video using the cx88 broadcast decoder is
-		 * working, but blackbird isn't working yet, audio is only
-		 * working correctly for television mode. S-Video and Composite
-		 * are working for video-only, so I have them disabled for now.
-		 */
+		/* FIXME: Audio not working for s-video / composite inputs. */
 		.name           = "KWorld HardwareMpegTV XPert",
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
 		.radio_type     = UNSET,
@@ -1065,12 +1061,21 @@
 			.vmux   = 0,
 			.gpio0  = 0x3de2,
 			.gpio2  = 0x00ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x3de6,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x3de6,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x3de6,
 			.gpio2  = 0x00ff,
 		},
+		.blackbird      = 1,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
 		.name           = "DViCO FusionHDTV DVB-T Hybrid",
@@ -1093,7 +1098,102 @@
 		}},
 		.dvb            = 1,
 	},
-
+	[CX88_BOARD_PCHDTV_HD5500] = {
+		.name           = "pcHDTV HD5500 HDTV",
+		.tuner_type     = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.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,
+		}},
+		.dvb            = 1,
+	},
+	[CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+		/* FIXME: tested TV input only, disabled composite,
+		   svideo and radio until they can be tested also. */
+		.name           = "Kworld MCE 200 Deluxe",
+		.tuner_type     = TUNER_TENA_9533_DI,
+		.radio_type     = UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x0000BDE6
+		}},
+		.blackbird = 1,
+	},
+	[CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+		/* FIXME: SVideo, Composite and FM inputs are untested */
+		.name           = "PixelView PlayTV P7000",
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+				  TDA9887_PORT2_ACTIVE,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x5da6,
+		}},
+		.blackbird = 1,
+	},
+	[CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+		.name           = "NPG Tech Real TV FM Top 10",
+		.tuner_type     = TUNER_TNF_5335MF, /* Actually a TNF9535 */
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0	= 0x0788,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0	= 0x078b,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0	= 0x078b,
+		}},
+		.radio = {
+			 .type  = CX88_RADIO,
+			 .gpio0 = 0x074a,
+		},
+	},
+	[CX88_BOARD_WINFAST_DTV2000H] = {
+		/* video inputs and radio still in testing */
+		.name           = "WinFast DTV2000 H",
+		.tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x00017304,
+			.gpio1  = 0x00008203,
+			.gpio2  = 0x00017304,
+			.gpio3  = 0x02000000,
+		}},
+		.dvb            = 1,
+	},
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -1311,6 +1411,34 @@
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb44,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+	},{
+		.subvendor = 0x7063,
+		.subdevice = 0x5500,
+		.card      = CX88_BOARD_PCHDTV_HD5500,
+	},{
+		.subvendor = 0x17de,
+		.subdevice = 0x0841,
+		.card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
+	},{
+		.subvendor = 0x1822,
+		.subdevice = 0x0019,
+		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+	},{
+		.subvendor = 0x1554,
+		.subdevice = 0x4813,
+		.card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
+	},{
+		.subvendor = 0x14f1,
+		.subdevice = 0x0842,
+		.card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
+	},{
+		.subvendor = 0x107d,
+		.subdevice = 0x665e,
+		.card      = CX88_BOARD_WINFAST_DTV2000H,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
+		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
 	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1572,11 +1700,6 @@
 /* ------------------------------------------------------------------ */
 
 EXPORT_SYMBOL(cx88_boards);
-EXPORT_SYMBOL(cx88_bcount);
-EXPORT_SYMBOL(cx88_subids);
-EXPORT_SYMBOL(cx88_idcount);
-EXPORT_SYMBOL(cx88_card_list);
-EXPORT_SYMBOL(cx88_card_setup);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index e1092d5..26f4c0f 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -677,7 +677,7 @@
 
 static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
 {
-	return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+	return (norm->id & V4L2_STD_625_50) ? 511 : 400;
 }
 
 int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -932,9 +932,9 @@
 		htotal, cx_read(MO_HTOTAL), (u32)tmp64);
 	cx_write(MO_HTOTAL, htotal);
 
-	// vbi stuff
-	cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */
-				 norm_vbipack(norm)));
+	// vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+	// the effective vbi offset ~244 samples, the same as the Bt8x8
+	cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
 
 	// this is needed as well to set all tvnorm parameter
 	cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
@@ -1181,8 +1181,6 @@
 EXPORT_SYMBOL(cx88_vdev_init);
 EXPORT_SYMBOL(cx88_core_get);
 EXPORT_SYMBOL(cx88_core_put);
-EXPORT_SYMBOL(cx88_start_audio_dma);
-EXPORT_SYMBOL(cx88_stop_audio_dma);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 3619a44..dce1fed 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -51,6 +51,7 @@
 #endif
 #ifdef HAVE_LGDT330X
 # include "lgdt330x.h"
+# include "lg_h06xf.h"
 #endif
 #ifdef HAVE_NXT200X
 # include "nxt200x.h"
@@ -58,6 +59,7 @@
 #ifdef HAVE_CX24123
 # include "cx24123.h"
 #endif
+#include "isl6421.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -113,21 +115,6 @@
 
 /* ------------------------------------------------------------------ */
 
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
-static int zarlink_pll_set(struct dvb_frontend *fe,
-			      struct dvb_frontend_parameters *params,
-			      u8 *pllbuf)
-{
-	struct cx8802_dev *dev = fe->dvb->priv;
-
-	pllbuf[0] = dev->core->pll_addr << 1;
-	dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
-			  params->frequency,
-			  params->u.ofdm.bandwidth);
-	return 0;
-}
-#endif
-
 #ifdef HAVE_MT352
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
@@ -196,19 +183,16 @@
 static struct mt352_config dvico_fusionhdtv = {
 	.demod_address = 0x0F,
 	.demod_init    = dvico_fusionhdtv_demod_init,
-	.pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dntv_live_dvbt_config = {
 	.demod_address = 0x0f,
 	.demod_init    = dntv_live_dvbt_demod_init,
-	.pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dvico_fusionhdtv_dual = {
 	.demod_address = 0x0F,
 	.demod_init    = dvico_dual_demod_init,
-	.pll_set       = zarlink_pll_set,
 };
 
 #ifdef HAVE_VP3054_I2C
@@ -246,6 +230,8 @@
 		  .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
 	int err;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
 		if (err < 0)
 			return err;
@@ -256,14 +242,14 @@
 	return 0;
 }
 
-static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
-				      struct dvb_frontend_parameters* params,
-				      u8* pllbuf)
+static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
+					       struct dvb_frontend_parameters* params)
 {
 	struct cx8802_dev *dev= fe->dvb->priv;
+	u8 buf[4];
 	struct i2c_msg msg =
 		{ .addr = dev->core->pll_addr, .flags = 0,
-		  .buf = pllbuf+1, .len = 4 };
+		  .buf = buf, .len = 4 };
 	int err;
 
 	/* Switch PLL to DVB mode */
@@ -272,14 +258,16 @@
 		return err;
 
 	/* Tune PLL */
-	pllbuf[0] = dev->core->pll_addr << 1;
-	dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+	dvb_pll_configure(dev->core->pll_desc, buf,
 			  params->frequency,
 			  params->u.ofdm.bandwidth);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+
 		printk(KERN_WARNING "cx88-dvb: %s error "
 			   "(addr %02x <- %02x, err = %i)\n",
-			   __FUNCTION__, pllbuf[0], pllbuf[1], err);
+			   __FUNCTION__, dev->core->pll_addr, buf[0], err);
 		if (err < 0)
 			return err;
 		else
@@ -293,27 +281,27 @@
 	.demod_address = 0x0f,
 	.no_tuner      = 1,
 	.demod_init    = dntv_live_dvbt_pro_demod_init,
-	.pll_set       = dntv_live_dvbt_pro_pll_set,
 };
 #endif
 #endif
 
 #ifdef HAVE_ZL10353
-static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
-				 struct dvb_frontend_parameters *params,
-				 u8 *pllbuf)
+static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
+					 struct dvb_frontend_parameters *params)
 {
+	u8 pllbuf[4];
 	struct cx8802_dev *dev= fe->dvb->priv;
 	struct i2c_msg msg =
 		{ .addr = dev->core->pll_addr, .flags = 0,
-		  .buf = pllbuf + 1, .len = 4 };
+		  .buf = pllbuf, .len = 4 };
 	int err;
 
-	pllbuf[0] = dev->core->pll_addr << 1;
-	dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+	dvb_pll_configure(dev->core->pll_desc, pllbuf,
 			  params->frequency,
 			  params->u.ofdm.bandwidth);
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
 		printk(KERN_WARNING "cx88-dvb: %s error "
 			   "(addr %02x <- %02x, err = %i)\n",
@@ -329,12 +317,11 @@
 
 static struct zl10353_config dvico_fusionhdtv_hybrid = {
 	.demod_address = 0x0F,
-	.pll_set       = dvico_hybrid_tune_pll,
+	.no_tuner      = 1,
 };
 
 static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
 	.demod_address = 0x0F,
-	.pll_set       = zarlink_pll_set,
 };
 #endif
 
@@ -342,21 +329,15 @@
 static struct cx22702_config connexant_refboard_config = {
 	.demod_address = 0x43,
 	.output_mode   = CX22702_SERIAL_OUTPUT,
-	.pll_address   = 0x60,
-	.pll_desc      = &dvb_pll_thomson_dtt7579,
 };
 
 static struct cx22702_config hauppauge_novat_config = {
 	.demod_address = 0x43,
 	.output_mode   = CX22702_SERIAL_OUTPUT,
-	.pll_address   = 0x61,
-	.pll_desc      = &dvb_pll_thomson_dtt759x,
 };
 static struct cx22702_config hauppauge_hvr1100_config = {
 	.demod_address = 0x63,
 	.output_mode   = CX22702_SERIAL_OUTPUT,
-	.pll_address   = 0x61,
-	.pll_desc      = &dvb_pll_fmd1216me,
 };
 #endif
 
@@ -371,15 +352,13 @@
 
 static struct or51132_config pchdtv_hd3000 = {
 	.demod_address    = 0x15,
-	.pll_address      = 0x61,
-	.pll_desc         = &dvb_pll_thomson_dtt761x,
 	.set_ts_params    = or51132_set_ts_param,
 };
 #endif
 
 #ifdef HAVE_LGDT330X
-static int lgdt330x_pll_set(struct dvb_frontend* fe,
-			    struct dvb_frontend_parameters* params)
+static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
+				     struct dvb_frontend_parameters* params)
 {
 	/* FIXME make this routine use the tuner-simple code.
 	 * It could probably be shared with a number of ATSC
@@ -392,12 +371,12 @@
 		{ .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
 	int err;
 
-	/* Put the analog decoder in standby to keep it quiet */
-	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
 	dvb_pll_configure(core->pll_desc, 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 (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
 		printk(KERN_WARNING "cx88-dvb: %s error "
 			   "(addr %02x <- %02x, err = %i)\n",
@@ -407,16 +386,21 @@
 		else
 			return -EREMOTEIO;
 	}
-	if (core->tuner_type == TUNER_LG_TDVS_H062F) {
-		/* Set the Auxiliary Byte. */
-		buf[2] &= ~0x20;
-		buf[2] |= 0x18;
-		buf[3] = 0x50;
-		i2c_transfer(&core->i2c_adap, &msg, 1);
-	}
 	return 0;
 }
 
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
+				     struct dvb_frontend_parameters* params)
+{
+	struct cx8802_dev *dev= fe->dvb->priv;
+	struct cx88_core *core = dev->core;
+
+	/* Put the analog decoder in standby to keep it quiet */
+	cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
+	return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
+}
+
 static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
 {
 	struct cx8802_dev *dev= fe->dvb->priv;
@@ -444,7 +428,6 @@
 	.demod_address    = 0x0e,
 	.demod_chip       = LGDT3302,
 	.serial_mpeg      = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
-	.pll_set          = lgdt330x_pll_set,
 	.set_ts_params    = lgdt330x_set_ts_param,
 };
 
@@ -452,7 +435,13 @@
 	.demod_address    = 0x0e,
 	.demod_chip       = LGDT3303,
 	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
-	.pll_set          = lgdt330x_pll_set,
+	.set_ts_params    = lgdt330x_set_ts_param,
+};
+
+static struct lgdt330x_config pchdtv_hd5500 = {
+	.demod_address    = 0x59,
+	.demod_chip       = LGDT3303,
+	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
 	.set_ts_params    = lgdt330x_set_ts_param,
 };
 #endif
@@ -477,8 +466,6 @@
 
 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,
 };
@@ -493,28 +480,30 @@
 	return 0;
 }
 
-static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
 	struct cx8802_dev *dev= fe->dvb->priv;
 	struct cx88_core *core = dev->core;
 
-	if (on)
-		cx_write(MO_GP0_IO, 0x000006f9);
-	else
+	if (voltage == SEC_VOLTAGE_OFF) {
 		cx_write(MO_GP0_IO, 0x000006fB);
+	} else {
+		cx_write(MO_GP0_IO, 0x000006f9);
+	}
+
+	if (core->prev_set_voltage)
+		return core->prev_set_voltage(fe, voltage);
+	return 0;
 }
 
 static struct cx24123_config hauppauge_novas_config = {
 	.demod_address		= 0x55,
-	.use_isl6421		= 1,
 	.set_ts_params		= cx24123_set_ts_param,
 };
 
 static struct cx24123_config kworld_dvbs_100_config = {
 	.demod_address		= 0x15,
-	.use_isl6421		= 0,
 	.set_ts_params		= cx24123_set_ts_param,
-	.enable_lnb_voltage	= cx24123_enable_lnb_voltage,
 };
 #endif
 
@@ -530,6 +519,11 @@
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
 		dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
 						   &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt759x);
+		}
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 	case CX88_BOARD_CONEXANT_DVB_T1:
@@ -537,44 +531,92 @@
 	case CX88_BOARD_WINFAST_DTV1000:
 		dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
 						   &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x60,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt7579);
+		}
 		break;
+	case CX88_BOARD_WINFAST_DTV2000H:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
 		dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
 						   &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_fmd1216me);
+		}
 		break;
 #endif
 #if defined(HAVE_MT352) || defined(HAVE_ZL10353)
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-		dev->core->pll_addr = 0x60;
-		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
 #ifdef HAVE_MT352
 		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
 						 &dev->core->i2c_adap);
-		if (dev->dvb.frontend != NULL)
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x60,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt7579);
 			break;
+		}
 #endif
 #ifdef HAVE_ZL10353
 		/* ZL10353 replaces MT352 on later cards */
 		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
 						   &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x60,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt7579);
+		}
+#endif
+		break;
+	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+#ifdef HAVE_MT352
+		/* The tin box says DEE1601, but it seems to be DTT7579
+		 * compatible, with a slightly different MT352 AGC gain. */
+		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+						 &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt7579);
+			break;
+		}
+#endif
+#ifdef HAVE_ZL10353
+		/* ZL10353 replaces MT352 on later cards */
+		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+						   &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt7579);
+		}
 #endif
 		break;
 #endif /* HAVE_MT352 || HAVE_ZL10353 */
 #ifdef HAVE_MT352
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-		dev->core->pll_addr = 0x61;
-		dev->core->pll_desc = &dvb_pll_lg_z201;
 		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
 						 &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_lg_z201);
+		}
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
-		dev->core->pll_addr = 0x61;
-		dev->core->pll_desc = &dvb_pll_unknown_1;
 		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
 						 &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_unknown_1);
+		}
 		break;
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 #ifdef HAVE_VP3054_I2C
@@ -582,18 +624,13 @@
 		dev->core->pll_desc = &dvb_pll_fmd1216me;
 		dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
 			&((struct vp3054_i2c_state *)dev->card_priv)->adap);
+		if (dev->dvb.frontend != NULL) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+		}
 #else
 		printk("%s: built without vp3054 support\n", dev->core->name);
 #endif
 		break;
-	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
-		/* The tin box says DEE1601, but it seems to be DTT7579
-		 * compatible, with a slightly different MT352 AGC gain. */
-		dev->core->pll_addr = 0x61;
-		dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
-		dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
-						 &dev->core->i2c_adap);
-		break;
 #endif
 #ifdef HAVE_ZL10353
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -601,12 +638,20 @@
 		dev->core->pll_desc = &dvb_pll_thomson_fe6600;
 		dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
 						   &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+		}
 		break;
 #endif
 #ifdef HAVE_OR51132
 	case CX88_BOARD_PCHDTV_HD3000:
 		dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
 						 &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_thomson_dtt761x);
+		}
 		break;
 #endif
 #ifdef HAVE_LGDT330X
@@ -627,6 +672,9 @@
 		dev->core->pll_desc = &dvb_pll_microtune_4042;
 		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
 						    &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+		}
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
@@ -643,6 +691,9 @@
 		dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
 		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
 						    &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+		}
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -655,10 +706,28 @@
 		mdelay(100);
 		cx_set(MO_GP0_IO, 1);
 		mdelay(200);
-		dev->core->pll_addr = 0x61;
-		dev->core->pll_desc = &dvb_pll_tdvs_tua6034;
 		dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
 						    &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+		}
+		}
+		break;
+	case CX88_BOARD_PCHDTV_HD5500:
+		dev->ts_gen_cntrl = 0x08;
+		{
+		/* Do a hardware reset of chip before using it. */
+		struct cx88_core *core = dev->core;
+
+		cx_clear(MO_GP0_IO, 1);
+		mdelay(100);
+		cx_set(MO_GP0_IO, 1);
+		mdelay(200);
+		dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
+						    &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+		}
 		}
 		break;
 #endif
@@ -666,6 +735,11 @@
 	case CX88_BOARD_ATI_HDTVWONDER:
 		dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
 						 &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61,
+				       &dev->core->i2c_adap,
+				       &dvb_pll_tuv1236d);
+		}
 		break;
 #endif
 #ifdef HAVE_CX24123
@@ -673,10 +747,18 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 		dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
 			&dev->core->i2c_adap);
+		if (dev->dvb.frontend) {
+			isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
+				       0x08, 0x00, 0x00);
+		}
 		break;
 	case CX88_BOARD_KWORLD_DVBS_100:
 		dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
 			&dev->core->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+			dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+		}
 		break;
 #endif
 	default:
@@ -690,15 +772,15 @@
 	}
 
 	if (dev->core->pll_desc) {
-		dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
-		dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+		dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
+		dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
 	}
 
 	/* 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);
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
 }
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index f720901..7066380 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -138,13 +138,13 @@
 		return;
 
 	if (core->dvbdev) {
-		if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
-			core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+		if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+			core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
 
 		i2c_clients_command(&core->i2c_adap, cmd, arg);
 
-		if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
-			core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+		if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+			core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
 	} else
 		i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
@@ -234,7 +234,6 @@
 /* ----------------------------------------------------------------------- */
 
 EXPORT_SYMBOL(cx88_call_i2c_clients);
-EXPORT_SYMBOL(cx88_i2c_init);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 78a63b7..72b630a 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -70,14 +70,33 @@
 static void cx88_ir_handle_key(struct cx88_IR *ir)
 {
 	struct cx88_core *core = ir->core;
-	u32 gpio, data;
+	u32 gpio, data, auxgpio;
 
 	/* read gpio value */
 	gpio = cx_read(ir->gpio_addr);
+	if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+		/* This board apparently uses a combination of 2 GPIO
+		   to represent the keys. Additionally, the second GPIO
+		   can be used for parity.
+
+		   Example:
+
+		   for key "5"
+			gpio = 0x758, auxgpio = 0xe5 or 0xf5
+		   for key "Power"
+			gpio = 0x758, auxgpio = 0xed or 0xfd
+		 */
+
+		auxgpio = cx_read(MO_GP1_IO);
+		/* Take out the parity part */
+		gpio+=(gpio & 0x7fd) + (auxgpio & 0xef);
+	} else
+		auxgpio = gpio;
+
 	if (ir->polling) {
-		if (ir->last_gpio == gpio)
+		if (ir->last_gpio == auxgpio)
 			return;
-		ir->last_gpio = gpio;
+		ir->last_gpio = auxgpio;
 	}
 
 	/* extract data */
@@ -172,12 +191,13 @@
 		ir_type = IR_TYPE_RC5;
 		ir->sampling = 1;
 		break;
+	case CX88_BOARD_WINFAST_DTV2000H:
 	case CX88_BOARD_WINFAST2000XP_EXPERT:
 		ir_codes = ir_codes_winfast;
 		ir->gpio_addr = MO_GP0_IO;
 		ir->mask_keycode = 0x8f8;
 		ir->mask_keyup = 0x100;
-		ir->polling = 1; /* ms */
+		ir->polling = 50; /* ms */
 		break;
 	case CX88_BOARD_IODATA_GVBCTV7E:
 		ir_codes = ir_codes_iodata_bctv7e;
@@ -228,6 +248,12 @@
 		ir_type = IR_TYPE_PD;
 		ir->sampling = 0xff00; /* address */
 		break;
+	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+		ir_codes = ir_codes_npgtech;
+		ir->gpio_addr = MO_GP0_IO;
+		ir->mask_keycode = 0xfa;
+		ir->polling = 50; /* ms */
+		break;
 	}
 
 	if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 7d16888..a9d7795 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 w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+	dprintk(1, "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],
@@ -76,6 +76,7 @@
 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
 		case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+		case CX88_BOARD_PCHDTV_HD5500:
 			cx_write(TS_SOP_STAT, 1<<13);
 			break;
 		case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -109,7 +110,7 @@
 	q->count = 1;
 
 	/* enable irqs */
-	dprintk( 0, "setting the interrupt mask\n" );
+	dprintk( 1, "setting the interrupt mask\n" );
 	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
 	cx_set(MO_TS_INTMSK,  0x1f0011);
 
@@ -122,7 +123,7 @@
 static int cx8802_stop_dma(struct cx8802_dev *dev)
 {
 	struct cx88_core *core = dev->core;
-	dprintk( 0, "cx8802_stop_dma\n" );
+	dprintk( 1, "cx8802_stop_dma\n" );
 
 	/* stop dma */
 	cx_clear(MO_TS_DMACNTRL, 0x11);
@@ -142,10 +143,43 @@
 	struct cx88_buffer *buf;
 	struct list_head *item;
 
-	dprintk( 0, "cx8802_restart_queue\n" );
+       dprintk( 1, "cx8802_restart_queue\n" );
 	if (list_empty(&q->active))
 	{
-		dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
+	       struct cx88_buffer *prev;
+	       prev = NULL;
+
+	       dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+	       for (;;) {
+		       if (list_empty(&q->queued))
+			       return 0;
+		       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);
+			       cx8802_start_dma(dev, q, buf);
+			       buf->vb.state = STATE_ACTIVE;
+			       buf->count    = q->count++;
+			       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+			       dprintk(1,"[%p/%d] restart_queue - first active\n",
+				       buf,buf->vb.i);
+
+		       } else if (prev->vb.width  == buf->vb.width  &&
+				  prev->vb.height == buf->vb.height &&
+				  prev->fmt       == buf->fmt) {
+			       list_del(&buf->vb.queue);
+			       list_add_tail(&buf->vb.queue,&q->active);
+			       buf->vb.state = STATE_ACTIVE;
+			       buf->count    = q->count++;
+			       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			       dprintk(1,"[%p/%d] restart_queue - move to active\n",
+				       buf,buf->vb.i);
+		       } else {
+			       return 0;
+		       }
+		       prev = buf;
+	       }
 		return 0;
 	}
 
@@ -204,13 +238,13 @@
 	buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
 
 	if (list_empty(&cx88q->active)) {
-		dprintk( 0, "queue is empty - first active\n" );
+		dprintk( 1, "queue is empty - first active\n" );
 		list_add_tail(&buf->vb.queue,&cx88q->active);
 		cx8802_start_dma(dev, cx88q, buf);
 		buf->vb.state = STATE_ACTIVE;
 		buf->count    = cx88q->count++;
 		mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
-		dprintk(0,"[%p/%d] %s - first active\n",
+		dprintk(1,"[%p/%d] %s - first active\n",
 			buf, buf->vb.i, __FUNCTION__);
 
 	} else {
@@ -244,7 +278,7 @@
 	}
 	if (restart)
 	{
-		dprintk(0, "restarting queue\n" );
+		dprintk(1, "restarting queue\n" );
 		cx8802_restart_queue(dev,q);
 	}
 	spin_unlock_irqrestore(&dev->slock,flags);
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 641a0c5..5785c34 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -52,6 +52,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
+#include <linux/config.h>
 #include <linux/kthread.h>
 
 #include "cx88.h"
@@ -137,21 +138,28 @@
 {
 	u32 volume;
 
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
 	/* restart dma; This avoids buzz in NICAM and is good in others  */
 	cx88_stop_audio_dma(core);
 #endif
 	cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
 	cx88_start_audio_dma(core);
 #endif
 
 	if (cx88_boards[core->board].blackbird) {
 		/* sets sound input from external adc */
-		if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+		switch (core->board) {
+		case CX88_BOARD_HAUPPAUGE_ROSLYN:
+		case CX88_BOARD_KWORLD_MCE200_DELUXE:
+		case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
+		case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
+		case CX88_BOARD_ASUS_PVR_416:
 			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
-		else
+			break;
+		default:
 			cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+		}
 
 		cx_write(AUD_I2SINPUTCNTL, 4);
 		cx_write(AUD_BAUDRATE, 1);
@@ -718,7 +726,7 @@
 
 /* ----------------------------------------------------------- */
 
-int cx88_detect_nicam(struct cx88_core *core)
+static int cx88_detect_nicam(struct cx88_core *core)
 {
 	int i, j = 0;
 
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 846faad..aa2a697 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -34,8 +34,8 @@
 	if (dev->core->tvnorm->id & V4L2_STD_525_60) {
 		/* ntsc */
 		f->fmt.vbi.sampling_rate = 28636363;
-		f->fmt.vbi.start[0] = 10 -1;
-		f->fmt.vbi.start[1] = 273 -1;
+		f->fmt.vbi.start[0] = 10;
+		f->fmt.vbi.start[1] = 273;
 
 	} else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
 		/* pal */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 694d1d8..dcda529 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -494,8 +494,7 @@
 			return 0;
 		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);
+			list_move_tail(&buf->vb.queue, &q->active);
 			start_video_dma(dev, q, buf);
 			buf->vb.state = STATE_ACTIVE;
 			buf->count    = q->count++;
@@ -506,8 +505,7 @@
 		} else if (prev->vb.width  == buf->vb.width  &&
 			   prev->vb.height == buf->vb.height &&
 			   prev->fmt       == buf->fmt) {
-			list_del(&buf->vb.queue);
-			list_add_tail(&buf->vb.queue,&q->active);
+			list_move_tail(&buf->vb.queue, &q->active);
 			buf->vb.state = STATE_ACTIVE;
 			buf->count    = q->count++;
 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 326a25f..9a9a0fc 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -25,9 +25,11 @@
 #include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/video-buf.h>
+#include <media/cx2341x.h>
 #include <media/video-buf-dvb.h>
 
 #include "btcx-risc.h"
@@ -35,7 +37,7 @@
 
 #include <linux/version.h>
 #include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
+#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
 
 #ifndef TRUE
 # define TRUE (1==1)
@@ -189,6 +191,11 @@
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
 #define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500           47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE    48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000  49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM  50
+#define CX88_BOARD_WINFAST_DTV2000H        51
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -296,6 +303,7 @@
 	/* config info -- dvb */
 	struct dvb_pll_desc        *pll_desc;
 	unsigned int               pll_addr;
+	int 			   (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
 
 	/* state info */
 	struct task_struct         *kthread;
@@ -391,14 +399,6 @@
 	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;
@@ -432,8 +432,7 @@
 	unsigned char              ts_gen_cntrl;
 
 	/* mpeg params */
-	struct v4l2_mpeg_compression params;
-	struct blackbird_dnr       dnr_params;
+	struct cx2341x_mpeg_params params;
 };
 
 /* ----------------------------------------------------------- */
@@ -564,7 +563,6 @@
 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                                                */
@@ -593,16 +591,6 @@
 				struct cx88_core *core, unsigned int cmd,
 				void *arg, v4l2_kioctl driver_ioctl);
 
-/* ----------------------------------------------------------- */
-/* cx88-blackbird.c                                            */
-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:
  * c-basic-offset: 8
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c
index 3b4e998..f7e33f9 100644
--- a/drivers/media/video/dsbr100.c
+++ b/drivers/media/video/dsbr100.c
@@ -72,6 +72,7 @@
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3ba3439..ed882eb 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
-		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
 		      Sascha Sommer <saschasommer@freenet.de>
 
    This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,8 @@
 #include <linux/usb.h>
 #include <media/tuner.h>
 #include <media/msp3400.h>
+#include <media/saa7115.h>
+#include <media/tvp5150.h>
 #include <media/tveeprom.h>
 #include <media/audiochip.h>
 #include <media/v4l2-common.h>
@@ -46,11 +48,11 @@
 		.decoder      = EM28XX_SAA7113,
 		.input           = {{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -64,11 +66,11 @@
 		.decoder      = EM28XX_SAA7113,
 		.input           = {{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -82,11 +84,11 @@
 		.decoder      = EM28XX_SAA7113,
 		.input           = {{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -100,15 +102,15 @@
 		.decoder      = EM28XX_SAA7113,
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 2,
+			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -122,15 +124,15 @@
 		.decoder      = EM28XX_SAA7113,
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 2,
+			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -146,11 +148,11 @@
 		/*FIXME: S-Video not tested */
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 0,
+			.vmux     = TVP5150_COMPOSITE0,
 			.amux     = MSP_INPUT_DEFAULT,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 2,
+			.vmux     = TVP5150_SVIDEO,
 			.amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
 					MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
 		}},
@@ -165,15 +167,15 @@
 		.decoder        = EM28XX_SAA7114,
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 4,
+			.vmux     = SAA7115_COMPOSITE4,
 			.amux     = 0,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -188,15 +190,15 @@
 		.decoder      = EM28XX_SAA7113,
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 2,
+			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -211,15 +213,15 @@
 		.decoder      = EM28XX_SAA7113,
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 2,
+			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -234,15 +236,15 @@
 		.decoder      = EM28XX_SAA7113,
 		.input          = {{
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = 2,
+			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
 		},{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -254,11 +256,11 @@
 		.decoder      = EM28XX_SAA7113,
 		.input          = {{
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = 0,
+			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
 		},{
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = 9,
+			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
 		}},
 	},
@@ -324,8 +326,4 @@
 	}
 }
 
-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
index e5ee8bc..4350cc7 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
-		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
 		      Sascha Sommer <saschasommer@freenet.de>
 
    This program is free software; you can redistribute it and/or modify
@@ -317,8 +317,8 @@
 	return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
 }
 
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
-				  u8 ymax)
+static 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);
 
@@ -328,7 +328,7 @@
 	return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
 }
 
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
 				   u16 width, u16 height)
 {
 	u8 cwidth = width;
@@ -345,7 +345,7 @@
 	return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
 }
 
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 {
 	u8 mode;
 	/* the em2800 scaler only supports scaling down to 50% */
@@ -534,7 +534,7 @@
  * em28xx_isoIrq()
  * handles the incoming isoc urbs and fills the frames from our inqueue
  */
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
 {
 	struct em28xx *dev = urb->context;
 	int i, status;
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 5b6cece..d829d8f 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
-		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
 		      Sascha Sommer <saschasommer@freenet.de>
 
    This program is free software; you can redistribute it and/or modify
@@ -399,17 +399,6 @@
 	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)
 {
@@ -436,9 +425,19 @@
 	struct em28xx *dev = client->adapter->algo_data;
 
 	switch (client->addr << 1) {
-		case 0x86:
+		case 0x43:
+		case 0x4b:
+		{
+			struct tuner_setup tun_setup;
+
+			tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+			tun_setup.type = TUNER_TDA9887;
+			tun_setup.addr = client->addr;
+
+			em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 			em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
 			break;
+		}
 		case 0x42:
 			dprintk1(1,"attach_inform: saa7114 detected.\n");
 			break;
@@ -464,6 +463,7 @@
 		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;
@@ -480,12 +480,7 @@
 };
 
 static struct i2c_adapter em28xx_adap_template = {
-#ifdef I2C_PEC
 	.owner = THIS_MODULE,
-#else
-	.inc_use = inc_use,
-	.dec_use = dec_use,
-#endif
 	.class = I2C_CLASS_TV_ANALOG,
 	.name = "em28xx",
 	.id = I2C_HW_B_EM28XX,
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 31e89e4..3ffb568 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
-		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
 		      Sascha Sommer <saschasommer@freenet.de>
 
   This program is free software; you can redistribute it and/or modify
@@ -105,7 +105,7 @@
 	return 1;
 }
 
-static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char buf[3];
 
@@ -148,8 +148,8 @@
 		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
 		break;
 	case (EM2820_BOARD_PINNACLE_USB_2):
-		ir->ir_codes = ir_codes_em_pinnacle_usb;
-		ir->get_key = get_key_pinnacle_usb;
+		ir->ir_codes = ir_codes_pinnacle_grey;
+		ir->get_key = get_key_pinnacle_usb_grey;
 		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
 		break;
 	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index cf7cdf9..9286090 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
-		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
 		      Sascha Sommer <saschasommer@freenet.de>
 
 	Some parts based on SN9C10x PC Camera Controllers GPL driver made
@@ -42,7 +42,7 @@
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
 		      "Markus Rechberger <mrechberger@gmail.com>, " \
-		      "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
 		      "Sascha Sommer <saschasommer@freenet.de>"
 
 #define DRIVER_NAME         "em28xx"
@@ -170,8 +170,12 @@
 static void em28xx_config_i2c(struct em28xx *dev)
 {
 	struct v4l2_frequency f;
+	struct v4l2_routing route;
+
+	route.input = INPUT(dev->ctl_input)->vmux;
+	route.output = 0;
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
-	em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 
 	/* configure tuner */
@@ -206,19 +210,19 @@
 
 static void video_mux(struct em28xx *dev, int index)
 {
-	int input, ainput;
+	int ainput;
+	struct v4l2_routing route;
 
-	input = INPUT(index)->vmux;
+	route.input = INPUT(index)->vmux;
+	route.output = 0;
 	dev->ctl_input = index;
 	dev->ctl_ainput = INPUT(index)->amux;
 
-	em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
-	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
 
 	if (dev->has_msp34xx) {
-		struct v4l2_routing route;
-
 		if (dev->i2s_speed)
 			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
 		route.input = dev->ctl_ainput;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index e1ddc2f..d8fcc9e 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -3,7 +3,7 @@
 
    Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
 		      Ludovico Cavedon <cavedon@sssup.it>
-		      Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+		      Mauro Carvalho Chehab <mchehab@infradead.org>
 
    Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
 
@@ -319,13 +319,7 @@
 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);
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index dfc9dd7..8992b6e 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2341,11 +2341,9 @@
 	case VIDIOC_G_CTRL:
 		return et61x251_vidioc_g_ctrl(cam, arg);
 
-	case VIDIOC_S_CTRL_OLD:
 	case VIDIOC_S_CTRL:
 		return et61x251_vidioc_s_ctrl(cam, arg);
 
-	case VIDIOC_CROPCAP_OLD:
 	case VIDIOC_CROPCAP:
 		return et61x251_vidioc_cropcap(cam, arg);
 
@@ -2392,7 +2390,6 @@
 	case VIDIOC_G_PARM:
 		return et61x251_vidioc_g_parm(cam, arg);
 
-	case VIDIOC_S_PARM_OLD:
 	case VIDIOC_S_PARM:
 		return et61x251_vidioc_s_parm(cam, arg);
 
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 7e66d83..fba30a4 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -150,12 +150,11 @@
 	return 1;
 }
 
-/* The new pinnacle PCTV remote (with the colored buttons)
+/* Common (grey or coloured) pinnacle PCTV remote handling
  *
- * Ricardo Cerqueira <v4l@cerqueira.org>
  */
-
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+			    int parity_offset, int marker, int code_modulo)
 {
 	unsigned char b[4];
 	unsigned int start = 0,parity = 0,code = 0;
@@ -167,9 +166,9 @@
 	}
 
 	for (start = 0; start<4; start++) {
-		if (b[start] == 0x80) {
-			code=b[(start+3)%4];
-			parity=b[(start+2)%4];
+		if (b[start] == marker) {
+			code=b[(start+parity_offset+1)%4];
+			parity=b[(start+parity_offset)%4];
 		}
 	}
 
@@ -181,16 +180,14 @@
 	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
-	 */
+	/* drop special codes when a key is held down a long time for the grey controller
+	   In this case, the second bit of the code is asserted */
+	if (marker == 0xfe && (code & 0x40))
+		return 0;
 
-	code %= 0x88;
+	code %= code_modulo;
 
 	*ir_raw = code;
 	*ir_key = code;
@@ -200,7 +197,40 @@
 	return 1;
 }
 
-EXPORT_SYMBOL_GPL(get_key_pinnacle);
+/* The grey pinnacle PCTV remote
+ *
+ *  There are one issue with this remote:
+ *   - I2c packet does not change when the same key is pressed quickly. The workaround
+ *     is to hold down each key for about half a second, so that another code is generated
+ *     in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+	return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	/* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+	 *
+	 * this is the only value that results in 42 unique
+	 * codes < 128
+	 */
+
+	return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
 
 /* ----------------------------------------------------------------------- */
 
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
new file mode 100644
index 0000000..3bf7ac4
--- /dev/null
+++ b/drivers/media/video/ks0127.c
@@ -0,0 +1,846 @@
+/*
+ * Video Capture Driver (Video for Linux 1/2)
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999  Ryan Drake <stiletto@mediaone.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ *****************************************************************************
+ *
+ * Modified and extended by
+ *	Mike Bernson <mike@mlb.org>
+ *	Gerard v.d. Horst
+ *	Leon van Stuivenberg <l.vanstuivenberg@chello.nl>
+ *	Gernot Ziegler <gz@lysator.liu.se>
+ *
+ * Version History:
+ * V1.0 Ryan Drake	   Initial version by Ryan Drake
+ * V1.1 Gerard v.d. Horst  Added some debugoutput, reset the video-standard
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "ks0127.h"
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define dprintk     if (debug) printk
+
+/* i2c identification */
+#define I2C_KS0127_ADDON   0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
+#define KS_TYPE_UNKNOWN	0
+#define KS_TYPE_0122S	1
+#define KS_TYPE_0127	2
+#define KS_TYPE_0127B	3
+
+/* ks0127 control registers */
+#define KS_STAT     0x00
+#define KS_CMDA     0x01
+#define KS_CMDB     0x02
+#define KS_CMDC     0x03
+#define KS_CMDD     0x04
+#define KS_HAVB     0x05
+#define KS_HAVE     0x06
+#define KS_HS1B     0x07
+#define KS_HS1E     0x08
+#define KS_HS2B     0x09
+#define KS_HS2E     0x0a
+#define KS_AGC      0x0b
+#define KS_HXTRA    0x0c
+#define KS_CDEM     0x0d
+#define KS_PORTAB   0x0e
+#define KS_LUMA     0x0f
+#define KS_CON      0x10
+#define KS_BRT      0x11
+#define KS_CHROMA   0x12
+#define KS_CHROMB   0x13
+#define KS_DEMOD    0x14
+#define KS_SAT      0x15
+#define KS_HUE      0x16
+#define KS_VERTIA   0x17
+#define KS_VERTIB   0x18
+#define KS_VERTIC   0x19
+#define KS_HSCLL    0x1a
+#define KS_HSCLH    0x1b
+#define KS_VSCLL    0x1c
+#define KS_VSCLH    0x1d
+#define KS_OFMTA    0x1e
+#define KS_OFMTB    0x1f
+#define KS_VBICTL   0x20
+#define KS_CCDAT2   0x21
+#define KS_CCDAT1   0x22
+#define KS_VBIL30   0x23
+#define KS_VBIL74   0x24
+#define KS_VBIL118  0x25
+#define KS_VBIL1512 0x26
+#define KS_TTFRAM   0x27
+#define KS_TESTA    0x28
+#define KS_UVOFFH   0x29
+#define KS_UVOFFL   0x2a
+#define KS_UGAIN    0x2b
+#define KS_VGAIN    0x2c
+#define KS_VAVB     0x2d
+#define KS_VAVE     0x2e
+#define KS_CTRACK   0x2f
+#define KS_POLCTL   0x30
+#define KS_REFCOD   0x31
+#define KS_INVALY   0x32
+#define KS_INVALU   0x33
+#define KS_INVALV   0x34
+#define KS_UNUSEY   0x35
+#define KS_UNUSEU   0x36
+#define KS_UNUSEV   0x37
+#define KS_USRSAV   0x38
+#define KS_USREAV   0x39
+#define KS_SHS1A    0x3a
+#define KS_SHS1B    0x3b
+#define KS_SHS1C    0x3c
+#define KS_CMDE     0x3d
+#define KS_VSDEL    0x3e
+#define KS_CMDF     0x3f
+#define KS_GAMMA0   0x40
+#define KS_GAMMA1   0x41
+#define KS_GAMMA2   0x42
+#define KS_GAMMA3   0x43
+#define KS_GAMMA4   0x44
+#define KS_GAMMA5   0x45
+#define KS_GAMMA6   0x46
+#define KS_GAMMA7   0x47
+#define KS_GAMMA8   0x48
+#define KS_GAMMA9   0x49
+#define KS_GAMMA10  0x4a
+#define KS_GAMMA11  0x4b
+#define KS_GAMMA12  0x4c
+#define KS_GAMMA13  0x4d
+#define KS_GAMMA14  0x4e
+#define KS_GAMMA15  0x4f
+#define KS_GAMMA16  0x50
+#define KS_GAMMA17  0x51
+#define KS_GAMMA18  0x52
+#define KS_GAMMA19  0x53
+#define KS_GAMMA20  0x54
+#define KS_GAMMA21  0x55
+#define KS_GAMMA22  0x56
+#define KS_GAMMA23  0x57
+#define KS_GAMMA24  0x58
+#define KS_GAMMA25  0x59
+#define KS_GAMMA26  0x5a
+#define KS_GAMMA27  0x5b
+#define KS_GAMMA28  0x5c
+#define KS_GAMMA29  0x5d
+#define KS_GAMMA30  0x5e
+#define KS_GAMMA31  0x5f
+#define KS_GAMMAD0  0x60
+#define KS_GAMMAD1  0x61
+#define KS_GAMMAD2  0x62
+#define KS_GAMMAD3  0x63
+#define KS_GAMMAD4  0x64
+#define KS_GAMMAD5  0x65
+#define KS_GAMMAD6  0x66
+#define KS_GAMMAD7  0x67
+#define KS_GAMMAD8  0x68
+#define KS_GAMMAD9  0x69
+#define KS_GAMMAD10 0x6a
+#define KS_GAMMAD11 0x6b
+#define KS_GAMMAD12 0x6c
+#define KS_GAMMAD13 0x6d
+#define KS_GAMMAD14 0x6e
+#define KS_GAMMAD15 0x6f
+#define KS_GAMMAD16 0x70
+#define KS_GAMMAD17 0x71
+#define KS_GAMMAD18 0x72
+#define KS_GAMMAD19 0x73
+#define KS_GAMMAD20 0x74
+#define KS_GAMMAD21 0x75
+#define KS_GAMMAD22 0x76
+#define KS_GAMMAD23 0x77
+#define KS_GAMMAD24 0x78
+#define KS_GAMMAD25 0x79
+#define KS_GAMMAD26 0x7a
+#define KS_GAMMAD27 0x7b
+#define KS_GAMMAD28 0x7c
+#define KS_GAMMAD29 0x7d
+#define KS_GAMMAD30 0x7e
+#define KS_GAMMAD31 0x7f
+
+
+/****************************************************************************
+* mga_dev : represents one ks0127 chip.
+****************************************************************************/
+
+struct adjust {
+	int	contrast;
+	int	bright;
+	int	hue;
+	int	ugain;
+	int	vgain;
+};
+
+struct ks0127 {
+	struct i2c_client *client;
+	unsigned char	addr;
+	int		format_width;
+	int		format_height;
+	int		cap_width;
+	int		cap_height;
+	int		norm;
+	int		ks_type;
+	u8 		regs[256];
+};
+
+
+static int debug; /* insmod parameter */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug output");
+MODULE_LICENSE("GPL");
+
+static u8 reg_defaults[64];
+
+
+
+static void init_reg_defaults(void)
+{
+	u8 *table = reg_defaults;
+
+	table[KS_CMDA]     = 0x2c;  /* VSE=0, CCIR 601, autodetect standard */
+	table[KS_CMDB]     = 0x12;  /* VALIGN=0, AGC control and input */
+	table[KS_CMDC]     = 0x00;  /* Test options */
+	/* clock & input select, write 1 to PORTA */
+	table[KS_CMDD]     = 0x01;
+	table[KS_HAVB]     = 0x00;  /* HAV Start Control */
+	table[KS_HAVE]     = 0x00;  /* HAV End Control */
+	table[KS_HS1B]     = 0x10;  /* HS1 Start Control */
+	table[KS_HS1E]     = 0x00;  /* HS1 End Control */
+	table[KS_HS2B]     = 0x00;  /* HS2 Start Control */
+	table[KS_HS2E]     = 0x00;  /* HS2 End Control */
+	table[KS_AGC]      = 0x53;  /* Manual setting for AGC */
+	table[KS_HXTRA]    = 0x00;  /* Extra Bits for HAV and HS1/2 */
+	table[KS_CDEM]     = 0x00;  /* Chroma Demodulation Control */
+	table[KS_PORTAB]   = 0x0f;  /* port B is input, port A output GPPORT */
+	table[KS_LUMA]     = 0x01;  /* Luma control */
+	table[KS_CON]      = 0x00;  /* Contrast Control */
+	table[KS_BRT]      = 0x00;  /* Brightness Control */
+	table[KS_CHROMA]   = 0x2a;  /* Chroma control A */
+	table[KS_CHROMB]   = 0x90;  /* Chroma control B */
+	table[KS_DEMOD]    = 0x00;  /* Chroma Demodulation Control & Status */
+	table[KS_SAT]      = 0x00;  /* Color Saturation Control*/
+	table[KS_HUE]      = 0x00;  /* Hue Control */
+	table[KS_VERTIA]   = 0x00;  /* Vertical Processing Control A */
+	/* Vertical Processing Control B, luma 1 line delayed */
+	table[KS_VERTIB]   = 0x12;
+	table[KS_VERTIC]   = 0x0b;  /* Vertical Processing Control C */
+	table[KS_HSCLL]    = 0x00;  /* Horizontal Scaling Ratio Low */
+	table[KS_HSCLH]    = 0x00;  /* Horizontal Scaling Ratio High */
+	table[KS_VSCLL]    = 0x00;  /* Vertical Scaling Ratio Low */
+	table[KS_VSCLH]    = 0x00;  /* Vertical Scaling Ratio High */
+	/* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */
+	table[KS_OFMTA]    = 0x30;
+	table[KS_OFMTB]    = 0x00;  /* Output Control B */
+	/* VBI Decoder Control; 4bit fmt: avoid Y overflow */
+	table[KS_VBICTL]   = 0x5d;
+	table[KS_CCDAT2]   = 0x00;  /* Read Only register */
+	table[KS_CCDAT1]   = 0x00;  /* Read Only register */
+	table[KS_VBIL30]   = 0xa8;  /* VBI data decoding options */
+	table[KS_VBIL74]   = 0xaa;  /* VBI data decoding options */
+	table[KS_VBIL118]  = 0x2a;  /* VBI data decoding options */
+	table[KS_VBIL1512] = 0x00;  /* VBI data decoding options */
+	table[KS_TTFRAM]   = 0x00;  /* Teletext frame alignment pattern */
+	table[KS_TESTA]    = 0x00;  /* test register, shouldn't be written */
+	table[KS_UVOFFH]   = 0x00;  /* UV Offset Adjustment High */
+	table[KS_UVOFFL]   = 0x00;  /* UV Offset Adjustment Low */
+	table[KS_UGAIN]    = 0x00;  /* U Component Gain Adjustment */
+	table[KS_VGAIN]    = 0x00;  /* V Component Gain Adjustment */
+	table[KS_VAVB]     = 0x07;  /* VAV Begin */
+	table[KS_VAVE]     = 0x00;  /* VAV End */
+	table[KS_CTRACK]   = 0x00;  /* Chroma Tracking Control */
+	table[KS_POLCTL]   = 0x41;  /* Timing Signal Polarity Control */
+	table[KS_REFCOD]   = 0x80;  /* Reference Code Insertion Control */
+	table[KS_INVALY]   = 0x10;  /* Invalid Y Code */
+	table[KS_INVALU]   = 0x80;  /* Invalid U Code */
+	table[KS_INVALV]   = 0x80;  /* Invalid V Code */
+	table[KS_UNUSEY]   = 0x10;  /* Unused Y Code */
+	table[KS_UNUSEU]   = 0x80;  /* Unused U Code */
+	table[KS_UNUSEV]   = 0x80;  /* Unused V Code */
+	table[KS_USRSAV]   = 0x00;  /* reserved */
+	table[KS_USREAV]   = 0x00;  /* reserved */
+	table[KS_SHS1A]    = 0x00;  /* User Defined SHS1 A */
+	/* User Defined SHS1 B, ALT656=1 on 0127B */
+	table[KS_SHS1B]    = 0x80;
+	table[KS_SHS1C]    = 0x00;  /* User Defined SHS1 C */
+	table[KS_CMDE]     = 0x00;  /* Command Register E */
+	table[KS_VSDEL]    = 0x00;  /* VS Delay Control */
+	/* Command Register F, update -immediately- */
+	/* (there might come no vsync)*/
+	table[KS_CMDF]     = 0x02;
+}
+
+
+/* We need to manually read because of a bug in the KS0127 chip.
+ *
+ * An explanation from kayork@mail.utexas.edu:
+ *
+ * During I2C reads, the KS0127 only samples for a stop condition
+ * during the place where the acknoledge bit should be. Any standard
+ * I2C implementation (correctly) throws in another clock transition
+ * at the 9th bit, and the KS0127 will not recognize the stop condition
+ * and will continue to clock out data.
+ *
+ * So we have to do the read ourself.  Big deal.
+	   workaround in i2c-algo-bit
+ */
+
+
+static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+{
+	struct i2c_client *c = ks->client;
+	char val = 0;
+	struct i2c_msg msgs[] = {
+		{c->addr, 0, sizeof(reg), &reg},
+		{c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+	int ret;
+
+	ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		dprintk("ks0127_write error\n");
+
+	return val;
+}
+
+
+static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+{
+	char msg[] = {reg, val};
+
+	if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
+		dprintk("ks0127_write error\n");
+
+	ks->regs[reg] = val;
+}
+
+
+/* generic bit-twiddling */
+static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+{
+	u8 val = ks->regs[reg];
+	val = (val & and_v) | or_v;
+	ks0127_write(ks, reg, val);
+}
+
+
+
+/****************************************************************************
+* ks0127 private api
+****************************************************************************/
+static void ks0127_reset(struct ks0127* ks)
+{
+	int i;
+	u8 *table = reg_defaults;
+
+	ks->ks_type = KS_TYPE_UNKNOWN;
+
+	dprintk("ks0127: reset\n");
+	msleep(1);
+
+	/* initialize all registers to known values */
+	/* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+	for(i = 1; i < 33; i++)
+		ks0127_write(ks, i, table[i]);
+
+	for(i = 35; i < 40; i++)
+		ks0127_write(ks, i, table[i]);
+
+	for(i = 41; i < 56; i++)
+		ks0127_write(ks, i, table[i]);
+
+	for(i = 58; i < 64; i++)
+		ks0127_write(ks, i, table[i]);
+
+
+	if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+		ks->ks_type = KS_TYPE_0122S;
+		dprintk("ks0127: ks0122s Found\n");
+		return;
+	}
+
+	switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
+
+	case 0:
+		ks->ks_type = KS_TYPE_0127;
+		dprintk("ks0127: ks0127 found\n");
+		break;
+
+	case 9:
+		ks->ks_type = KS_TYPE_0127B;
+		dprintk("ks0127: ks0127B Revision A found\n");
+		break;
+
+	default:
+		dprintk("ks0127: unknown revision\n");
+		break;
+	}
+}
+
+static int ks0127_command(struct i2c_client *client,
+			  unsigned int cmd, void *arg)
+{
+	struct ks0127 *ks = i2c_get_clientdata(client);
+
+	int		*iarg = (int*)arg;
+
+	int		status;
+
+	if (!ks)
+		return -ENODEV;
+
+	switch (cmd) {
+
+	case DECODER_INIT:
+		dprintk("ks0127: command DECODER_INIT\n");
+		ks0127_reset(ks);
+		break;
+
+	case DECODER_SET_INPUT:
+		switch(*iarg) {
+		case KS_INPUT_COMPOSITE_1:
+		case KS_INPUT_COMPOSITE_2:
+		case KS_INPUT_COMPOSITE_3:
+		case KS_INPUT_COMPOSITE_4:
+		case KS_INPUT_COMPOSITE_5:
+		case KS_INPUT_COMPOSITE_6:
+			dprintk("ks0127: command DECODER_SET_INPUT %d: "
+				"Composite\n", *iarg);
+			/* autodetect 50/60 Hz */
+			ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+			/* VSE=0 */
+			ks0127_and_or(ks, KS_CMDA,   ~0x40, 0x00);
+			/* set input line */
+			ks0127_and_or(ks, KS_CMDB,   0xb0, *iarg);
+			/* non-freerunning mode */
+			ks0127_and_or(ks, KS_CMDC,   0x70, 0x0a);
+			/* analog input */
+			ks0127_and_or(ks, KS_CMDD,   0x03, 0x00);
+			/* enable chroma demodulation */
+			ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+			/* chroma trap, HYBWR=1 */
+			ks0127_and_or(ks, KS_LUMA,   0x00,
+				       (reg_defaults[KS_LUMA])|0x0c);
+			/* scaler fullbw, luma comb off */
+			ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+			/* manual chroma comb .25 .5 .25 */
+			ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+
+			/* chroma path delay */
+			ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+
+			ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+			ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+			ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+			ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+			break;
+
+		case KS_INPUT_SVIDEO_1:
+		case KS_INPUT_SVIDEO_2:
+		case KS_INPUT_SVIDEO_3:
+			dprintk("ks0127: command DECODER_SET_INPUT %d: "
+				"S-Video\n", *iarg);
+			/* autodetect 50/60 Hz */
+			ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+			/* VSE=0 */
+			ks0127_and_or(ks, KS_CMDA,   ~0x40, 0x00);
+			/* set input line */
+			ks0127_and_or(ks, KS_CMDB,   0xb0, *iarg);
+			/* non-freerunning mode */
+			ks0127_and_or(ks, KS_CMDC,   0x70, 0x0a);
+			/* analog input */
+			ks0127_and_or(ks, KS_CMDD,   0x03, 0x00);
+			/* enable chroma demodulation */
+			ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+			ks0127_and_or(ks, KS_LUMA, 0x00,
+				       reg_defaults[KS_LUMA]);
+			/* disable luma comb */
+			ks0127_and_or(ks, KS_VERTIA, 0x08,
+				       (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+			ks0127_and_or(ks, KS_VERTIC, 0x0f,
+				       reg_defaults[KS_VERTIC]&0xf0);
+
+			ks0127_and_or(ks, KS_CHROMB, 0x0f,
+				       reg_defaults[KS_CHROMB]&0xf0);
+
+			ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+			ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+			ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+			ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+			break;
+
+		case KS_INPUT_YUV656:
+			dprintk("ks0127: command DECODER_SET_INPUT 15: "
+				"YUV656\n");
+			if (ks->norm == VIDEO_MODE_NTSC ||
+			    ks->norm == KS_STD_PAL_M)
+				/* force 60 Hz */
+				ks0127_and_or(ks, KS_CMDA,   0xfc, 0x03);
+			else
+				/* force 50 Hz */
+				ks0127_and_or(ks, KS_CMDA,   0xfc, 0x02);
+
+			ks0127_and_or(ks, KS_CMDA,   0xff, 0x40); /* VSE=1 */
+			/* set input line and VALIGN */
+			ks0127_and_or(ks, KS_CMDB,   0xb0, (*iarg | 0x40));
+			/* freerunning mode, */
+			/* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0  VMEM=1*/
+			ks0127_and_or(ks, KS_CMDC,   0x70, 0x87);
+			/* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+			ks0127_and_or(ks, KS_CMDD,   0x03, 0x08);
+			/* disable chroma demodulation */
+			ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+			/* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+			ks0127_and_or(ks, KS_LUMA,   0x00, 0x71);
+			ks0127_and_or(ks, KS_VERTIC, 0x0f,
+				       reg_defaults[KS_VERTIC]&0xf0);
+
+			/* scaler fullbw, luma comb off */
+			ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+
+			ks0127_and_or(ks, KS_CHROMB, 0x0f,
+				       reg_defaults[KS_CHROMB]&0xf0);
+
+			ks0127_and_or(ks, KS_CON, 0x00, 0x00);
+			ks0127_and_or(ks, KS_BRT, 0x00, 32);	/* spec: 34 */
+				/* spec: 229 (e5) */
+			ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
+			ks0127_and_or(ks, KS_HUE, 0x00, 0);
+
+			ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
+			ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+
+			/*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+			ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
+			ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+			break;
+
+		default:
+			dprintk("ks0127: command DECODER_SET_INPUT: "
+				"Unknown input %d\n", *iarg);
+			break;
+		}
+
+		/* hack: CDMLPF sometimes spontaneously switches on; */
+		/* force back off */
+		ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+		break;
+
+	case DECODER_SET_OUTPUT:
+		switch(*iarg) {
+		case KS_OUTPUT_YUV656E:
+			dprintk("ks0127: command DECODER_SET_OUTPUT: "
+				"OUTPUT_YUV656E (Missing)\n");
+			return -EINVAL;
+			break;
+
+		case KS_OUTPUT_EXV:
+			dprintk("ks0127: command DECODER_SET_OUTPUT: "
+				"OUTPUT_EXV\n");
+			ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+			break;
+		}
+		break;
+
+	case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+		/* Set to automatic SECAM/Fsc mode */
+		ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+
+		ks->norm = *iarg;
+		switch(*iarg)
+		{
+		/* this is untested !! */
+		/* It just detects PAL_N/NTSC_M (no special frequencies) */
+		/* And you have to set the standard a second time afterwards */
+		case VIDEO_MODE_AUTO:
+			dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+
+			/* The chip determines the format */
+			/* based on the current field rate */
+			ks0127_and_or(ks, KS_CMDA,   0xfc, 0x00);
+			ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+			/* This is wrong for PAL ! As I said, */
+			/* you need to set the standard once again !! */
+			ks->format_height = 240;
+			ks->format_width = 704;
+			break;
+
+		case VIDEO_MODE_NTSC:
+			dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
+			ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+			ks->format_height = 240;
+			ks->format_width = 704;
+			break;
+
+		case KS_STD_NTSC_N:
+			dprintk("ks0127: command KS0127_SET_STANDARD: "
+				"NTSC_N (fixme)\n");
+			ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+			ks->format_height = 240;
+			ks->format_width = 704;
+			break;
+
+		case VIDEO_MODE_PAL:
+			dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
+			ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+			ks->format_height = 290;
+			ks->format_width = 704;
+			break;
+
+		case KS_STD_PAL_M:
+			dprintk("ks0127: command KS0127_SET_STANDARD: "
+				"PAL_M (fixme)\n");
+			ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+			ks->format_height = 290;
+			ks->format_width = 704;
+			break;
+
+		case VIDEO_MODE_SECAM:
+			dprintk("ks0127: command KS0127_SET_STANDARD: "
+				"SECAM\n");
+			ks->format_height = 290;
+			ks->format_width = 704;
+
+			/* set to secam autodetection */
+			ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
+			ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+			schedule_timeout_interruptible(HZ/10+1);
+
+			/* did it autodetect? */
+			if (ks0127_read(ks, KS_DEMOD) & 0x40)
+				break;
+
+			/* force to secam mode */
+			ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+			break;
+
+		default:
+			dprintk("ks0127: command DECODER_SET_NORM: "
+				"Unknown norm %d\n", *iarg);
+			break;
+		}
+		break;
+
+	case DECODER_SET_PICTURE:
+		dprintk("ks0127: command DECODER_SET_PICTURE "
+			"not yet supported (fixme)\n");
+		return -EINVAL;
+
+	//sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
+	//sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
+	//sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
+	//sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
+	//sam todo: KS0127_SET_AGC_MODE:
+	//sam todo: KS0127_SET_AGC:
+	//sam todo: KS0127_SET_CHROMA_MODE:
+	//sam todo: KS0127_SET_PIXCLK_MODE:
+	//sam todo: KS0127_SET_GAMMA_MODE:
+	//sam todo: KS0127_SET_UGAIN:
+	//sam todo: KS0127_SET_VGAIN:
+	//sam todo: KS0127_SET_INVALY:
+	//sam todo: KS0127_SET_INVALU:
+	//sam todo: KS0127_SET_INVALV:
+	//sam todo: KS0127_SET_UNUSEY:
+	//sam todo: KS0127_SET_UNUSEU:
+	//sam todo: KS0127_SET_UNUSEV:
+	//sam todo: KS0127_SET_VSALIGN_MODE:
+
+	case DECODER_ENABLE_OUTPUT:
+	{
+
+		int *iarg = arg;
+		int enable = (*iarg != 0);
+			if (enable) {
+				dprintk("ks0127: command "
+					"DECODER_ENABLE_OUTPUT on "
+					"(%d)\n", enable);
+				/* All output pins on */
+				ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+				/* Obey the OEN pin */
+				ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+			} else {
+				dprintk("ks0127: command "
+					"DECODER_ENABLE_OUTPUT off "
+					"(%d)\n", enable);
+				/* Video output pins off */
+				ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+				/* Ignore the OEN pin */
+				ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+			}
+	}
+		break;
+
+	//sam todo: KS0127_SET_OUTPUT_MODE:
+	//sam todo: KS0127_SET_WIDTH:
+	//sam todo: KS0127_SET_HEIGHT:
+	//sam todo: KS0127_SET_HSCALE:
+
+	case DECODER_GET_STATUS:
+		dprintk("ks0127: command DECODER_GET_STATUS\n");
+		*iarg = 0;
+		status = ks0127_read(ks, KS_STAT);
+		if (!(status & 0x20))		 /* NOVID not set */
+			*iarg = (*iarg & DECODER_STATUS_GOOD);
+		if ((status & 0x01))		      /* CLOCK set */
+			*iarg = (*iarg & DECODER_STATUS_COLOR);
+		if ((status & 0x08))		   /* PALDET set */
+			*iarg = (*iarg & DECODER_STATUS_PAL);
+		else
+			*iarg = (*iarg & DECODER_STATUS_NTSC);
+		break;
+
+	//Catch any unknown command
+	default:
+		dprintk("ks0127: command unknown: %04X\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+
+
+static int ks0127_probe(struct i2c_adapter *adapter);
+static int ks0127_detach(struct i2c_client *client);
+static int ks0127_command(struct i2c_client *client,
+			  unsigned int cmd, void *arg);
+
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
+				       I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
+static unsigned short probe[2] =	{I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = 	{I2C_CLIENT_END, I2C_CLIENT_END};
+static struct i2c_client_address_data addr_data = {
+	normal_i2c,
+	probe,
+	ignore,
+};
+
+static struct i2c_driver i2c_driver_ks0127 = {
+	.driver.name = "ks0127",
+	.id             = I2C_DRIVERID_KS0127,
+	.attach_adapter = ks0127_probe,
+	.detach_client  = ks0127_detach,
+	.command        = ks0127_command
+};
+
+static struct i2c_client ks0127_client_tmpl =
+{
+	.name = "(ks0127 unset)",
+	.addr = 0,
+	.adapter = NULL,
+	.driver = &i2c_driver_ks0127,
+	.usage_count = 0
+};
+
+static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+	struct ks0127 *ks;
+	struct i2c_client *client;
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (client == NULL)
+		return -ENOMEM;
+	memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+
+	ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+	if (ks == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, ks);
+	client->adapter = adapter;
+	client->addr = addr;
+	sprintf(client->name, "ks0127-%02x", adapter->id);
+
+	ks->client = client;
+	ks->addr = addr;
+	ks->ks_type = KS_TYPE_UNKNOWN;
+
+	/* power up */
+	ks0127_write(ks, KS_CMDA, 0x2c);
+	mdelay(10);
+
+	/* reset the device */
+	ks0127_reset(ks);
+	printk(KERN_INFO "ks0127: attach: %s video decoder\n",
+	       ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
+
+	i2c_attach_client(client);
+	return 0;
+}
+
+
+static int ks0127_probe(struct i2c_adapter *adapter)
+{
+	if (adapter->id == I2C_HW_B_ZR36067)
+		return i2c_probe(adapter, &addr_data, ks0127_found_proc);
+	return 0;
+}
+
+static int ks0127_detach(struct i2c_client *client)
+{
+	struct ks0127 *ks = i2c_get_clientdata(client);
+
+	ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
+	ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+
+	i2c_detach_client(client);
+	kfree(ks);
+	kfree(client);
+
+	dprintk("ks0127: detach\n");
+	return 0;
+}
+
+
+static int __devinit ks0127_init_module(void)
+{
+	init_reg_defaults();
+	i2c_add_driver(&i2c_driver_ks0127);
+	return 0;
+}
+
+static void __devexit ks0127_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver_ks0127);
+}
+
+
+module_init(ks0127_init_module);
+module_exit(ks0127_cleanup_module);
diff --git a/drivers/media/video/ks0127.h b/drivers/media/video/ks0127.h
new file mode 100644
index 0000000..1ec5788
--- /dev/null
+++ b/drivers/media/video/ks0127.h
@@ -0,0 +1,53 @@
+/*
+ * Video Capture Driver ( Video for Linux 1/2 )
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999  Ryan Drake <stiletto@mediaone.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef KS0127_H
+#define KS0127_H
+
+#include <linux/videodev.h>
+
+/* input channels */
+#define KS_INPUT_COMPOSITE_1    0
+#define KS_INPUT_COMPOSITE_2    1
+#define KS_INPUT_COMPOSITE_3    2
+#define KS_INPUT_COMPOSITE_4    4
+#define KS_INPUT_COMPOSITE_5    5
+#define KS_INPUT_COMPOSITE_6    6
+
+#define KS_INPUT_SVIDEO_1       8
+#define KS_INPUT_SVIDEO_2       9
+#define KS_INPUT_SVIDEO_3       10
+
+#define KS_INPUT_YUV656		15
+#define KS_INPUT_COUNT          10
+
+/* output channels */
+#define KS_OUTPUT_YUV656E       0
+#define KS_OUTPUT_EXV           1
+
+/* video standards */
+#define KS_STD_NTSC_N           112       /* 50 Hz NTSC */
+#define KS_STD_PAL_M            113       /* 60 Hz PAL  */
+
+#endif /* KS0127_H */
+
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 850bee9..f68ca7d 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -32,6 +32,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -1682,13 +1683,13 @@
 
 static void meye_vm_open(struct vm_area_struct *vma)
 {
-	int idx = (int)vma->vm_private_data;
+	long idx = (long)vma->vm_private_data;
 	meye.vma_use_count[idx]++;
 }
 
 static void meye_vm_close(struct vm_area_struct *vma)
 {
-	int idx = (int)vma->vm_private_data;
+	long idx = (long)vma->vm_private_data;
 	meye.vma_use_count[idx]--;
 }
 
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index b806999..dbb75a7 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -385,67 +385,6 @@
 	return V4L2_TUNER_MODE_MONO;
 }
 
-static struct v4l2_queryctrl msp_qctrl_std[] = {
-	{
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 58880,
-		.flags         = 0,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	},{
-		.id            = V4L2_CID_AUDIO_MUTE,
-		.name          = "Mute",
-		.minimum       = 0,
-		.maximum       = 1,
-		.step          = 1,
-		.default_value = 1,
-		.flags         = 0,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},
-};
-
-static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
-	{
-		.id            = V4L2_CID_AUDIO_BALANCE,
-		.name          = "Balance",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 32768,
-		.flags         = 0,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	},{
-		.id            = V4L2_CID_AUDIO_BASS,
-		.name          = "Bass",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 32768,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	},{
-		.id            = V4L2_CID_AUDIO_TREBLE,
-		.name          = "Treble",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535/100,
-		.default_value = 32768,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	},{
-		.id            = V4L2_CID_AUDIO_LOUDNESS,
-		.name          = "Loudness",
-		.minimum       = 0,
-		.maximum       = 1,
-		.step          = 1,
-		.default_value = 1,
-		.flags         = 0,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},
-};
-
-
 static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
@@ -674,22 +613,31 @@
 		int sc1_out = rt->output & 0xf;
 		int sc2_out = (rt->output >> 4) & 0xf;
 		u16 val, reg;
+		int i;
+		int extern_input = 1;
 
 		if (state->routing.input == rt->input &&
 		    state->routing.output == rt->output)
 			break;
 		state->routing = *rt;
+		/* check if the tuner input is used */
+		for (i = 0; i < 5; i++) {
+			if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+				extern_input = 0;
+		}
+		if (extern_input)
+			state->mode = MSP_MODE_EXTERN;
+		else
+			state->mode = MSP_MODE_AM_DETECT;
 		msp_set_scart(client, sc_in, 0);
 		msp_set_scart(client, sc1_out, 1);
 		msp_set_scart(client, sc2_out, 2);
 		msp_set_audmode(client);
 		reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
 		val = msp_read_dem(client, reg);
-		if (tuner != ((val >> 8) & 1)) {
-			msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
-			/* wake thread when a new tuner input is chosen */
-			msp_wake_thread(client);
-		}
+		msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+		/* wake thread when a new input is chosen */
+		msp_wake_thread(client);
 		break;
 	}
 
@@ -744,21 +692,25 @@
 	case VIDIOC_QUERYCTRL:
 	{
 		struct v4l2_queryctrl *qc = arg;
-		int i;
 
-		for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
-			if (qc->id && qc->id == msp_qctrl_std[i].id) {
-				memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
-				return 0;
-			}
+		switch (qc->id) {
+			case V4L2_CID_AUDIO_VOLUME:
+			case V4L2_CID_AUDIO_MUTE:
+				return v4l2_ctrl_query_fill_std(qc);
+			default:
+				break;
+		}
 		if (!state->has_sound_processing)
 			return -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
-			if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
-				memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
-				return 0;
-			}
-		return -EINVAL;
+		switch (qc->id) {
+			case V4L2_CID_AUDIO_LOUDNESS:
+			case V4L2_CID_AUDIO_BALANCE:
+			case V4L2_CID_AUDIO_BASS:
+			case V4L2_CID_AUDIO_TREBLE:
+				return v4l2_ctrl_query_fill_std(qc);
+			default:
+				return -EINVAL;
+		}
 	}
 
 	case VIDIOC_G_CTRL:
@@ -794,7 +746,9 @@
 		case MSP_MODE_EXTERN: p = "External input"; break;
 		default: p = "unknown"; break;
 		}
-		if (state->opmode == OPMODE_MANUAL) {
+		if (state->mode == MSP_MODE_EXTERN) {
+			v4l_info(client, "Mode:     %s\n", p);
+		} else if (state->opmode == OPMODE_MANUAL) {
 			v4l_info(client, "Mode:     %s (%s%s)\n", p,
 				(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
 				(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 633a102..f2fd919 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -244,19 +244,21 @@
 	   the hardware does not support SAP. So the rxsubchans combination
 	   of STEREO | LANG2 does not occur. */
 
-	/* switch to mono if only mono is available */
-	if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
-		audmode = V4L2_TUNER_MODE_MONO;
-	/* if bilingual */
-	else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
-		/* and mono or stereo, then fallback to lang1 */
-		if (audmode == V4L2_TUNER_MODE_MONO ||
-		    audmode == V4L2_TUNER_MODE_STEREO)
-			audmode = V4L2_TUNER_MODE_LANG1;
+	if (state->mode != MSP_MODE_EXTERN) {
+		/* switch to mono if only mono is available */
+		if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
+			audmode = V4L2_TUNER_MODE_MONO;
+		/* if bilingual */
+		else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
+			/* and mono or stereo, then fallback to lang1 */
+			if (audmode == V4L2_TUNER_MODE_MONO ||
+			    audmode == V4L2_TUNER_MODE_STEREO)
+				audmode = V4L2_TUNER_MODE_LANG1;
+		}
+		/* if stereo, and audmode is not mono, then switch to stereo */
+		else if (audmode != V4L2_TUNER_MODE_MONO)
+			audmode = V4L2_TUNER_MODE_STEREO;
 	}
-	/* if stereo, and audmode is not mono, then switch to stereo */
-	else if (audmode != V4L2_TUNER_MODE_MONO)
-		audmode = V4L2_TUNER_MODE_STEREO;
 
 	/* switch demodulator */
 	switch (state->mode) {
@@ -481,6 +483,7 @@
 			/* no carrier scan, just unmute */
 			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
 			state->scan_in_progress = 0;
+			state->rxsubchans = V4L2_TUNER_SUB_STEREO;
 			msp_set_audio(client);
 			continue;
 		}
@@ -947,6 +950,14 @@
 		if (kthread_should_stop())
 			break;
 
+		if (state->mode == MSP_MODE_EXTERN) {
+			/* no carrier scan needed, just unmute */
+			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+			state->scan_in_progress = 0;
+			msp_set_audio(client);
+			continue;
+		}
+
 		/* setup the chip*/
 		msp34xxg_reset(client);
 		state->std = state->radio ? 0x40 : msp_standard;
@@ -978,6 +989,11 @@
 		v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
 			msp_standard_std_name(state->std), state->std);
 
+		if (state->std == 9) {
+			/* AM NICAM mode */
+			msp_write_dsp(client, 0x0e, 0x7c00);
+		}
+
 		/* unmute: dispatch sound to scart output, set scart volume */
 		msp_set_audio(client);
 
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index fdc8e3f..a988df2 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -3239,7 +3239,7 @@
 		RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
 		if (frame->scanstate == STATE_LINES) {
-	    		int nextf;
+			int nextf;
 
 			frame->grabstate = FRAME_DONE;
 			wake_up_interruptible(&frame->wq);
@@ -3405,7 +3405,7 @@
 	RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
 
 	if (frame->scanstate == STATE_LINES) {
-    		int nextf;
+		int nextf;
 
 		frame->grabstate = FRAME_DONE;
 		wake_up_interruptible(&frame->wq);
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 12b3d51..68b082b 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -3,6 +3,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index d9e3cad..3484e36 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -40,6 +40,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 09835ca..5d681fa 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
@@ -804,7 +805,7 @@
 			struct video_picture *p = arg;
 			if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
 			    ||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
-			    	return -EINVAL;
+				return -EINVAL;
 			pd->picture= *p;
 
 			/*
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 53cbc95..697145e 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -7,6 +7,7 @@
 	   * Philips PCA645, PCA646
 	   * Philips PCVC675, PCVC680, PCVC690
 	   * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+	   * Philips SPC900NC
 	   * Askey VC010
 	   * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
 	     and 'Orbit'/'Sphere'
@@ -19,10 +20,18 @@
 	  and never will be, but the 665 and 720/20 are supported by other
 	  drivers.
 
-	  See <file:Documentation/usb/philips.txt> for more information and
-	  installation instructions.
+	  Some newer logitech webcams are not handled by this driver but by the
+	  Usb Video Class driver (linux-uvc).
 
 	  The built-in microphone is enabled by selecting USB Audio support.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called pwc.
+
+config USB_PWC_DEBUG
+	bool "USB Philips Cameras verbose debug"
+	depends USB_PWC
+	help
+	  Say Y here in order to have the pwc driver generate verbose debugging
+	  messages.
+	  A special module options 'trace' is used to control the verbosity.
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
index 33d6012..9db2260 100644
--- a/drivers/media/video/pwc/Makefile
+++ b/drivers/media/video/pwc/Makefile
@@ -1,3 +1,12 @@
-pwc-objs	:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+pwc-objs	:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs	+= pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
 
 obj-$(CONFIG_USB_PWC) += pwc.o
+
+ifeq ($(CONFIG_USB_PWC_DEBUG),y)
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
+else
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
+endif
+
+
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 4ba549b..0bd1155 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -2,7 +2,7 @@
    Functions that send various control messages to the webcam, including
    video modes.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -41,12 +41,14 @@
 #include <asm/uaccess.h>
 #endif
 #include <asm/errno.h>
+#include <linux/version.h>
 
 #include "pwc.h"
-#include "pwc-ioctl.h"
 #include "pwc-uncompress.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 /* Request types: video */
 #define SET_LUM_CTL			0x01
@@ -57,6 +59,10 @@
 #define GET_STATUS_CTL			0x06
 #define SET_EP_STREAM_CTL		0x07
 #define GET_EP_STREAM_CTL		0x08
+#define GET_XX_CTL			0x09
+#define SET_XX_CTL			0x0A
+#define GET_XY_CTL			0x0B
+#define SET_XY_CTL			0x0C
 #define SET_MPT_CTL			0x0D
 #define GET_MPT_CTL			0x0E
 
@@ -93,12 +99,20 @@
 #define READ_SHUTTER_FORMATTER			0x0600
 #define READ_RED_GAIN_FORMATTER			0x0700
 #define READ_BLUE_GAIN_FORMATTER		0x0800
+#define GET_STATUS_B00				0x0B00
 #define SENSOR_TYPE_FORMATTER1			0x0C00
+#define GET_STATUS_3000				0x3000
 #define READ_RAW_Y_MEAN_FORMATTER		0x3100
 #define SET_POWER_SAVE_MODE_FORMATTER		0x3200
 #define MIRROR_IMAGE_FORMATTER			0x3300
 #define LED_FORMATTER				0x3400
+#define LOWLIGHT				0x3500
+#define GET_STATUS_3600				0x3600
 #define SENSOR_TYPE_FORMATTER2			0x3700
+#define GET_STATUS_3800				0x3800
+#define GET_STATUS_4000				0x4000
+#define GET_STATUS_4100				0x4100	/* Get */
+#define CTL_STATUS_4200				0x4200	/* [GS] 1 */
 
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER		0x0100
@@ -138,6 +152,7 @@
 #include "pwc-nala.h"
 };
 
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 
 /****************************************************************************/
 
@@ -159,31 +174,7 @@
 		&buf, buflen, 500)
 
 
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
-	int i;
-	unsigned char *s;
-	char buf[100], *d;
-
-	s = (unsigned char *)p;
-	d = buf;
-	*d = '\0';
-	Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
-	for (i = 0; i < len; i++) {
-		d += sprintf(d, "%02X ", *s++);
-		if ((i & 0xF) == 0xF) {
-			Debug("%s\n", buf);
-			d = buf;
-			*d = '\0';
-		}
-	}
-	if ((i & 0xF) != 0)
-		Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
 {
 	return usb_control_msg(udev,
 		usb_sndctrlpipe(udev, 0),
@@ -196,7 +187,7 @@
 
 
 
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
 {
 	unsigned char buf[3];
 	int ret, fps;
@@ -229,34 +220,14 @@
 	if (pEntry->alternate == 0)
 		return -EINVAL;
 
-	if (pEntry->compressed)
-		return -ENOENT; /* Not supported. */
-
 	memcpy(buf, pEntry->mode, 3);
 	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
 	if (ret < 0) {
-		Debug("Failed to send video command... %d\n", ret);
+		PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
 		return ret;
 	}
 	if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
-	 {
-	   switch(pdev->type) {
-	     case 645:
-	     case 646:
-/*	       pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-	       break;
-
-	     case 675:
-	     case 680:
-	     case 690:
-	     case 720:
-	     case 730:
-	     case 740:
-	     case 750:
-/*	       pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-	       break;
-	   }
-	}
+		pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
 
 	pdev->cmd_len = 3;
 	memcpy(pdev->cmd_buf, buf, 3);
@@ -283,7 +254,7 @@
 }
 
 
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
 {
 	unsigned char buf[13];
 	const struct Timon_table_entry *pChoose;
@@ -315,8 +286,8 @@
 	if (ret < 0)
 		return ret;
 
-/* 	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-	   pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+		pwc_dec23_init(pdev, pdev->type, buf);
 
 	pdev->cmd_len = 13;
 	memcpy(pdev->cmd_buf, buf, 13);
@@ -336,7 +307,7 @@
 }
 
 
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
 {
 	const struct Kiara_table_entry *pChoose = NULL;
 	int fps, ret;
@@ -350,21 +321,14 @@
 	fps = (frames / 5) - 1;
 
 	/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-	if (size == PSZ_VGA && frames == 5 && snapshot)
+	if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
 	{
 		/* Only available in case the raw palette is selected or
 		   we have the decompressor available. This mode is
 		   only available in compressed form
 		*/
-		if (pdev->vpalette == VIDEO_PALETTE_RAW)
-		{
-			Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
-			pChoose = &RawEntry;
-		}
-		else
-		{
-			Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
-		}
+		PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
+		pChoose = &RawEntry;
 	}
 	else
 	{
@@ -372,6 +336,7 @@
 		   if the preferred ratio is not available.
 		   Skip this step when using RAW modes.
 		*/
+		snapshot = 0;
 		while (compression <= 3) {
 			pChoose = &Kiara_table[size][fps][compression];
 			if (pChoose->alternate != 0)
@@ -382,7 +347,7 @@
 	if (pChoose == NULL || pChoose->alternate == 0)
 		return -ENOENT; /* Not supported. */
 
-	Debug("Using alternate setting %d.\n", pChoose->alternate);
+	PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
 
 	/* usb_control_msg won't take staticly allocated arrays as argument?? */
 	memcpy(buf, pChoose->mode, 12);
@@ -394,8 +359,8 @@
 	if (ret < 0)
 		return ret;
 
-/*	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-	  pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+	if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+		pwc_dec23_init(pdev, pdev->type, buf);
 
 	pdev->cmd_len = 12;
 	memcpy(pdev->cmd_buf, buf, 12);
@@ -410,49 +375,13 @@
 		pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
 	else
 		pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+	PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
+	    pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
 	return 0;
 }
 
 
 
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
-	int i, factor = 0, filler = 0;
-
-	/* for PALETTE_YUV420P */
-	switch(pdev->vpalette)
-	{
-	case VIDEO_PALETTE_YUV420P:
-		factor = 6;
-		filler = 128;
-		break;
-	case VIDEO_PALETTE_RAW:
-		factor = 6; /* can be uncompressed YUV420P */
-		filler = 0;
-		break;
-	}
-
-	/* Set sizes in bytes */
-	pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
-	pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
-
-	/* Align offset, or you'll get some very weird results in
-	   YUV420 mode... x must be multiple of 4 (to get the Y's in
-	   place), and y even (or you'll mixup U & V). This is less of a
-	   problem for YUV420P.
-	 */
-	pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
-	pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
-	/* Fill buffers with gray or black */
-	for (i = 0; i < MAX_IMAGES; i++) {
-		if (pdev->image_ptr[i] != NULL)
-			memset(pdev->image_ptr[i], filler, pdev->view.size);
-	}
-}
-
-
-
 /**
    @pdev: device structure
    @width: viewport width
@@ -465,50 +394,78 @@
 {
 	int ret, size;
 
-	Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+	PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
 	size = pwc_decode_size(pdev, width, height);
 	if (size < 0) {
-		Debug("Could not find suitable size.\n");
+		PWC_DEBUG_MODULE("Could not find suitable size.\n");
 		return -ERANGE;
 	}
-	Debug("decode_size = %d.\n", size);
+	PWC_TRACE("decode_size = %d.\n", size);
 
-	ret = -EINVAL;
-	switch(pdev->type) {
-	case 645:
-	case 646:
+	if (DEVICE_USE_CODEC1(pdev->type)) {
 		ret = set_video_mode_Nala(pdev, size, frames);
-		break;
 
-	case 675:
-	case 680:
-	case 690:
-		ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
-		break;
-
-	case 720:
-	case 730:
-	case 740:
-	case 750:
+	} else if (DEVICE_USE_CODEC3(pdev->type)) {
 		ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-		break;
+
+	} else {
+		ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
 	}
 	if (ret < 0) {
-		if (ret == -ENOENT)
-			Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
-		else {
-			Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-		}
+		PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
 		return ret;
 	}
 	pdev->view.x = width;
 	pdev->view.y = height;
 	pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
 	pwc_set_image_buffer_size(pdev);
-	Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+	PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
 	return 0;
 }
 
+#define BLACK_Y 0
+#define BLACK_U 128
+#define BLACK_V 128
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+	int i, factor = 0;
+
+	/* for PALETTE_YUV420P */
+	switch(pdev->vpalette)
+	{
+	case VIDEO_PALETTE_YUV420P:
+		factor = 6;
+		break;
+	case VIDEO_PALETTE_RAW:
+		factor = 6; /* can be uncompressed YUV420P */
+		break;
+	}
+
+	/* Set sizes in bytes */
+	pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+	pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
+
+	/* Align offset, or you'll get some very weird results in
+	   YUV420 mode... x must be multiple of 4 (to get the Y's in
+	   place), and y even (or you'll mixup U & V). This is less of a
+	   problem for YUV420P.
+	 */
+	pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+	pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+	/* Fill buffers with black colors */
+	for (i = 0; i < pwc_mbufs; i++) {
+		unsigned char *p = pdev->image_data + pdev->images[i].offset;
+		memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
+		p += pdev->view.x * pdev->view.y;
+		memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
+		p += pdev->view.x * pdev->view.y/4;
+		memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
+	}
+}
+
+
 
 /* BRIGHTNESS */
 
@@ -520,7 +477,7 @@
 	ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-	return buf << 9;
+	return buf;
 }
 
 int pwc_set_brightness(struct pwc_device *pdev, int value)
@@ -545,7 +502,7 @@
 	ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-	return buf << 10;
+	return buf;
 }
 
 int pwc_set_contrast(struct pwc_device *pdev, int value)
@@ -570,7 +527,7 @@
 	ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-	return buf << 11;
+	return buf;
 }
 
 int pwc_set_gamma(struct pwc_device *pdev, int value)
@@ -588,37 +545,47 @@
 
 /* SATURATION */
 
-int pwc_get_saturation(struct pwc_device *pdev)
+/* return a value between [-100 , 100] */
+int pwc_get_saturation(struct pwc_device *pdev, int *value)
 {
 	char buf;
-	int ret;
-
-	if (pdev->type < 675)
-		return -1;
-	ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
-	if (ret < 0)
-		return ret;
-	return 32768 + buf * 327;
-}
-
-int pwc_set_saturation(struct pwc_device *pdev, int value)
-{
-	char buf;
+	int ret, saturation_register;
 
 	if (pdev->type < 675)
 		return -EINVAL;
-	if (value < 0)
-		value = 0;
-	if (value > 0xffff)
-		value = 0xffff;
-	/* saturation ranges from -100 to +100 */
-	buf = (value - 32768) / 327;
-	return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+	if (pdev->type < 730)
+		saturation_register = SATURATION_MODE_FORMATTER2;
+	else
+		saturation_register = SATURATION_MODE_FORMATTER1;
+	ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1);
+	if (ret < 0)
+		return ret;
+	*value = (signed)buf;
+	return 0;
+}
+
+/* @param value saturation color between [-100 , 100] */
+int pwc_set_saturation(struct pwc_device *pdev, int value)
+{
+	char buf;
+	int saturation_register;
+
+	if (pdev->type < 675)
+		return -EINVAL;
+	if (value < -100)
+		value = -100;
+	if (value > 100)
+		value = 100;
+	if (pdev->type < 730)
+		saturation_register = SATURATION_MODE_FORMATTER2;
+	else
+		saturation_register = SATURATION_MODE_FORMATTER1;
+	return SendControlMsg(SET_CHROM_CTL, saturation_register, 1);
 }
 
 /* AGC */
 
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
 {
 	char buf;
 	int ret;
@@ -643,7 +610,7 @@
 	return 0;
 }
 
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_get_agc(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -673,7 +640,7 @@
 	return 0;
 }
 
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
 {
 	char buf[2];
 	int speed, ret;
@@ -691,23 +658,16 @@
 			value = 0;
 		if (value > 0xffff)
 			value = 0xffff;
-		switch(pdev->type) {
-		case 675:
-		case 680:
-		case 690:
+
+		if (DEVICE_USE_CODEC2(pdev->type)) {
 			/* speed ranges from 0x0 to 0x290 (656) */
 			speed = (value / 100);
 			buf[1] = speed >> 8;
 			buf[0] = speed & 0xff;
-			break;
-		case 720:
-		case 730:
-		case 740:
-		case 750:
+		} else if (DEVICE_USE_CODEC3(pdev->type)) {
 			/* speed seems to range from 0x0 to 0xff */
 			buf[1] = 0;
 			buf[0] = value >> 8;
-			break;
 		}
 
 		ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
@@ -715,6 +675,25 @@
 	return ret;
 }
 
+/* This function is not exported to v4l1, so output values between 0 -> 256 */
+int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+{
+	unsigned char buf[2];
+	int ret;
+
+	ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2);
+	if (ret < 0)
+		return ret;
+	*value = buf[0] + (buf[1] << 8);
+	if (DEVICE_USE_CODEC2(pdev->type)) {
+		/* speed ranges from 0x0 to 0x290 (656) */
+		*value *= 256/656;
+	} else if (DEVICE_USE_CODEC3(pdev->type)) {
+		/* speed seems to range from 0x0 to 0xff */
+	}
+	return 0;
+}
+
 
 /* POWER */
 
@@ -736,19 +715,19 @@
 
 /* private calls */
 
-static inline int pwc_restore_user(struct pwc_device *pdev)
+int pwc_restore_user(struct pwc_device *pdev)
 {
 	char buf; /* dummy */
 	return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
 }
 
-static inline int pwc_save_user(struct pwc_device *pdev)
+int pwc_save_user(struct pwc_device *pdev)
 {
 	char buf; /* dummy */
 	return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
 }
 
-static inline int pwc_restore_factory(struct pwc_device *pdev)
+int pwc_restore_factory(struct pwc_device *pdev)
 {
 	char buf; /* dummy */
 	return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
@@ -766,7 +745,7 @@
   * 03: manual
   * 04: auto
   */
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+int pwc_set_awb(struct pwc_device *pdev, int mode)
 {
 	char buf;
 	int ret;
@@ -786,7 +765,7 @@
 	return 0;
 }
 
-static inline int pwc_get_awb(struct pwc_device *pdev)
+int pwc_get_awb(struct pwc_device *pdev)
 {
 	unsigned char buf;
 	int ret;
@@ -798,7 +777,7 @@
 	return buf;
 }
 
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+int pwc_set_red_gain(struct pwc_device *pdev, int value)
 {
 	unsigned char buf;
 
@@ -811,7 +790,7 @@
 	return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
 }
 
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+int pwc_get_red_gain(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -824,7 +803,7 @@
 }
 
 
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+int pwc_set_blue_gain(struct pwc_device *pdev, int value)
 {
 	unsigned char buf;
 
@@ -837,7 +816,7 @@
 	return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
 }
 
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -854,7 +833,7 @@
    internal red/blue gains, which may be different from the manual
    gains set or read above.
  */
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -866,7 +845,7 @@
 	return 0;
 }
 
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -879,7 +858,7 @@
 }
 
 
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
 {
 	unsigned char buf;
 
@@ -888,7 +867,7 @@
 	return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
 }
 
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -901,7 +880,7 @@
 }
 
 
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
 {
 	unsigned char buf;
 
@@ -910,7 +889,7 @@
 	return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
 }
 
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
 {
 	unsigned char buf;
 	int ret;
@@ -965,7 +944,7 @@
 	return 0;
 }
 
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+int pwc_set_contour(struct pwc_device *pdev, int contour)
 {
 	unsigned char buf;
 	int ret;
@@ -990,7 +969,7 @@
 	return 0;
 }
 
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+int pwc_get_contour(struct pwc_device *pdev, int *contour)
 {
 	unsigned char buf;
 	int ret;
@@ -1012,7 +991,7 @@
 }
 
 
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+int pwc_set_backlight(struct pwc_device *pdev, int backlight)
 {
 	unsigned char buf;
 
@@ -1023,7 +1002,7 @@
 	return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
 }
 
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
 {
 	int ret;
 	unsigned char buf;
@@ -1031,12 +1010,35 @@
 	ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-	*backlight = buf;
+	*backlight = !!buf;
+	return 0;
+}
+
+int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
+{
+	unsigned char buf;
+
+	if (colour)
+		buf = 0xff;
+	else
+		buf = 0x0;
+	return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+}
+
+int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
+{
+	int ret;
+	unsigned char buf;
+
+	ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+	if (ret < 0)
+		return ret;
+	*colour = !!buf;
 	return 0;
 }
 
 
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+int pwc_set_flicker(struct pwc_device *pdev, int flicker)
 {
 	unsigned char buf;
 
@@ -1047,7 +1049,7 @@
 	return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 }
 
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
 {
 	int ret;
 	unsigned char buf;
@@ -1055,12 +1057,11 @@
 	ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-	*flicker = buf;
+	*flicker = !!buf;
 	return 0;
 }
 
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
 {
 	unsigned char buf;
 
@@ -1072,7 +1073,7 @@
 	return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
 }
 
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
 {
 	int ret;
 	unsigned char buf;
@@ -1084,7 +1085,7 @@
 	return 0;
 }
 
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
 {
 	unsigned char buf;
 
@@ -1092,7 +1093,18 @@
 	return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
 }
 
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+	int ret;
+	ret = _pwc_mpt_reset(pdev, flags);
+	if (ret >= 0) {
+		pdev->pan_angle = 0;
+		pdev->tilt_angle = 0;
+	}
+	return ret;
+}
+
+static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
 {
 	unsigned char buf[4];
 
@@ -1110,7 +1122,35 @@
 	return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
 }
 
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+	int ret;
+
+	/* check absolute ranges */
+	if (pan  < pdev->angle_range.pan_min  ||
+	    pan  > pdev->angle_range.pan_max  ||
+	    tilt < pdev->angle_range.tilt_min ||
+	    tilt > pdev->angle_range.tilt_max)
+		return -ERANGE;
+
+	/* go to relative range, check again */
+	pan  -= pdev->pan_angle;
+	tilt -= pdev->tilt_angle;
+	/* angles are specified in degrees * 100, thus the limit = 36000 */
+	if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
+		return -ERANGE;
+
+	ret = _pwc_mpt_set_angle(pdev, pan, tilt);
+	if (ret >= 0) {
+		pdev->pan_angle  += pan;
+		pdev->tilt_angle += tilt;
+	}
+	if (ret == -EPIPE) /* stall -> out of range */
+		ret = -ERANGE;
+	return ret;
+}
+
+static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
 {
 	int ret;
 	unsigned char buf[5];
@@ -1151,6 +1191,26 @@
  /* End of Add-Ons                                    */
  /* ************************************************* */
 
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+   and copy_to_user() calls. With these macros we circumvent this,
+   and let me maintain only one source file. The functionality is
+   exactly the same otherwise.
+ */
+
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+	ARG_type *ARG_name = arg;
+/* copy arg to local variable */
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
 
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
@@ -1180,206 +1240,243 @@
 
 	case VIDIOCPWCSCQUAL:
 	{
-		int *qual = arg;
+		ARG_DEF(int, qual)
 
-		if (*qual < 0 || *qual > 3)
+		ARG_IN(qual)
+		if (ARGR(qual) < 0 || ARGR(qual) > 3)
 			ret = -EINVAL;
 		else
-			ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+			ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
 		if (ret >= 0)
-			pdev->vcompression = *qual;
+			pdev->vcompression = ARGR(qual);
 		break;
 	}
 
 	case VIDIOCPWCGCQUAL:
 	{
-		int *qual = arg;
-		*qual = pdev->vcompression;
+		ARG_DEF(int, qual)
+
+		ARGR(qual) = pdev->vcompression;
+		ARG_OUT(qual)
 		break;
 	}
 
 	case VIDIOCPWCPROBE:
 	{
-		struct pwc_probe *probe = arg;
-		strcpy(probe->name, pdev->vdev->name);
-		probe->type = pdev->type;
+		ARG_DEF(struct pwc_probe, probe)
+
+		strcpy(ARGR(probe).name, pdev->vdev->name);
+		ARGR(probe).type = pdev->type;
+		ARG_OUT(probe)
 		break;
 	}
 
 	case VIDIOCPWCGSERIAL:
 	{
-		struct pwc_serial *serial = arg;
-		strcpy(serial->serial, pdev->serial);
+		ARG_DEF(struct pwc_serial, serial)
+
+		strcpy(ARGR(serial).serial, pdev->serial);
+		ARG_OUT(serial)
 		break;
 	}
 
 	case VIDIOCPWCSAGC:
 	{
-		int *agc = arg;
-		if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+		ARG_DEF(int, agc)
+
+		ARG_IN(agc)
+		if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
 			ret = -EINVAL;
 		break;
 	}
 
 	case VIDIOCPWCGAGC:
 	{
-		int *agc = arg;
+		ARG_DEF(int, agc)
 
-		if (pwc_get_agc(pdev, agc))
+		if (pwc_get_agc(pdev, ARGA(agc)))
 			ret = -EINVAL;
+		ARG_OUT(agc)
 		break;
 	}
 
 	case VIDIOCPWCSSHUTTER:
 	{
-		int *shutter_speed = arg;
-		ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+		ARG_DEF(int, shutter_speed)
+
+		ARG_IN(shutter_speed)
+		ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
 		break;
 	}
 
 	case VIDIOCPWCSAWB:
 	{
-		struct pwc_whitebalance *wb = arg;
+		ARG_DEF(struct pwc_whitebalance, wb)
 
-		ret = pwc_set_awb(pdev, wb->mode);
-		if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
-			pwc_set_red_gain(pdev, wb->manual_red);
-			pwc_set_blue_gain(pdev, wb->manual_blue);
+		ARG_IN(wb)
+		ret = pwc_set_awb(pdev, ARGR(wb).mode);
+		if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+			pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+			pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
 		}
 		break;
 	}
 
 	case VIDIOCPWCGAWB:
 	{
-		struct pwc_whitebalance *wb = arg;
+		ARG_DEF(struct pwc_whitebalance, wb)
 
-		memset(wb, 0, sizeof(struct pwc_whitebalance));
-		wb->mode = pwc_get_awb(pdev);
-		if (wb->mode < 0)
+		memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+		ARGR(wb).mode = pwc_get_awb(pdev);
+		if (ARGR(wb).mode < 0)
 			ret = -EINVAL;
 		else {
-			if (wb->mode == PWC_WB_MANUAL) {
-				ret = pwc_get_red_gain(pdev, &wb->manual_red);
+			if (ARGR(wb).mode == PWC_WB_MANUAL) {
+				ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
 				if (ret < 0)
 					break;
-				ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+				ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
 				if (ret < 0)
 					break;
 			}
-			if (wb->mode == PWC_WB_AUTO) {
-				ret = pwc_read_red_gain(pdev, &wb->read_red);
+			if (ARGR(wb).mode == PWC_WB_AUTO) {
+				ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
 				if (ret < 0)
 					break;
-				ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+				ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
 				if (ret < 0)
 					break;
 			}
 		}
+		ARG_OUT(wb)
 		break;
 	}
 
 	case VIDIOCPWCSAWBSPEED:
 	{
-		struct pwc_wb_speed *wbs = arg;
+		ARG_DEF(struct pwc_wb_speed, wbs)
 
-		if (wbs->control_speed > 0) {
-			ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+		if (ARGR(wbs).control_speed > 0) {
+			ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
 		}
-		if (wbs->control_delay > 0) {
-			ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+		if (ARGR(wbs).control_delay > 0) {
+			ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
 		}
 		break;
 	}
 
 	case VIDIOCPWCGAWBSPEED:
 	{
-		struct pwc_wb_speed *wbs = arg;
+		ARG_DEF(struct pwc_wb_speed, wbs)
 
-		ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+		ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
 		if (ret < 0)
 			break;
-		ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+		ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
 		if (ret < 0)
 			break;
+		ARG_OUT(wbs)
 		break;
 	}
 
 	case VIDIOCPWCSLED:
 	{
-		struct pwc_leds *leds = arg;
-		ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
-	    	break;
+		ARG_DEF(struct pwc_leds, leds)
+
+		ARG_IN(leds)
+		ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+		break;
 	}
 
 
 	case VIDIOCPWCGLED:
 	{
-		struct pwc_leds *leds = arg;
-		ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+		ARG_DEF(struct pwc_leds, leds)
+
+		ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+		ARG_OUT(leds)
 		break;
 	}
 
 	case VIDIOCPWCSCONTOUR:
 	{
-		int *contour = arg;
-		ret = pwc_set_contour(pdev, *contour);
+		ARG_DEF(int, contour)
+
+		ARG_IN(contour)
+		ret = pwc_set_contour(pdev, ARGR(contour));
 		break;
 	}
 
 	case VIDIOCPWCGCONTOUR:
 	{
-		int *contour = arg;
-		ret = pwc_get_contour(pdev, contour);
+		ARG_DEF(int, contour)
+
+		ret = pwc_get_contour(pdev, ARGA(contour));
+		ARG_OUT(contour)
 		break;
 	}
 
 	case VIDIOCPWCSBACKLIGHT:
 	{
-		int *backlight = arg;
-		ret = pwc_set_backlight(pdev, *backlight);
+		ARG_DEF(int, backlight)
+
+		ARG_IN(backlight)
+		ret = pwc_set_backlight(pdev, ARGR(backlight));
 		break;
 	}
 
 	case VIDIOCPWCGBACKLIGHT:
 	{
-		int *backlight = arg;
-		ret = pwc_get_backlight(pdev, backlight);
+		ARG_DEF(int, backlight)
+
+		ret = pwc_get_backlight(pdev, ARGA(backlight));
+		ARG_OUT(backlight)
 		break;
 	}
 
 	case VIDIOCPWCSFLICKER:
 	{
-		int *flicker = arg;
-		ret = pwc_set_flicker(pdev, *flicker);
+		ARG_DEF(int, flicker)
+
+		ARG_IN(flicker)
+		ret = pwc_set_flicker(pdev, ARGR(flicker));
 		break;
 	}
 
 	case VIDIOCPWCGFLICKER:
 	{
-		int *flicker = arg;
-		ret = pwc_get_flicker(pdev, flicker);
+		ARG_DEF(int, flicker)
+
+		ret = pwc_get_flicker(pdev, ARGA(flicker));
+		ARG_OUT(flicker)
 		break;
 	}
 
 	case VIDIOCPWCSDYNNOISE:
 	{
-		int *dynnoise = arg;
-		ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+		ARG_DEF(int, dynnoise)
+
+		ARG_IN(dynnoise)
+		ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
 		break;
 	}
 
 	case VIDIOCPWCGDYNNOISE:
 	{
-		int *dynnoise = arg;
-		ret = pwc_get_dynamic_noise(pdev, dynnoise);
+		ARG_DEF(int, dynnoise)
+
+		ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+		ARG_OUT(dynnoise);
 		break;
 	}
 
 	case VIDIOCPWCGREALSIZE:
 	{
-		struct pwc_imagesize *size = arg;
-		size->width = pdev->image.x;
-		size->height = pdev->image.y;
+		ARG_DEF(struct pwc_imagesize, size)
+
+		ARGR(size).width = pdev->image.x;
+		ARGR(size).height = pdev->image.y;
+		ARG_OUT(size)
 		break;
 	}
 
@@ -1387,14 +1484,10 @@
 	{
 		if (pdev->features & FEATURE_MOTOR_PANTILT)
 		{
-			int *flags = arg;
+			ARG_DEF(int, flags)
 
-			ret = pwc_mpt_reset(pdev, *flags);
-			if (ret >= 0)
-			{
-				pdev->pan_angle = 0;
-				pdev->tilt_angle = 0;
-			}
+			ARG_IN(flags)
+			ret = pwc_mpt_reset(pdev, ARGR(flags));
 		}
 		else
 		{
@@ -1407,8 +1500,10 @@
 	{
 		if (pdev->features & FEATURE_MOTOR_PANTILT)
 		{
-			struct pwc_mpt_range *range = arg;
-			*range = pdev->angle_range;
+			ARG_DEF(struct pwc_mpt_range, range)
+
+			ARGR(range) = pdev->angle_range;
+			ARG_OUT(range)
 		}
 		else
 		{
@@ -1423,48 +1518,23 @@
 
 		if (pdev->features & FEATURE_MOTOR_PANTILT)
 		{
-			struct pwc_mpt_angles *angles = arg;
+			ARG_DEF(struct pwc_mpt_angles, angles)
+
+			ARG_IN(angles)
 			/* The camera can only set relative angles, so
 			   do some calculations when getting an absolute angle .
 			 */
-			if (angles->absolute)
+			if (ARGR(angles).absolute)
 			{
-				new_pan  = angles->pan;
-				new_tilt = angles->tilt;
+				new_pan  = ARGR(angles).pan;
+				new_tilt = ARGR(angles).tilt;
 			}
 			else
 			{
-				new_pan  = pdev->pan_angle  + angles->pan;
-				new_tilt = pdev->tilt_angle + angles->tilt;
+				new_pan  = pdev->pan_angle  + ARGR(angles).pan;
+				new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
 			}
-			/* check absolute ranges */
-			if (new_pan  < pdev->angle_range.pan_min  ||
-			    new_pan  > pdev->angle_range.pan_max  ||
-			    new_tilt < pdev->angle_range.tilt_min ||
-			    new_tilt > pdev->angle_range.tilt_max)
-			{
-				ret = -ERANGE;
-			}
-			else
-			{
-				/* go to relative range, check again */
-				new_pan  -= pdev->pan_angle;
-				new_tilt -= pdev->tilt_angle;
-				/* angles are specified in degrees * 100, thus the limit = 36000 */
-				if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
-					ret = -ERANGE;
-			}
-			if (ret == 0) /* no errors so far */
-			{
-				ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
-				if (ret >= 0)
-				{
-					pdev->pan_angle  += new_pan;
-					pdev->tilt_angle += new_tilt;
-				}
-				if (ret == -EPIPE) /* stall -> out of range */
-					ret = -ERANGE;
-			}
+			ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
 		}
 		else
 		{
@@ -1478,11 +1548,12 @@
 
 		if (pdev->features & FEATURE_MOTOR_PANTILT)
 		{
-			struct pwc_mpt_angles *angles = arg;
+			ARG_DEF(struct pwc_mpt_angles, angles)
 
-			angles->absolute = 1;
-			angles->pan  = pdev->pan_angle;
-			angles->tilt = pdev->tilt_angle;
+			ARGR(angles).absolute = 1;
+			ARGR(angles).pan  = pdev->pan_angle;
+			ARGR(angles).tilt = pdev->tilt_angle;
+			ARG_OUT(angles)
 		}
 		else
 		{
@@ -1495,8 +1566,10 @@
 	{
 		if (pdev->features & FEATURE_MOTOR_PANTILT)
 		{
-			struct pwc_mpt_status *status = arg;
-			ret = pwc_mpt_get_status(pdev, status);
+			ARG_DEF(struct pwc_mpt_status, status)
+
+			ret = pwc_mpt_get_status(pdev, ARGA(status));
+			ARG_OUT(status)
 		}
 		else
 		{
@@ -1507,22 +1580,24 @@
 
 	case VIDIOCPWCGVIDCMD:
 	{
-		struct pwc_video_command *cmd = arg;
+		ARG_DEF(struct pwc_video_command, cmd);
 
-		cmd->type = pdev->type;
-		cmd->release = pdev->release;
-		cmd->command_len = pdev->cmd_len;
-		memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
-		cmd->bandlength = pdev->vbandlength;
-		cmd->frame_size = pdev->frame_size;
+		ARGR(cmd).type = pdev->type;
+		ARGR(cmd).release = pdev->release;
+		ARGR(cmd).command_len = pdev->cmd_len;
+		memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+		ARGR(cmd).bandlength = pdev->vbandlength;
+		ARGR(cmd).frame_size = pdev->frame_size;
+		ARG_OUT(cmd)
 		break;
 	}
        /*
 	case VIDIOCPWCGVIDTABLE:
 	{
-		struct pwc_table_init_buffer *table = arg;
-		table->len = pdev->cmd_len;
-		memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+		ARG_DEF(struct pwc_table_init_buffer, table);
+		ARGR(table).len = pdev->cmd_len;
+		memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+		ARG_OUT(table)
 		break;
 	}
 	*/
@@ -1538,4 +1613,4 @@
 }
 
 
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c
new file mode 100644
index 0000000..c29593f
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec1.c
@@ -0,0 +1,50 @@
+/* Linux driver for Philips webcam
+   Decompression for chipset version 1
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   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 "pwc-dec1.h"
+
+
+void pwc_dec1_init(int type, int release, void *buffer, void *table)
+{
+
+}
+
+void pwc_dec1_exit(void)
+{
+
+
+
+}
+
+int pwc_dec1_alloc(struct pwc_device *pwc)
+{
+	pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+	if (pwc->decompress_data == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h
new file mode 100644
index 0000000..8b62ddc
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec1.h
@@ -0,0 +1,43 @@
+/* Linux driver for Philips webcam
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+
+#ifndef PWC_DEC1_H
+#define PWC_DEC1_H
+
+#include "pwc.h"
+
+struct pwc_dec1_private
+{
+	int version;
+
+};
+
+int  pwc_dec1_alloc(struct pwc_device *pwc);
+void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
+void pwc_dec1_exit(void);
+
+#endif
+
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
new file mode 100644
index 0000000..9e2d91f
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec23.c
@@ -0,0 +1,941 @@
+/* Linux driver for Philips webcam
+   Decompression for chipset version 2 et 3
+   (C) 2004-2006  Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   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 "pwc-timon.h"
+#include "pwc-kiara.h"
+#include "pwc-dec23.h"
+#include <media/pwc-ioctl.h>
+
+#include <linux/string.h>
+
+/*
+ * USE_LOOKUP_TABLE_TO_CLAMP
+ *   0: use a C version of this tests:  {  a<0?0:(a>255?255:a) }
+ *   1: use a faster lookup table for cpu with a big cache (intel)
+ */
+#define USE_LOOKUP_TABLE_TO_CLAMP	1
+/*
+ * UNROLL_LOOP_FOR_COPYING_BLOCK
+ *   0: use a loop for a smaller code (but little slower)
+ *   1: when unrolling the loop, gcc produces some faster code (perhaps only
+ *   valid for intel processor class). Activating this option, automaticaly
+ *   activate USE_LOOKUP_TABLE_TO_CLAMP
+ */
+#define UNROLL_LOOP_FOR_COPY		1
+#if UNROLL_LOOP_FOR_COPY
+# undef USE_LOOKUP_TABLE_TO_CLAMP
+# define USE_LOOKUP_TABLE_TO_CLAMP 1
+#endif
+
+/*
+ * ENABLE_BAYER_DECODER
+ *   0: bayer decoder is not build (save some space)
+ *   1: bayer decoder is build and can be used
+ */
+#define ENABLE_BAYER_DECODER 0
+
+static void build_subblock_pattern(struct pwc_dec23_private *pdec)
+{
+	static const unsigned int initial_values[12] = {
+		-0x526500, -0x221200, 0x221200, 0x526500,
+			   -0x3de200, 0x3de200,
+		-0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
+			   -0x12c200, 0x12c200
+
+	};
+	static const unsigned int values_derivated[12] = {
+		0xa4ca, 0x4424, -0x4424, -0xa4ca,
+			0x7bc4, -0x7bc4,
+		0xdb69, 0x5aba, -0x5aba, -0xdb69,
+			0x2584, -0x2584
+	};
+	unsigned int temp_values[12];
+	int i, j;
+
+	memcpy(temp_values, initial_values, sizeof(initial_values));
+	for (i = 0; i < 256; i++) {
+		for (j = 0; j < 12; j++) {
+			pdec->table_subblock[i][j] = temp_values[j];
+			temp_values[j] += values_derivated[j];
+		}
+	}
+}
+
+static void build_bit_powermask_table(struct pwc_dec23_private *pdec)
+{
+	unsigned char *p;
+	unsigned int bit, byte, mask, val;
+	unsigned int bitpower = 1;
+
+	for (bit = 0; bit < 8; bit++) {
+		mask = bitpower - 1;
+		p = pdec->table_bitpowermask[bit];
+		for (byte = 0; byte < 256; byte++) {
+			val = (byte & mask);
+			if (byte & bitpower)
+				val = -val;
+			*p++ = val;
+		}
+		bitpower<<=1;
+	}
+}
+
+
+static void build_table_color(const unsigned int romtable[16][8],
+			      unsigned char p0004[16][1024],
+			      unsigned char p8004[16][256])
+{
+	int compression_mode, j, k, bit, pw;
+	unsigned char *p0, *p8;
+	const unsigned int *r;
+
+	/* We have 16 compressions tables */
+	for (compression_mode = 0; compression_mode < 16; compression_mode++) {
+		p0 = p0004[compression_mode];
+		p8 = p8004[compression_mode];
+		r  = romtable[compression_mode];
+
+		for (j = 0; j < 8; j++, r++, p0 += 128) {
+
+			for (k = 0; k < 16; k++) {
+				if (k == 0)
+					bit = 1;
+				else if (k >= 1 && k < 3)
+					bit = (r[0] >> 15) & 7;
+				else if (k >= 3 && k < 6)
+					bit = (r[0] >> 12) & 7;
+				else if (k >= 6 && k < 10)
+					bit = (r[0] >> 9) & 7;
+				else if (k >= 10 && k < 13)
+					bit = (r[0] >> 6) & 7;
+				else if (k >= 13 && k < 15)
+					bit = (r[0] >> 3) & 7;
+				else
+					bit = (r[0]) & 7;
+				if (k == 0)
+					*p8++ = 8;
+				else
+					*p8++ = j - bit;
+				*p8++ = bit;
+
+				pw = 1 << bit;
+				p0[k + 0x00] = (1 * pw) + 0x80;
+				p0[k + 0x10] = (2 * pw) + 0x80;
+				p0[k + 0x20] = (3 * pw) + 0x80;
+				p0[k + 0x30] = (4 * pw) + 0x80;
+				p0[k + 0x40] = (-1 * pw) + 0x80;
+				p0[k + 0x50] = (-2 * pw) + 0x80;
+				p0[k + 0x60] = (-3 * pw) + 0x80;
+				p0[k + 0x70] = (-4 * pw) + 0x80;
+			}	/* end of for (k=0; k<16; k++, p8++) */
+		}	/* end of for (j=0; j<8; j++ , table++) */
+	} /* end of foreach compression_mode */
+}
+
+/*
+ *
+ */
+static void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
+{
+#define SCALEBITS 15
+#define ONE_HALF  (1UL << (SCALEBITS - 1))
+	int i;
+	unsigned int offset1 = ONE_HALF;
+	unsigned int offset2 = 0x0000;
+
+	for (i=0; i<256; i++) {
+		pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
+		pdec->table_d800[i] = offset2;
+
+		offset1 += 0x7bc4;
+		offset2 += 0x7bc4;
+	}
+}
+
+/*
+ * To decode the stream:
+ *   if look_bits(2) == 0:	# op == 2 in the lookup table
+ *      skip_bits(2)
+ *      end of the stream
+ *   elif look_bits(3) == 7:	# op == 1 in the lookup table
+ *      skip_bits(3)
+ *      yyyy = get_bits(4)
+ *      xxxx = get_bits(8)
+ *   else:			# op == 0 in the lookup table
+ *      skip_bits(x)
+ *
+ * For speedup processing, we build a lookup table and we takes the first 6 bits.
+ *
+ * struct {
+ *   unsigned char op;	    // operation to execute
+ *   unsigned char bits;    // bits use to perform operation
+ *   unsigned char offset1; // offset to add to access in the table_0004 % 16
+ *   unsigned char offset2; // offset to add to access in the table_0004
+ * }
+ *
+ * How to build this table ?
+ *   op == 2 when (i%4)==0
+ *   op == 1 when (i%8)==7
+ *   op == 0 otherwise
+ *
+ */
+static const unsigned char hash_table_ops[64*4] = {
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x10,
+	0x00, 0x06, 0x01, 0x30,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x01, 0x20,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x50,
+	0x00, 0x05, 0x02, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x03, 0x00,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x10,
+	0x00, 0x06, 0x02, 0x10,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x01, 0x60,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x50,
+	0x00, 0x05, 0x02, 0x40,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x03, 0x40,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x10,
+	0x00, 0x06, 0x01, 0x70,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x01, 0x20,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x50,
+	0x00, 0x05, 0x02, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x03, 0x00,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x10,
+	0x00, 0x06, 0x02, 0x50,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x01, 0x60,
+	0x01, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x00,
+	0x00, 0x04, 0x01, 0x50,
+	0x00, 0x05, 0x02, 0x40,
+	0x02, 0x00, 0x00, 0x00,
+	0x00, 0x03, 0x01, 0x40,
+	0x00, 0x05, 0x03, 0x40,
+	0x01, 0x00, 0x00, 0x00
+};
+
+/*
+ *
+ */
+static const unsigned int MulIdx[16][16] = {
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+	{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
+	{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
+	{4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
+	{6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
+	{4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
+	{1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
+	{0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
+	{0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
+	{1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
+	{7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
+	{4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
+	{7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
+	{1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
+	{1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
+	{10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
+};
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+#define MAX_OUTER_CROP_VALUE	(512)
+static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
+#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
+#else
+#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
+#endif
+
+
+/* If the type or the command change, we rebuild the lookup table */
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+{
+	int flags, version, shift, i;
+	struct pwc_dec23_private *pdec;
+
+	if (pwc->decompress_data == NULL) {
+		pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+		if (pdec == NULL)
+			return -ENOMEM;
+		pwc->decompress_data = pdec;
+	}
+	pdec = pwc->decompress_data;
+
+	if (DEVICE_USE_CODEC3(type)) {
+		flags = cmd[2] & 0x18;
+		if (flags == 8)
+			pdec->nbits = 7;	/* More bits, mean more bits to encode the stream, but better quality */
+		else if (flags == 0x10)
+			pdec->nbits = 8;
+		else
+			pdec->nbits = 6;
+
+		version = cmd[2] >> 5;
+		build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+		build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+
+	} else {
+
+		flags = cmd[2] & 6;
+		if (flags == 2)
+			pdec->nbits = 7;
+		else if (flags == 4)
+			pdec->nbits = 8;
+		else
+			pdec->nbits = 6;
+
+		version = cmd[2] >> 3;
+		build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+		build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+	}
+
+	/* Informations can be coded on a variable number of bits but never less than 8 */
+	shift = 8 - pdec->nbits;
+	pdec->scalebits = SCALEBITS - shift;
+	pdec->nbitsmask = 0xFF >> shift;
+
+	fill_table_dc00_d800(pdec);
+	build_subblock_pattern(pdec);
+	build_bit_powermask_table(pdec);
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+	/* Build the static table to clamp value [0-255] */
+	for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
+		pwc_crop_table[i] = 0;
+	for (i=0; i<256; i++)
+		pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
+	for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
+		pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
+#endif
+
+	return 0;
+}
+
+/*
+ * Copy the 4x4 image block to Y plane buffer
+ */
+static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+	const int *c = src;
+	unsigned char *d = dst;
+
+	*d++ = cm[c[0] >> scalebits];
+	*d++ = cm[c[1] >> scalebits];
+	*d++ = cm[c[2] >> scalebits];
+	*d++ = cm[c[3] >> scalebits];
+
+	d = dst + bytes_per_line;
+	*d++ = cm[c[4] >> scalebits];
+	*d++ = cm[c[5] >> scalebits];
+	*d++ = cm[c[6] >> scalebits];
+	*d++ = cm[c[7] >> scalebits];
+
+	d = dst + bytes_per_line*2;
+	*d++ = cm[c[8] >> scalebits];
+	*d++ = cm[c[9] >> scalebits];
+	*d++ = cm[c[10] >> scalebits];
+	*d++ = cm[c[11] >> scalebits];
+
+	d = dst + bytes_per_line*3;
+	*d++ = cm[c[12] >> scalebits];
+	*d++ = cm[c[13] >> scalebits];
+	*d++ = cm[c[14] >> scalebits];
+	*d++ = cm[c[15] >> scalebits];
+#else
+	int i;
+	const int *c = src;
+	unsigned char *d = dst;
+	for (i = 0; i < 4; i++, c++)
+		*d++ = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line;
+	for (i = 0; i < 4; i++, c++)
+		*d++ = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line*2;
+	for (i = 0; i < 4; i++, c++)
+		*d++ = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line*3;
+	for (i = 0; i < 4; i++, c++)
+		*d++ = CLAMP((*c) >> scalebits);
+#endif
+}
+
+/*
+ * Copy the 4x4 image block to a CrCb plane buffer
+ *
+ */
+static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+	/* Unroll all loops */
+	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+	const int *c = src;
+	unsigned char *d = dst;
+
+	*d++ = cm[c[0] >> scalebits];
+	*d++ = cm[c[4] >> scalebits];
+	*d++ = cm[c[1] >> scalebits];
+	*d++ = cm[c[5] >> scalebits];
+	*d++ = cm[c[2] >> scalebits];
+	*d++ = cm[c[6] >> scalebits];
+	*d++ = cm[c[3] >> scalebits];
+	*d++ = cm[c[7] >> scalebits];
+
+	d = dst + bytes_per_line;
+	*d++ = cm[c[12] >> scalebits];
+	*d++ = cm[c[8] >> scalebits];
+	*d++ = cm[c[13] >> scalebits];
+	*d++ = cm[c[9] >> scalebits];
+	*d++ = cm[c[14] >> scalebits];
+	*d++ = cm[c[10] >> scalebits];
+	*d++ = cm[c[15] >> scalebits];
+	*d++ = cm[c[11] >> scalebits];
+#else
+	int i;
+	const int *c1 = src;
+	const int *c2 = src + 4;
+	unsigned char *d = dst;
+
+	for (i = 0; i < 4; i++, c1++, c2++) {
+		*d++ = CLAMP((*c1) >> scalebits);
+		*d++ = CLAMP((*c2) >> scalebits);
+	}
+	c1 = src + 12;
+	d = dst + bytes_per_line;
+	for (i = 0; i < 4; i++, c1++, c2++) {
+		*d++ = CLAMP((*c1) >> scalebits);
+		*d++ = CLAMP((*c2) >> scalebits);
+	}
+#endif
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 8x2 pixels
+ *   . G . G . G . G . G . G . G
+ *   . . . . . . . . . . . . . .
+ *   . G . G . G . G . G . G . G
+ *   . . . . . . . . . . . . . .
+ *   or
+ *   . . . . . . . . . . . . . .
+ *   G . G . G . G . G . G . G .
+ *   . . . . . . . . . . . . . .
+ *   G . G . G . G . G . G . G .
+*/
+static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+	/* Unroll all loops */
+	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+	unsigned char *d = dst;
+	const int *c = src;
+
+	d[0] = cm[c[0] >> scalebits];
+	d[2] = cm[c[1] >> scalebits];
+	d[4] = cm[c[2] >> scalebits];
+	d[6] = cm[c[3] >> scalebits];
+	d[8] = cm[c[4] >> scalebits];
+	d[10] = cm[c[5] >> scalebits];
+	d[12] = cm[c[6] >> scalebits];
+	d[14] = cm[c[7] >> scalebits];
+
+	d = dst + bytes_per_line;
+	d[0] = cm[c[8] >> scalebits];
+	d[2] = cm[c[9] >> scalebits];
+	d[4] = cm[c[10] >> scalebits];
+	d[6] = cm[c[11] >> scalebits];
+	d[8] = cm[c[12] >> scalebits];
+	d[10] = cm[c[13] >> scalebits];
+	d[12] = cm[c[14] >> scalebits];
+	d[14] = cm[c[15] >> scalebits];
+#else
+	int i;
+	unsigned char *d;
+	const int *c = src;
+
+	d = dst;
+	for (i = 0; i < 8; i++, c++)
+		d[i*2] = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line;
+	for (i = 0; i < 8; i++, c++)
+		d[i*2] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 4x4 pixels
+ *   R . R . R . R
+ *   . B . B . B .
+ *   R . R . R . R
+ *   . B . B . B .
+ */
+static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+	/* Unroll all loops */
+	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+	unsigned char *d = dst;
+	const int *c = src;
+
+	d[0] = cm[c[0] >> scalebits];
+	d[2] = cm[c[1] >> scalebits];
+	d[4] = cm[c[2] >> scalebits];
+	d[6] = cm[c[3] >> scalebits];
+
+	d = dst + bytes_per_line;
+	d[1] = cm[c[4] >> scalebits];
+	d[3] = cm[c[5] >> scalebits];
+	d[5] = cm[c[6] >> scalebits];
+	d[7] = cm[c[7] >> scalebits];
+
+	d = dst + bytes_per_line*2;
+	d[0] = cm[c[8] >> scalebits];
+	d[2] = cm[c[9] >> scalebits];
+	d[4] = cm[c[10] >> scalebits];
+	d[6] = cm[c[11] >> scalebits];
+
+	d = dst + bytes_per_line*3;
+	d[1] = cm[c[12] >> scalebits];
+	d[3] = cm[c[13] >> scalebits];
+	d[5] = cm[c[14] >> scalebits];
+	d[7] = cm[c[15] >> scalebits];
+#else
+	int i;
+	unsigned char *d;
+	const int *c = src;
+
+	d = dst;
+	for (i = 0; i < 4; i++, c++)
+		d[i*2] = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line;
+	for (i = 0; i < 4; i++, c++)
+		d[i*2+1] = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line*2;
+	for (i = 0; i < 4; i++, c++)
+		d[i*2] = CLAMP((*c) >> scalebits);
+
+	d = dst + bytes_per_line*3;
+	for (i = 0; i < 4; i++, c++)
+		d[i*2+1] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+/*
+ * To manage the stream, we keep bits in a 32 bits register.
+ * fill_nbits(n): fill the reservoir with at least n bits
+ * skip_bits(n): discard n bits from the reservoir
+ * get_bits(n): fill the reservoir, returns the first n bits and discard the
+ *              bits from the reservoir.
+ * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
+ *                 contains at least n bits. bits returned is discarded.
+ */
+#define fill_nbits(pdec, nbits_wanted) do { \
+   while (pdec->nbits_in_reservoir<(nbits_wanted)) \
+    { \
+      pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
+      pdec->nbits_in_reservoir += 8; \
+    } \
+}  while(0);
+
+#define skip_nbits(pdec, nbits_to_skip) do { \
+   pdec->reservoir >>= (nbits_to_skip); \
+   pdec->nbits_in_reservoir -= (nbits_to_skip); \
+}  while(0);
+
+#define get_nbits(pdec, nbits_wanted, result) do { \
+   fill_nbits(pdec, nbits_wanted); \
+   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+   skip_nbits(pdec, nbits_wanted); \
+}  while(0);
+
+#define __get_nbits(pdec, nbits_wanted, result) do { \
+   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+   skip_nbits(pdec, nbits_wanted); \
+}  while(0);
+
+#define look_nbits(pdec, nbits_wanted) \
+   ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
+
+/*
+ * Decode a 4x4 pixel block
+ */
+static void decode_block(struct pwc_dec23_private *pdec,
+			 const unsigned char *ptable0004,
+			 const unsigned char *ptable8004)
+{
+	unsigned int primary_color;
+	unsigned int channel_v, offset1, op;
+	int i;
+
+	fill_nbits(pdec, 16);
+	__get_nbits(pdec, pdec->nbits, primary_color);
+
+	if (look_nbits(pdec,2) == 0) {
+		skip_nbits(pdec, 2);
+		/* Very simple, the color is the same for all pixels of the square */
+		for (i = 0; i < 16; i++)
+			pdec->temp_colors[i] = pdec->table_dc00[primary_color];
+
+		return;
+	}
+
+	/* This block is encoded with small pattern */
+	for (i = 0; i < 16; i++)
+		pdec->temp_colors[i] = pdec->table_d800[primary_color];
+
+	__get_nbits(pdec, 3, channel_v);
+	channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
+
+	ptable0004 += (channel_v * 128);
+	ptable8004 += (channel_v * 32);
+
+	offset1 = 0;
+	do
+	{
+		unsigned int htable_idx, rows = 0;
+		const unsigned int *block;
+
+		/* [  zzzz y x x ]
+		 *     xx == 00 :=> end of the block def, remove the two bits from the stream
+		 *    yxx == 111
+		 *    yxx == any other value
+		 *
+		 */
+		fill_nbits(pdec, 16);
+		htable_idx = look_nbits(pdec, 6);
+		op = hash_table_ops[htable_idx * 4];
+
+		if (op == 2) {
+			skip_nbits(pdec, 2);
+
+		} else if (op == 1) {
+			/* 15bits [ xxxx xxxx yyyy 111 ]
+			 * yyy => offset in the table8004
+			 * xxx => offset in the tabled004 (tree)
+			 */
+			unsigned int mask, shift;
+			unsigned int nbits, col1;
+			unsigned int yyyy;
+
+			skip_nbits(pdec, 3);
+			/* offset1 += yyyy */
+			__get_nbits(pdec, 4, yyyy);
+			offset1 += 1 + yyyy;
+			offset1 &= 0x0F;
+			nbits = ptable8004[offset1 * 2];
+
+			/* col1 = xxxx xxxx */
+			__get_nbits(pdec, nbits+1, col1);
+
+			/* Bit mask table */
+			mask = pdec->table_bitpowermask[nbits][col1];
+			shift = ptable8004[offset1 * 2 + 1];
+			rows = ((mask << shift) + 0x80) & 0xFF;
+
+			block = pdec->table_subblock[rows];
+			for (i = 0; i < 16; i++)
+				pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+		} else {
+			/* op == 0
+			 * offset1 is coded on 3 bits
+			 */
+			unsigned int shift;
+
+			offset1 += hash_table_ops [htable_idx * 4 + 2];
+			offset1 &= 0x0F;
+
+			rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
+			block = pdec->table_subblock[rows];
+			for (i = 0; i < 16; i++)
+				pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+			shift = hash_table_ops[htable_idx * 4 + 1];
+			skip_nbits(pdec, shift);
+		}
+
+	} while (op != 2);
+
+}
+
+static void DecompressBand23(struct pwc_dec23_private *pdec,
+			     const unsigned char *rawyuv,
+			     unsigned char *planar_y,
+			     unsigned char *planar_u,
+			     unsigned char *planar_v,
+			     unsigned int   compressed_image_width,
+			     unsigned int   real_image_width)
+{
+	int compression_index, nblocks;
+	const unsigned char *ptable0004;
+	const unsigned char *ptable8004;
+
+	pdec->reservoir = 0;
+	pdec->nbits_in_reservoir = 0;
+	pdec->stream = rawyuv + 1;	/* The first byte of the stream is skipped */
+
+	get_nbits(pdec, 4, compression_index);
+
+	/* pass 1: uncompress Y component */
+	nblocks = compressed_image_width / 4;
+
+	ptable0004 = pdec->table_0004_pass1[compression_index];
+	ptable8004 = pdec->table_8004_pass1[compression_index];
+
+	/* Each block decode a square of 4x4 */
+	while (nblocks) {
+		decode_block(pdec, ptable0004, ptable8004);
+		copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
+		planar_y += 4;
+		nblocks--;
+	}
+
+	/* pass 2: uncompress UV component */
+	nblocks = compressed_image_width / 8;
+
+	ptable0004 = pdec->table_0004_pass2[compression_index];
+	ptable8004 = pdec->table_8004_pass2[compression_index];
+
+	/* Each block decode a square of 4x4 */
+	while (nblocks) {
+		decode_block(pdec, ptable0004, ptable8004);
+		copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
+
+		decode_block(pdec, ptable0004, ptable8004);
+		copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
+
+		planar_v += 8;
+		planar_u += 8;
+		nblocks -= 2;
+	}
+
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Size need to be a multiple of 8 in width
+ *
+ * Return a block of four line encoded like this:
+ *
+ *   G R G R G R G R G R G R G R G R
+ *   B G B G B G B G B G B G B G B G
+ *   G R G R G R G R G R G R G R G R
+ *   B G B G B G B G B G B G B G B G
+ *
+ */
+static void DecompressBandBayer(struct pwc_dec23_private *pdec,
+				const unsigned char *rawyuv,
+				unsigned char *rgbbayer,
+				unsigned int   compressed_image_width,
+				unsigned int   real_image_width)
+{
+	int compression_index, nblocks;
+	const unsigned char *ptable0004;
+	const unsigned char *ptable8004;
+	unsigned char *dest;
+
+	pdec->reservoir = 0;
+	pdec->nbits_in_reservoir = 0;
+	pdec->stream = rawyuv + 1;	/* The first byte of the stream is skipped */
+
+	get_nbits(pdec, 4, compression_index);
+
+	/* pass 1: uncompress RB component */
+	nblocks = compressed_image_width / 4;
+
+	ptable0004 = pdec->table_0004_pass1[compression_index];
+	ptable8004 = pdec->table_8004_pass1[compression_index];
+	dest = rgbbayer;
+
+	/* Each block decode a square of 4x4 */
+	while (nblocks) {
+		decode_block(pdec, ptable0004, ptable8004);
+		copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
+		dest += 8;
+		nblocks--;
+	}
+
+	/* pass 2: uncompress G component */
+	nblocks = compressed_image_width / 8;
+
+	ptable0004 = pdec->table_0004_pass2[compression_index];
+	ptable8004 = pdec->table_8004_pass2[compression_index];
+
+	/* Each block decode a square of 4x4 */
+	while (nblocks) {
+		decode_block(pdec, ptable0004, ptable8004);
+		copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
+
+		decode_block(pdec, ptable0004, ptable8004);
+		copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
+
+		rgbbayer += 16;
+		nblocks -= 2;
+	}
+}
+#endif
+
+
+/**
+ *
+ * Uncompress a pwc23 buffer.
+ *
+ * pwc.view: size of the image wanted
+ * pwc.image: size of the image returned by the camera
+ * pwc.offset: (x,y) to displayer image in the view
+ *
+ * src: raw data
+ * dst: image output
+ * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
+ */
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+			  const void *src,
+			  void *dst,
+			  int flags)
+{
+	int bandlines_left, stride, bytes_per_block;
+
+	bandlines_left = pwc->image.y / 4;
+	bytes_per_block = pwc->view.x * 4;
+
+	if (flags & PWCX_FLAG_BAYER) {
+#if ENABLE_BAYER_DECODER
+		/* RGB Bayer format */
+		unsigned char *rgbout;
+
+		stride = pwc->view.x * pwc->offset.y;
+		rgbout = dst + stride + pwc->offset.x;
+
+
+		while (bandlines_left--) {
+
+			DecompressBandBayer(pwc->decompress_data,
+					    src,
+					    rgbout,
+					    pwc->image.x, pwc->view.x);
+
+			src += pwc->vbandlength;
+			rgbout += bytes_per_block;
+
+		}
+#else
+		memset(dst, 0, pwc->view.x * pwc->view.y);
+#endif
+
+	} else {
+		/* YUV420P image format */
+		unsigned char *pout_planar_y;
+		unsigned char *pout_planar_u;
+		unsigned char *pout_planar_v;
+		unsigned int   plane_size;
+
+		plane_size = pwc->view.x * pwc->view.y;
+
+		/* offset in Y plane */
+		stride = pwc->view.x * pwc->offset.y;
+		pout_planar_y = dst + stride + pwc->offset.x;
+
+		/* offsets in U/V planes */
+		stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
+		pout_planar_u = dst + plane_size + stride;
+		pout_planar_v = dst + plane_size + plane_size / 4 + stride;
+
+		while (bandlines_left--) {
+
+			DecompressBand23(pwc->decompress_data,
+					 src,
+					 pout_planar_y, pout_planar_u, pout_planar_v,
+					 pwc->image.x, pwc->view.x);
+			src += pwc->vbandlength;
+			pout_planar_y += bytes_per_block;
+			pout_planar_u += pwc->view.x;
+			pout_planar_v += pwc->view.x;
+
+		}
+
+	}
+
+}
+
+void pwc_dec23_exit(void)
+{
+	/* Do nothing */
+
+}
+
+/**
+ * Allocate a private structure used by lookup table.
+ * You must call kfree() to free the memory allocated.
+ */
+int pwc_dec23_alloc(struct pwc_device *pwc)
+{
+	pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+	if (pwc->decompress_data == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h
new file mode 100644
index 0000000..1c55298
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec23.h
@@ -0,0 +1,67 @@
+/* Linux driver for Philips webcam
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef PWC_DEC23_H
+#define PWC_DEC23_H
+
+#include "pwc.h"
+
+struct pwc_dec23_private
+{
+  unsigned int scalebits;
+  unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
+
+  unsigned int reservoir;
+  unsigned int nbits_in_reservoir;
+  const unsigned char *stream;
+  int temp_colors[16];
+
+  unsigned char table_0004_pass1[16][1024];
+  unsigned char table_0004_pass2[16][1024];
+  unsigned char table_8004_pass1[16][256];
+  unsigned char table_8004_pass2[16][256];
+  unsigned int  table_subblock[256][12];
+
+  unsigned char table_bitpowermask[8][256];
+  unsigned int  table_d800[256];
+  unsigned int  table_dc00[256];
+
+};
+
+
+int pwc_dec23_alloc(struct pwc_device *pwc);
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
+void pwc_dec23_exit(void);
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+			  const void *src,
+			  void *dst,
+			  int flags);
+
+
+
+#endif
+
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 4141829..47d0d83 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -62,18 +62,21 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <asm/io.h>
+#include <linux/moduleparam.h>
 
 #include "pwc.h"
-#include "pwc-ioctl.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
+#include "pwc-dec23.h"
+#include "pwc-dec1.h"
 #include "pwc-uncompress.h"
 
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
+static const struct usb_device_id pwc_device_table [] = {
 	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
 	{ USB_DEVICE(0x0471, 0x0303) },
 	{ USB_DEVICE(0x0471, 0x0304) },
@@ -81,9 +84,10 @@
 	{ USB_DEVICE(0x0471, 0x0308) },
 	{ USB_DEVICE(0x0471, 0x030C) },
 	{ USB_DEVICE(0x0471, 0x0310) },
-	{ USB_DEVICE(0x0471, 0x0311) },
+	{ USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+	{ USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
 	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
 	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
 	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -94,8 +98,9 @@
 	{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
 	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
 	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
-	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
-	{ USB_DEVICE(0x055D, 0x9001) },
+	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
+	{ USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
+	{ USB_DEVICE(0x055D, 0x9002) },	/* Samsung SNC-35E (Ver3.0) */
 	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
 	{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
 	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
@@ -122,11 +127,13 @@
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_fbufs = 3;   /* Default number of frame buffers */
-static int default_mbufs = 2;	/* Default number of mmap() buffers */
-       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+       int pwc_mbufs = 2;	/* Default number of mmap() buffers */
+#if CONFIG_PWC_DEBUG
+       int pwc_trace = PWC_DEBUG_LEVEL;
+#endif
 static int power_save = 0;
 static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
 static struct {
 	int type;
 	char serial_number[30];
@@ -138,7 +145,7 @@
 
 static int pwc_video_open(struct inode *inode, struct file *file);
 static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
 			  size_t count, loff_t *ppos);
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct inode *inode, struct file *file,
@@ -153,7 +160,6 @@
 	.poll =		pwc_video_poll,
 	.mmap =		pwc_video_mmap,
 	.ioctl =        pwc_video_ioctl,
-	.compat_ioctl = v4l_compat_ioctl32,
 	.llseek =       no_llseek,
 };
 static struct video_device pwc_template = {
@@ -203,52 +209,44 @@
 /* Here we want the physical address of the memory.
  * This is used when initializing the contents of the area.
  */
-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); /* restore the offset */
-	ret = __pa(kva);
-	return ret;
-}
 
-static void * rvmalloc(unsigned long size)
+
+static void *pwc_rvmalloc(unsigned long size)
 {
 	void * mem;
 	unsigned long adr;
 
-	size=PAGE_ALIGN(size);
 	mem=vmalloc_32(size);
-	if (mem)
-	{
-		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-		adr=(unsigned long) mem;
-		while (size > 0)
-		{
-			SetPageReserved(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	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, unsigned long size)
+static void pwc_rvfree(void * mem, unsigned long size)
 {
 	unsigned long adr;
 
-	if (mem)
-	{
-		adr=(unsigned long) mem;
-		while ((long) size > 0)
-		{
-			ClearPageReserved(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
-	}
+	if (!mem)
+		return;
+
+	adr=(unsigned long) mem;
+	while ((long) size > 0)
+	 {
+	   ClearPageReserved(vmalloc_to_page((void *)adr));
+	   adr  += PAGE_SIZE;
+	   size -= PAGE_SIZE;
+	 }
+	vfree(mem);
 }
 
 
@@ -256,100 +254,83 @@
 
 static int pwc_allocate_buffers(struct pwc_device *pdev)
 {
-	int i;
+	int i, err;
 	void *kbuf;
 
-	Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+	PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
 
 	if (pdev == NULL)
 		return -ENXIO;
 
-#ifdef PWC_MAGIC
-	if (pdev->magic != PWC_MAGIC) {
-		Err("allocate_buffers(): magic failed.\n");
-		return -ENXIO;
-	}
-#endif
-	/* Allocate Isochronous pipe buffers */
+	/* Allocate Isochronuous pipe buffers */
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		if (pdev->sbuf[i].data == NULL) {
-			kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+			kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
 			if (kbuf == NULL) {
-				Err("Failed to allocate iso buffer %d.\n", i);
+				PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
 				return -ENOMEM;
 			}
-			Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+			PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
 			pdev->sbuf[i].data = kbuf;
-			memset(kbuf, 0, ISO_BUFFER_SIZE);
 		}
 	}
 
 	/* Allocate frame buffer structure */
 	if (pdev->fbuf == NULL) {
-		kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+		kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
 		if (kbuf == NULL) {
-			Err("Failed to allocate frame buffer structure.\n");
+			PWC_ERROR("Failed to allocate frame buffer structure.\n");
 			return -ENOMEM;
 		}
-		Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+		PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
 		pdev->fbuf = kbuf;
-		memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
 	}
+
 	/* create frame buffers, and make circular ring */
 	for (i = 0; i < default_fbufs; i++) {
 		if (pdev->fbuf[i].data == NULL) {
 			kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
 			if (kbuf == NULL) {
-				Err("Failed to allocate frame buffer %d.\n", i);
+				PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
 				return -ENOMEM;
 			}
-			Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+			PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
 			pdev->fbuf[i].data = kbuf;
-			memset(kbuf, 128, PWC_FRAME_SIZE);
+			memset(kbuf, 0, PWC_FRAME_SIZE);
 		}
 	}
 
 	/* Allocate decompressor table space */
-	kbuf = NULL;
-	switch (pdev->type)
-	 {
-	  case 675:
-	  case 680:
-	  case 690:
-	  case 720:
-	  case 730:
-	  case 740:
-	  case 750:
-#if 0
-	    Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
-	    kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);	/* Timon & Kiara */
-	    break;
-	  case 645:
-	  case 646:
-	    /* TODO & FIXME */
-	    kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
-	    break;
-#endif
-	;
-	 }
-	pdev->decompress_data = kbuf;
+	if (DEVICE_USE_CODEC1(pdev->type))
+		err = pwc_dec1_alloc(pdev);
+	else
+		err = pwc_dec23_alloc(pdev);
+
+	if (err) {
+		PWC_ERROR("Failed to allocate decompress table.\n");
+		return err;
+	}
 
 	/* Allocate image buffer; double buffer for mmap() */
-	kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+	kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
 	if (kbuf == NULL) {
-		Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+		PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
+				pwc_mbufs * pdev->len_per_image);
 		return -ENOMEM;
 	}
-	Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+	PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
 	pdev->image_data = kbuf;
-	for (i = 0; i < default_mbufs; i++)
-		pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
-	for (; i < MAX_IMAGES; i++)
-		pdev->image_ptr[i] = NULL;
+	for (i = 0; i < pwc_mbufs; i++) {
+		pdev->images[i].offset = i * pdev->len_per_image;
+		pdev->images[i].vma_use_count = 0;
+	}
+	for (; i < MAX_IMAGES; i++) {
+		pdev->images[i].offset = 0;
+	}
 
 	kbuf = NULL;
 
-	Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+	PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
 	return 0;
 }
 
@@ -357,21 +338,14 @@
 {
 	int i;
 
-	Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+	PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
 
 	if (pdev == NULL)
 		return;
-#ifdef PWC_MAGIC
-	if (pdev->magic != PWC_MAGIC) {
-		Err("free_buffers(): magic failed.\n");
-		return;
-	}
-#endif
-
 	/* Release Iso-pipe buffers */
 	for (i = 0; i < MAX_ISO_BUFS; i++)
 		if (pdev->sbuf[i].data != NULL) {
-			Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+			PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
 			kfree(pdev->sbuf[i].data);
 			pdev->sbuf[i].data = NULL;
 		}
@@ -380,7 +354,7 @@
 	if (pdev->fbuf != NULL) {
 		for (i = 0; i < default_fbufs; i++) {
 			if (pdev->fbuf[i].data != NULL) {
-				Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+				PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
 				vfree(pdev->fbuf[i].data);
 				pdev->fbuf[i].data = NULL;
 			}
@@ -391,20 +365,19 @@
 
 	/* Intermediate decompression buffer & tables */
 	if (pdev->decompress_data != NULL) {
-		Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+		PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
 		kfree(pdev->decompress_data);
 		pdev->decompress_data = NULL;
 	}
-	pdev->decompressor = NULL;
 
 	/* Release image buffers */
 	if (pdev->image_data != NULL) {
-		Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
-		rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+		PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
+		pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
 	}
 	pdev->image_data = NULL;
 
-	Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+	PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
 }
 
 /* The frame & image buffer mess.
@@ -464,7 +437,7 @@
 /**
   \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
  */
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+static int pwc_next_fill_frame(struct pwc_device *pdev)
 {
 	int ret;
 	unsigned long flags;
@@ -489,23 +462,17 @@
 	}
 	else {
 		/* Hmm. Take it from the full list */
-#if PWC_DEBUG
 		/* sanity check */
 		if (pdev->full_frames == NULL) {
-			Err("Neither empty or full frames available!\n");
+			PWC_ERROR("Neither empty or full frames available!\n");
 			spin_unlock_irqrestore(&pdev->ptrlock, flags);
 			return -EINVAL;
 		}
-#endif
 		pdev->fill_frame = pdev->full_frames;
 		pdev->full_frames = pdev->full_frames->next;
 		ret = 1;
 	}
 	pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
-	Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
-	pdev->fill_frame->sequence = pdev->sequence++;
-#endif
 	spin_unlock_irqrestore(&pdev->ptrlock, flags);
 	return ret;
 }
@@ -521,6 +488,8 @@
 	int i;
 	unsigned long flags;
 
+	PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+
 	spin_lock_irqsave(&pdev->ptrlock, flags);
 	pdev->full_frames = NULL;
 	pdev->full_frames_tail = NULL;
@@ -540,13 +509,15 @@
 	pdev->image_read_pos = 0;
 	pdev->fill_image = 0;
 	spin_unlock_irqrestore(&pdev->ptrlock, flags);
+
+	PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
 }
 
 
 /**
   \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
  */
-static int pwc_handle_frame(struct pwc_device *pdev)
+int pwc_handle_frame(struct pwc_device *pdev)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -556,41 +527,40 @@
 	   we can release the lock after this without problems */
 	if (pdev->read_frame != NULL) {
 		/* This can't theoretically happen */
-		Err("Huh? Read frame still in use?\n");
+		PWC_ERROR("Huh? Read frame still in use?\n");
+		spin_unlock_irqrestore(&pdev->ptrlock, flags);
+		return ret;
+	}
+
+
+	if (pdev->full_frames == NULL) {
+		PWC_ERROR("Woops. No frames ready.\n");
 	}
 	else {
-		if (pdev->full_frames == NULL) {
-			Err("Woops. No frames ready.\n");
+		pdev->read_frame = pdev->full_frames;
+		pdev->full_frames = pdev->full_frames->next;
+		pdev->read_frame->next = NULL;
+	}
+
+	if (pdev->read_frame != NULL) {
+		/* Decompression is a lenghty process, so it's outside of the lock.
+		   This gives the isoc_handler the opportunity to fill more frames
+		   in the mean time.
+		*/
+		spin_unlock_irqrestore(&pdev->ptrlock, flags);
+		ret = pwc_decompress(pdev);
+		spin_lock_irqsave(&pdev->ptrlock, flags);
+
+		/* We're done with read_buffer, tack it to the end of the empty buffer list */
+		if (pdev->empty_frames == NULL) {
+			pdev->empty_frames = pdev->read_frame;
+			pdev->empty_frames_tail = pdev->empty_frames;
 		}
 		else {
-			pdev->read_frame = pdev->full_frames;
-			pdev->full_frames = pdev->full_frames->next;
-			pdev->read_frame->next = NULL;
+			pdev->empty_frames_tail->next = pdev->read_frame;
+			pdev->empty_frames_tail = pdev->read_frame;
 		}
-
-		if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
-			Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
-			/* Decompression is a lenghty process, so it's outside of the lock.
-			   This gives the isoc_handler the opportunity to fill more frames
-			   in the mean time.
-			*/
-			spin_unlock_irqrestore(&pdev->ptrlock, flags);
-			ret = pwc_decompress(pdev);
-			spin_lock_irqsave(&pdev->ptrlock, flags);
-
-			/* We're done with read_buffer, tack it to the end of the empty buffer list */
-			if (pdev->empty_frames == NULL) {
-				pdev->empty_frames = pdev->read_frame;
-				pdev->empty_frames_tail = pdev->empty_frames;
-			}
-			else {
-				pdev->empty_frames_tail->next = pdev->read_frame;
-				pdev->empty_frames_tail = pdev->read_frame;
-			}
-			pdev->read_frame = NULL;
-		}
+		pdev->read_frame = NULL;
 	}
 	spin_unlock_irqrestore(&pdev->ptrlock, flags);
 	return ret;
@@ -599,12 +569,114 @@
 /**
   \brief Advance pointers of image buffer (after each user request)
 */
-static inline void pwc_next_image(struct pwc_device *pdev)
+void pwc_next_image(struct pwc_device *pdev)
 {
 	pdev->image_used[pdev->fill_image] = 0;
-	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+	pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
 }
 
+/**
+ * Print debug information when a frame is discarded because all of our buffer
+ * is full
+ */
+static void pwc_frame_dumped(struct pwc_device *pdev)
+{
+	pdev->vframes_dumped++;
+	if (pdev->vframe_count < FRAME_LOWMARK)
+		return;
+
+	if (pdev->vframes_dumped < 20)
+		PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
+	else if (pdev->vframes_dumped == 20)
+		PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
+				pdev->vframe_count);
+}
+
+static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+{
+	int awake = 0;
+
+	/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+	   frames on the USB wire after an exposure change. This conditition is
+	   however detected  in the cam and a bit is set in the header.
+	   */
+	if (pdev->type == 730) {
+		unsigned char *ptr = (unsigned char *)fbuf->data;
+
+		if (ptr[1] == 1 && ptr[0] & 0x10) {
+			PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
+			pdev->drop_frames += 2;
+			pdev->vframes_error++;
+		}
+		if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+			if (ptr[0] & 0x01) {
+				pdev->snapshot_button_status = 1;
+				PWC_TRACE("Snapshot button pressed.\n");
+			}
+			else {
+				PWC_TRACE("Snapshot button released.\n");
+			}
+		}
+		if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+			if (ptr[0] & 0x02)
+				PWC_TRACE("Image is mirrored.\n");
+			else
+				PWC_TRACE("Image is normal.\n");
+		}
+		pdev->vmirror = ptr[0] & 0x03;
+		/* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+		   after a short frame; this condition is filtered out specifically. A 4 byte
+		   frame doesn't make sense anyway.
+		   So we get either this sequence:
+		   drop_bit set -> 4 byte frame -> short frame -> good frame
+		   Or this one:
+		   drop_bit set -> short frame -> good frame
+		   So we drop either 3 or 2 frames in all!
+		   */
+		if (fbuf->filled == 4)
+			pdev->drop_frames++;
+	}
+	else if (pdev->type == 740 || pdev->type == 720) {
+		unsigned char *ptr = (unsigned char *)fbuf->data;
+		if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+			if (ptr[0] & 0x01) {
+				pdev->snapshot_button_status = 1;
+				PWC_TRACE("Snapshot button pressed.\n");
+			}
+			else
+				PWC_TRACE("Snapshot button released.\n");
+		}
+		pdev->vmirror = ptr[0] & 0x03;
+	}
+
+	/* In case we were instructed to drop the frame, do so silently.
+	   The buffer pointers are not updated either (but the counters are reset below).
+	   */
+	if (pdev->drop_frames > 0)
+		pdev->drop_frames--;
+	else {
+		/* Check for underflow first */
+		if (fbuf->filled < pdev->frame_total_size) {
+			PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
+				       " discarded.\n", fbuf->filled);
+			pdev->vframes_error++;
+		}
+		else {
+			/* Send only once per EOF */
+			awake = 1; /* delay wake_ups */
+
+			/* Find our next frame to fill. This will always succeed, since we
+			 * nick a frame from either empty or full list, but if we had to
+			 * take it from the full list, it means a frame got dropped.
+			 */
+			if (pwc_next_fill_frame(pdev))
+				pwc_frame_dumped(pdev);
+
+		}
+	} /* !drop_frames */
+	pdev->vframe_count++;
+	return awake;
+}
 
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
@@ -620,17 +692,12 @@
 	awake = 0;
 	pdev = (struct pwc_device *)urb->context;
 	if (pdev == NULL) {
-		Err("isoc_handler() called with NULL device?!\n");
+		PWC_ERROR("isoc_handler() called with NULL device?!\n");
 		return;
 	}
-#ifdef PWC_MAGIC
-	if (pdev->magic != PWC_MAGIC) {
-		Err("isoc_handler() called with bad magic!\n");
-		return;
-	}
-#endif
+
 	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+		PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
 		return;
 	}
 	if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -645,13 +712,13 @@
 			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break;
 			case -ETIMEDOUT:	errmsg = "NAK (device does not respond)"; break;
 		}
-		Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+		PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
 		/* Give up after a number of contiguous errors on the USB bus.
 		   Appearantly something is wrong so we simulate an unplug event.
 		 */
 		if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
 		{
-			Info("Too many ISOC errors, bailing out.\n");
+			PWC_INFO("Too many ISOC errors, bailing out.\n");
 			pdev->error_status = EIO;
 			awake = 1;
 			wake_up_interruptible(&pdev->frameq);
@@ -661,7 +728,7 @@
 
 	fbuf = pdev->fill_frame;
 	if (fbuf == NULL) {
-		Err("pwc_isoc_handler without valid fill frame.\n");
+		PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
 		awake = 1;
 		goto handler_end;
 	}
@@ -688,7 +755,7 @@
 
 					/* ...copy data to frame buffer, if possible */
 					if (flen + fbuf->filled > pdev->frame_total_size) {
-						Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+						PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
 						pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
 						pdev->vframes_error++;
 					}
@@ -704,96 +771,28 @@
 				/* Shorter packet... We probably have the end of an image-frame;
 				   wake up read() process and let select()/poll() do something.
 				   Decompression is done in user time over there.
-				 */
+				   */
 				if (pdev->vsync == 2) {
-					/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
-					   frames on the USB wire after an exposure change. This conditition is
-					   however detected  in the cam and a bit is set in the header.
-					 */
-					if (pdev->type == 730) {
-						unsigned char *ptr = (unsigned char *)fbuf->data;
-
-						if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
-							Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
-							pdev->drop_frames += 2;
-							pdev->vframes_error++;
-						}
-						if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-							if (ptr[0] & 0x01)
-								Info("Snapshot button pressed.\n");
-							else
-								Info("Snapshot button released.\n");
-						}
-						if ((ptr[0] ^ pdev->vmirror) & 0x02) {
-							if (ptr[0] & 0x02)
-								Info("Image is mirrored.\n");
-							else
-								Info("Image is normal.\n");
-						}
-						pdev->vmirror = ptr[0] & 0x03;
-						/* Sometimes the trailer of the 730 is still sent as a 4 byte packet
-						   after a short frame; this condition is filtered out specifically. A 4 byte
-						   frame doesn't make sense anyway.
-						   So we get either this sequence:
-							drop_bit set -> 4 byte frame -> short frame -> good frame
-						   Or this one:
-							drop_bit set -> short frame -> good frame
-						   So we drop either 3 or 2 frames in all!
-						 */
-						if (fbuf->filled == 4)
-							pdev->drop_frames++;
+					if (pwc_rcv_short_packet(pdev, fbuf)) {
+						awake = 1;
+						fbuf = pdev->fill_frame;
 					}
-
-					/* In case we were instructed to drop the frame, do so silently.
-					   The buffer pointers are not updated either (but the counters are reset below).
-					 */
-					if (pdev->drop_frames > 0)
-						pdev->drop_frames--;
-					else {
-						/* Check for underflow first */
-						if (fbuf->filled < pdev->frame_total_size) {
-							Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
-							pdev->vframes_error++;
-						}
-						else {
-							/* Send only once per EOF */
-							awake = 1; /* delay wake_ups */
-
-							/* Find our next frame to fill. This will always succeed, since we
-							 * nick a frame from either empty or full list, but if we had to
-							 * take it from the full list, it means a frame got dropped.
-							 */
-							if (pwc_next_fill_frame(pdev)) {
-								pdev->vframes_dumped++;
-								if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
-									if (pdev->vframes_dumped < 20)
-										Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
-									if (pdev->vframes_dumped == 20)
-										Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
-								}
-							}
-							fbuf = pdev->fill_frame;
-						}
-					} /* !drop_frames */
-					pdev->vframe_count++;
 				}
 				fbuf->filled = 0;
 				fillptr = fbuf->data;
 				pdev->vsync = 1;
-			} /* .. flen < last_packet_size */
+			}
+
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
-#if PWC_DEBUG
-		/* This is normally not interesting to the user, unless you are really debugging something */
 		else {
+			/* This is normally not interesting to the user, unless
+			 * you are really debugging something */
 			static int iso_error = 0;
 			iso_error++;
 			if (iso_error < 20)
-				Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+				PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
 		}
-#endif
 	}
 
 handler_end:
@@ -803,11 +802,11 @@
 	urb->dev = pdev->udev;
 	i = usb_submit_urb(urb, GFP_ATOMIC);
 	if (i != 0)
-		Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+		PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
 
-static int pwc_isoc_init(struct pwc_device *pdev)
+int pwc_isoc_init(struct pwc_device *pdev)
 {
 	struct usb_device *udev;
 	struct urb *urb;
@@ -826,7 +825,6 @@
 	/* Get the current alternate interface, adjust packet size */
 	if (!udev->actconfig)
 		return -EFAULT;
-
 	intf = usb_ifnum_to_if(udev, 0);
 	if (intf)
 		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
@@ -836,20 +834,21 @@
 
 	/* Search video endpoint */
 	pdev->vmax_packet_size = -1;
-	for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+	for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
 		if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
 			pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
 			break;
 		}
+	}
 
 	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
-		Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+		PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
 		return -ENFILE; /* Odd error, that should be noticeable */
 	}
 
 	/* Set alternate interface */
 	ret = 0;
-	Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+	PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
 	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
 	if (ret < 0)
 		return ret;
@@ -857,12 +856,12 @@
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
 		if (urb == NULL) {
-			Err("Failed to allocate urb %d\n", i);
+			PWC_ERROR("Failed to allocate urb %d\n", i);
 			ret = -ENOMEM;
 			break;
 		}
 		pdev->sbuf[i].urb = urb;
-		Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+		PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
 	}
 	if (ret) {
 		/* De-allocate in reverse order */
@@ -899,24 +898,26 @@
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
 		if (ret)
-			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+			PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
 		else
-			Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+			PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
 	}
 
 	/* All is done... */
 	pdev->iso_init = 1;
-	Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+	PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
 	return 0;
 }
 
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
+void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
 	int i;
 
-	Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
 	if (pdev == NULL)
 		return;
+	if (pdev->iso_init == 0)
+		return;
 
 	/* Unlinking ISOC buffers one by one */
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
@@ -925,10 +926,10 @@
 		urb = pdev->sbuf[i].urb;
 		if (urb != 0) {
 			if (pdev->iso_init) {
-				Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+				PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
 				usb_kill_urb(urb);
 			}
-			Trace(TRACE_MEMORY, "Freeing URB\n");
+			PWC_DEBUG_MEMORY("Freeing URB\n");
 			usb_free_urb(urb);
 			pdev->sbuf[i].urb = NULL;
 		}
@@ -938,12 +939,12 @@
 	   is signalled by EPIPE)
 	 */
 	if (pdev->error_status && pdev->error_status != EPIPE) {
-		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+		PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
 		usb_set_interface(pdev->udev, 0, 0);
 	}
 
 	pdev->iso_init = 0;
-	Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+	PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
 }
 
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -957,18 +958,18 @@
 	/* Try to set video mode... */
 	start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
 	if (ret) {
-		Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+		PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
 		/* That failed... restore old mode (we know that worked) */
 		start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
 		if (start) {
-			Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+			PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
 		}
 	}
 	if (start == 0)
 	{
 		if (pwc_isoc_init(pdev) < 0)
 		{
-			Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+			PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
 			ret = -EAGAIN; /* let's try again, who knows if it works a second time */
 		}
 	}
@@ -976,54 +977,129 @@
 	return ret; /* Return original error code */
 }
 
+/*********
+ * sysfs
+ *********/
+static struct pwc_device *cd_to_pwc(struct class_device *cd)
+{
+	struct video_device *vdev = to_video_device(cd);
+	return video_get_drvdata(vdev);
+}
+
+static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+{
+	struct pwc_device *pdev = cd_to_pwc(class_dev);
+	return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
+}
+
+static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
+			 size_t count)
+{
+	struct pwc_device *pdev = cd_to_pwc(class_dev);
+	int pan, tilt;
+	int ret = -EINVAL;
+
+	if (strncmp(buf, "reset", 5) == 0)
+		ret = pwc_mpt_reset(pdev, 0x3);
+
+	else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
+		ret = pwc_mpt_set_angle(pdev, pan, tilt);
+
+	if (ret < 0)
+		return ret;
+	return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+			 store_pan_tilt);
+
+static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+{
+	struct pwc_device *pdev = cd_to_pwc(class_dev);
+	int status = pdev->snapshot_button_status;
+	pdev->snapshot_button_status = 0;
+	return sprintf(buf, "%d\n", status);
+}
+
+static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+			 NULL);
+
+static void pwc_create_sysfs_files(struct video_device *vdev)
+{
+	struct pwc_device *pdev = video_get_drvdata(vdev);
+	if (pdev->features & FEATURE_MOTOR_PANTILT)
+		video_device_create_file(vdev, &class_device_attr_pan_tilt);
+	video_device_create_file(vdev, &class_device_attr_button);
+}
+
+static void pwc_remove_sysfs_files(struct video_device *vdev)
+{
+	struct pwc_device *pdev = video_get_drvdata(vdev);
+	if (pdev->features & FEATURE_MOTOR_PANTILT)
+		video_device_remove_file(vdev, &class_device_attr_pan_tilt);
+	video_device_remove_file(vdev, &class_device_attr_button);
+}
+
+#if CONFIG_PWC_DEBUG
+static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
+{
+	switch(sensor_type) {
+		case 0x00:
+			return "Hyundai CMOS sensor";
+		case 0x20:
+			return "Sony CCD sensor + TDA8787";
+		case 0x2E:
+			return "Sony CCD sensor + Exas 98L59";
+		case 0x2F:
+			return "Sony CCD sensor + ADI 9804";
+		case 0x30:
+			return "Sharp CCD sensor + TDA8787";
+		case 0x3E:
+			return "Sharp CCD sensor + Exas 98L59";
+		case 0x3F:
+			return "Sharp CCD sensor + ADI 9804";
+		case 0x40:
+			return "UPA 1021 sensor";
+		case 0x100:
+			return "VGA sensor";
+		case 0x101:
+			return "PAL MR sensor";
+		default:
+			return "unknown type of sensor";
+	}
+}
+#endif
 
 /***************************************************************************/
 /* Video4Linux functions */
 
 static int pwc_video_open(struct inode *inode, struct file *file)
 {
-	int i;
+	int i, ret;
 	struct video_device *vdev = video_devdata(file);
 	struct pwc_device *pdev;
 
-	Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+	PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev == NULL)
 		BUG();
-	if (pdev->vopen)
+	if (pdev->vopen) {
+		PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
 		return -EBUSY;
+	}
 
 	down(&pdev->modlock);
 	if (!pdev->usb_init) {
-		Trace(TRACE_OPEN, "Doing first time initialization.\n");
+		PWC_DEBUG_OPEN("Doing first time initialization.\n");
 		pdev->usb_init = 1;
 
-		if (pwc_trace & TRACE_OPEN)
+		/* Query sensor type */
+		ret = pwc_get_cmos_sensor(pdev, &i);
+		if (ret >= 0)
 		{
-			/* Query sensor type */
-			const char *sensor_type = NULL;
-			int ret;
-
-			ret = pwc_get_cmos_sensor(pdev, &i);
-			if (ret >= 0)
-			{
-				switch(i) {
-				case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
-				case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
-				case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
-				case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
-				case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
-				case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
-				case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
-				case 0x40:  sensor_type = "UPA 1021 sensor"; break;
-				case 0x100: sensor_type = "VGA sensor"; break;
-				case 0x101: sensor_type = "PAL MR sensor"; break;
-				default:    sensor_type = "unknown type of sensor"; break;
-				}
-			}
-			if (sensor_type != NULL)
-				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+			PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+					pdev->vdev->name,
+					pwc_sensor_type_to_string(i), i);
 		}
 	}
 
@@ -1031,34 +1107,32 @@
 	if (power_save) {
 		i = pwc_camera_power(pdev, 1);
 		if (i < 0)
-			Info("Failed to restore power to the camera! (%d)\n", i);
+			PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
 	}
 	/* Set LED on/off time */
 	if (pwc_set_leds(pdev, led_on, led_off) < 0)
-		Info("Failed to set LED on/off time.\n");
+		PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
 
 	pwc_construct(pdev); /* set min/max sizes correct */
 
 	/* So far, so good. Allocate memory. */
 	i = pwc_allocate_buffers(pdev);
 	if (i < 0) {
-		Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+		PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
+		pwc_free_buffers(pdev);
 		up(&pdev->modlock);
 		return i;
 	}
 
 	/* Reset buffers & parameters */
 	pwc_reset_buffers(pdev);
-	for (i = 0; i < default_mbufs; i++)
+	for (i = 0; i < pwc_mbufs; i++)
 		pdev->image_used[i] = 0;
 	pdev->vframe_count = 0;
 	pdev->vframes_dumped = 0;
 	pdev->vframes_error = 0;
 	pdev->visoc_errors = 0;
 	pdev->error_status = 0;
-#if PWC_DEBUG
-	pdev->sequence = 0;
-#endif
 	pwc_construct(pdev); /* set min/max sizes correct */
 
 	/* Set some defaults */
@@ -1070,29 +1144,44 @@
 	 */
 	i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
 	if (i)	{
-		Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
-		if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
-			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+		unsigned int default_resolution;
+		PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
+		if (pdev->type>= 730)
+			default_resolution = PSZ_QSIF;
 		else
-			i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+			default_resolution = PSZ_QCIF;
+
+		i = pwc_set_video_mode(pdev,
+				       pwc_image_sizes[default_resolution].x,
+				       pwc_image_sizes[default_resolution].y,
+				       10,
+				       pdev->vcompression,
+				       0);
 	}
 	if (i) {
-		Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+		PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
+		pwc_free_buffers(pdev);
 		up(&pdev->modlock);
 		return i;
 	}
 
 	i = pwc_isoc_init(pdev);
 	if (i) {
-		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+		PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
+		pwc_isoc_cleanup(pdev);
+		pwc_free_buffers(pdev);
 		up(&pdev->modlock);
 		return i;
 	}
 
+	/* Initialize the webcam to sane value */
+	pwc_set_brightness(pdev, 0x7fff);
+	pwc_set_agc(pdev, 1, 0);
+
 	pdev->vopen++;
 	file->private_data = vdev;
 	up(&pdev->modlock);
-	Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+	PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
 	return 0;
 }
 
@@ -1103,35 +1192,23 @@
 	struct pwc_device *pdev;
 	int i;
 
-	Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+	PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev->vopen == 0)
-		Info("video_close() called on closed device?\n");
+		PWC_DEBUG_MODULE("video_close() called on closed device?\n");
 
 	/* Dump statistics, but only if a reasonable amount of frames were
 	   processed (to prevent endless log-entries in case of snap-shot
 	   programs)
 	 */
 	if (pdev->vframe_count > 20)
-		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+		PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-	switch (pdev->type)
-	 {
-	  case 675:
-	  case 680:
-	  case 690:
-	  case 720:
-	  case 730:
-	  case 740:
-	  case 750:
-/*	    pwc_dec23_exit();	*//* Timon & Kiara */
-	    break;
-	  case 645:
-	  case 646:
-/*	    pwc_dec1_exit(); */
-	    break;
-	 }
+	if (DEVICE_USE_CODEC1(pdev->type))
+	    pwc_dec1_exit();
+	else
+	    pwc_dec23_exit();
 
 	pwc_isoc_cleanup(pdev);
 	pwc_free_buffers(pdev);
@@ -1140,15 +1217,15 @@
 	if (pdev->error_status != EPIPE) {
 		/* Turn LEDs off */
 		if (pwc_set_leds(pdev, 0, 0) < 0)
-			Info("Failed to set LED on/off time.\n");
+			PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
 		if (power_save) {
 			i = pwc_camera_power(pdev, 0);
 			if (i < 0)
-				Err("Failed to power down camera (%d)\n", i);
+				PWC_ERROR("Failed to power down camera (%d)\n", i);
 		}
 	}
-	pdev->vopen = 0;
-	Trace(TRACE_OPEN, "<< video_close()\n");
+	pdev->vopen--;
+	PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
 	return 0;
 }
 
@@ -1164,7 +1241,7 @@
 		device is tricky anyhow.
  */
 
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
 			  size_t count, loff_t *ppos)
 {
 	struct video_device *vdev = file->private_data;
@@ -1172,8 +1249,10 @@
 	int noblock = file->f_flags & O_NONBLOCK;
 	DECLARE_WAITQUEUE(wait, current);
 	int bytes_to_read;
+	void *image_buffer_addr;
 
-	Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+	PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
+			vdev, buf, count);
 	if (vdev == NULL)
 		return -EFAULT;
 	pdev = vdev->priv;
@@ -1214,16 +1293,19 @@
 			return -EFAULT;
 	}
 
-	Trace(TRACE_READ, "Copying data to user space.\n");
+	PWC_DEBUG_READ("Copying data to user space.\n");
 	if (pdev->vpalette == VIDEO_PALETTE_RAW)
-		bytes_to_read = pdev->frame_size;
+		bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
 	else
 		bytes_to_read = pdev->view.size;
 
 	/* copy bytes to user space; we allow for partial reads */
 	if (count + pdev->image_read_pos > bytes_to_read)
 		count = bytes_to_read - pdev->image_read_pos;
-	if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+	image_buffer_addr = pdev->image_data;
+	image_buffer_addr += pdev->images[pdev->fill_image].offset;
+	image_buffer_addr += pdev->image_read_pos;
+	if (copy_to_user(buf, image_buffer_addr, count))
 		return -EFAULT;
 	pdev->image_read_pos += count;
 	if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
@@ -1253,370 +1335,56 @@
 	return 0;
 }
 
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
-			      unsigned int cmd, void *arg)
-{
-	struct video_device *vdev = file->private_data;
-	struct pwc_device *pdev;
-	DECLARE_WAITQUEUE(wait, current);
-
-	if (vdev == NULL)
-		return -EFAULT;
-	pdev = vdev->priv;
-	if (pdev == NULL)
-		return -EFAULT;
-
-	switch (cmd) {
-		/* Query cabapilities */
-		case VIDIOCGCAP:
-		{
-			struct video_capability *caps = arg;
-
-			strcpy(caps->name, vdev->name);
-			caps->type = VID_TYPE_CAPTURE;
-			caps->channels = 1;
-			caps->audios = 1;
-			caps->minwidth  = pdev->view_min.x;
-			caps->minheight = pdev->view_min.y;
-			caps->maxwidth  = pdev->view_max.x;
-			caps->maxheight = pdev->view_max.y;
-			break;
-		}
-
-		/* Channel functions (simulate 1 channel) */
-		case VIDIOCGCHAN:
-		{
-			struct video_channel *v = arg;
-
-			if (v->channel != 0)
-				return -EINVAL;
-			v->flags = 0;
-			v->tuners = 0;
-			v->type = VIDEO_TYPE_CAMERA;
-			strcpy(v->name, "Webcam");
-			return 0;
-		}
-
-		case VIDIOCSCHAN:
-		{
-			/* The spec says the argument is an integer, but
-			   the bttv driver uses a video_channel arg, which
-			   makes sense becasue it also has the norm flag.
-			 */
-			struct video_channel *v = arg;
-			if (v->channel != 0)
-				return -EINVAL;
-			return 0;
-		}
-
-
-		/* Picture functions; contrast etc. */
-		case VIDIOCGPICT:
-		{
-			struct video_picture *p = arg;
-			int val;
-
-			val = pwc_get_brightness(pdev);
-			if (val >= 0)
-				p->brightness = val;
-			else
-				p->brightness = 0xffff;
-			val = pwc_get_contrast(pdev);
-			if (val >= 0)
-				p->contrast = val;
-			else
-				p->contrast = 0xffff;
-			/* Gamma, Whiteness, what's the difference? :) */
-			val = pwc_get_gamma(pdev);
-			if (val >= 0)
-				p->whiteness = val;
-			else
-				p->whiteness = 0xffff;
-			val = pwc_get_saturation(pdev);
-			if (val >= 0)
-				p->colour = val;
-			else
-				p->colour = 0xffff;
-			p->depth = 24;
-			p->palette = pdev->vpalette;
-			p->hue = 0xFFFF; /* N/A */
-			break;
-		}
-
-		case VIDIOCSPICT:
-		{
-			struct video_picture *p = arg;
-			/*
-			 *	FIXME:	Suppose we are mid read
-				ANSWER: No problem: the firmware of the camera
-					can handle brightness/contrast/etc
-					changes at _any_ time, and the palette
-					is used exactly once in the uncompress
-					routine.
-			 */
-			pwc_set_brightness(pdev, p->brightness);
-			pwc_set_contrast(pdev, p->contrast);
-			pwc_set_gamma(pdev, p->whiteness);
-			pwc_set_saturation(pdev, p->colour);
-			if (p->palette && p->palette != pdev->vpalette) {
-				switch (p->palette) {
-					case VIDEO_PALETTE_YUV420P:
-					case VIDEO_PALETTE_RAW:
-						pdev->vpalette = p->palette;
-						return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-						break;
-					default:
-						return -EINVAL;
-						break;
-				}
-			}
-			break;
-		}
-
-		/* Window/size parameters */
-		case VIDIOCGWIN:
-		{
-			struct video_window *vw = arg;
-
-			vw->x = 0;
-			vw->y = 0;
-			vw->width = pdev->view.x;
-			vw->height = pdev->view.y;
-			vw->chromakey = 0;
-			vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
-				   (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
-			break;
-		}
-
-		case VIDIOCSWIN:
-		{
-			struct video_window *vw = arg;
-			int fps, snapshot, ret;
-
-			fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
-			snapshot = vw->flags & PWC_FPS_SNAPSHOT;
-			if (fps == 0)
-				fps = pdev->vframes;
-			if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
-				return 0;
-			ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
-			if (ret)
-				return ret;
-			break;
-		}
-
-		/* We don't have overlay support (yet) */
-		case VIDIOCGFBUF:
-		{
-			struct video_buffer *vb = arg;
-
-			memset(vb,0,sizeof(*vb));
-			break;
-		}
-
-		/* mmap() functions */
-		case VIDIOCGMBUF:
-		{
-			/* Tell the user program how much memory is needed for a mmap() */
-			struct video_mbuf *vm = arg;
-			int i;
-
-			memset(vm, 0, sizeof(*vm));
-			vm->size = default_mbufs * pdev->len_per_image;
-			vm->frames = default_mbufs; /* double buffering should be enough for most applications */
-			for (i = 0; i < default_mbufs; i++)
-				vm->offsets[i] = i * pdev->len_per_image;
-			break;
-		}
-
-		case VIDIOCMCAPTURE:
-		{
-			/* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
-			struct video_mmap *vm = arg;
-
-			Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
-			if (vm->frame < 0 || vm->frame >= default_mbufs)
-				return -EINVAL;
-
-			/* xawtv is nasty. It probes the available palettes
-			   by setting a very small image size and trying
-			   various palettes... The driver doesn't support
-			   such small images, so I'm working around it.
-			 */
-			if (vm->format)
-			{
-				switch (vm->format)
-				{
-					case VIDEO_PALETTE_YUV420P:
-					case VIDEO_PALETTE_RAW:
-						break;
-					default:
-						return -EINVAL;
-						break;
-				}
-			}
-
-			if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
-			    (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
-				int ret;
-
-				Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
-				ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-				if (ret)
-					return ret;
-			} /* ... size mismatch */
-
-			/* FIXME: should we lock here? */
-			if (pdev->image_used[vm->frame])
-				return -EBUSY;	/* buffer wasn't available. Bummer */
-			pdev->image_used[vm->frame] = 1;
-
-			/* Okay, we're done here. In the SYNC call we wait until a
-			   frame comes available, then expand image into the given
-			   buffer.
-			   In contrast to the CPiA cam the Philips cams deliver a
-			   constant stream, almost like a grabber card. Also,
-			   we have separate buffers for the rawdata and the image,
-			   meaning we can nearly always expand into the requested buffer.
-			 */
-			Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
-			break;
-		}
-
-		case VIDIOCSYNC:
-		{
-			/* The doc says: "Whenever a buffer is used it should
-			   call VIDIOCSYNC to free this frame up and continue."
-
-			   The only odd thing about this whole procedure is
-			   that MCAPTURE flags the buffer as "in use", and
-			   SYNC immediately unmarks it, while it isn't
-			   after SYNC that you know that the buffer actually
-			   got filled! So you better not start a CAPTURE in
-			   the same frame immediately (use double buffering).
-			   This is not a problem for this cam, since it has
-			   extra intermediate buffers, but a hardware
-			   grabber card will then overwrite the buffer
-			   you're working on.
-			 */
-			int *mbuf = arg;
-			int ret;
-
-			Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
-			/* bounds check */
-			if (*mbuf < 0 || *mbuf >= default_mbufs)
-				return -EINVAL;
-			/* check if this buffer was requested anyway */
-			if (pdev->image_used[*mbuf] == 0)
-				return -EINVAL;
-
-			/* Add ourselves to the frame wait-queue.
-
-			   FIXME: needs auditing for safety.
-			   QUESTION: In what respect? I think that using the
-				     frameq is safe now.
-			 */
-			add_wait_queue(&pdev->frameq, &wait);
-			while (pdev->full_frames == NULL) {
-				if (pdev->error_status) {
-					remove_wait_queue(&pdev->frameq, &wait);
-					set_current_state(TASK_RUNNING);
-					return -pdev->error_status;
-				}
-
-				if (signal_pending(current)) {
-					remove_wait_queue(&pdev->frameq, &wait);
-					set_current_state(TASK_RUNNING);
-					return -ERESTARTSYS;
-				}
-				schedule();
-				set_current_state(TASK_INTERRUPTIBLE);
-			}
-			remove_wait_queue(&pdev->frameq, &wait);
-			set_current_state(TASK_RUNNING);
-
-			/* The frame is ready. Expand in the image buffer
-			   requested by the user. I don't care if you
-			   mmap() 5 buffers and request data in this order:
-			   buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
-			   Grabber hardware may not be so forgiving.
-			 */
-			Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
-			pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
-			/* Decompress, etc */
-			ret = pwc_handle_frame(pdev);
-			pdev->image_used[*mbuf] = 0;
-			if (ret)
-				return -EFAULT;
-			break;
-		}
-
-		case VIDIOCGAUDIO:
-		{
-			struct video_audio *v = arg;
-
-			strcpy(v->name, "Microphone");
-			v->audio = -1; /* unknown audio minor */
-			v->flags = 0;
-			v->mode = VIDEO_SOUND_MONO;
-			v->volume = 0;
-			v->bass = 0;
-			v->treble = 0;
-			v->balance = 0x8000;
-			v->step = 1;
-			break;
-		}
-
-		case VIDIOCSAUDIO:
-		{
-			/* Dummy: nothing can be set */
-			break;
-		}
-
-		case VIDIOCGUNIT:
-		{
-			struct video_unit *vu = arg;
-
-			vu->video = pdev->vdev->minor & 0x3F;
-			vu->audio = -1; /* not known yet */
-			vu->vbi = -1;
-			vu->radio = -1;
-			vu->teletext = -1;
-			break;
-		}
-		default:
-			return pwc_ioctl(pdev, cmd, arg);
-	} /* ..switch */
-	return 0;
-}
-
 static int pwc_video_ioctl(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg)
 {
 	return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
 }
 
-
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct video_device *vdev = file->private_data;
 	struct pwc_device *pdev;
-	unsigned long start = vma->vm_start;
-	unsigned long size  = vma->vm_end-vma->vm_start;
-	unsigned long page, pos;
+	unsigned long start;
+	unsigned long size;
+	unsigned long page, pos = 0;
+	int index;
 
-	Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+	PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
 	pdev = vdev->priv;
+	size = vma->vm_end - vma->vm_start;
+	start = vma->vm_start;
 
-	vma->vm_flags |= VM_IO;
+	/* Find the idx buffer for this mapping */
+	for (index = 0; index < pwc_mbufs; index++) {
+		pos = pdev->images[index].offset;
+		if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+	if (index == MAX_IMAGES)
+		return -EINVAL;
+	if (index == 0) {
+		/*
+		 * Special case for v4l1. In v4l1, we map only one big buffer,
+		 * but in v4l2 each buffer is mapped
+		 */
+		unsigned long total_size;
+		total_size = pwc_mbufs * pdev->len_per_image;
+		if (size != pdev->len_per_image && size != total_size) {
+			PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
+				   size, pdev->len_per_image, total_size);
+			return -EINVAL;
+		}
+	} else if (size > pdev->len_per_image)
+		return -EINVAL;
 
-	pos = (unsigned long)pdev->image_data;
+	vma->vm_flags |= VM_IO;	/* from 2.6.9-acX */
+
+	pos += (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
-
 		start += PAGE_SIZE;
 		pos += PAGE_SIZE;
 		if (size > PAGE_SIZE)
@@ -1624,7 +1392,6 @@
 		else
 			size = 0;
 	}
-
 	return 0;
 }
 
@@ -1645,10 +1412,12 @@
 	int video_nr = -1; /* default: use next available device */
 	char serial_number[30], *name;
 
+	vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+	product_id = le16_to_cpu(udev->descriptor.idProduct);
+
 	/* Check if we can handle this device */
-	Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
-		le16_to_cpu(udev->descriptor.idVendor),
-		le16_to_cpu(udev->descriptor.idProduct),
+	PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
+		vendor_id, product_id,
 		intf->altsetting->desc.bInterfaceNumber);
 
 	/* the interfaces are probed one by one. We are only interested in the
@@ -1658,61 +1427,63 @@
 	if (intf->altsetting->desc.bInterfaceNumber > 0)
 		return -ENODEV;
 
-	vendor_id = le16_to_cpu(udev->descriptor.idVendor);
-	product_id = le16_to_cpu(udev->descriptor.idProduct);
-
 	if (vendor_id == 0x0471) {
 		switch (product_id) {
 		case 0x0302:
-			Info("Philips PCA645VC USB webcam detected.\n");
+			PWC_INFO("Philips PCA645VC USB webcam detected.\n");
 			name = "Philips 645 webcam";
 			type_id = 645;
 			break;
 		case 0x0303:
-			Info("Philips PCA646VC USB webcam detected.\n");
+			PWC_INFO("Philips PCA646VC USB webcam detected.\n");
 			name = "Philips 646 webcam";
 			type_id = 646;
 			break;
 		case 0x0304:
-			Info("Askey VC010 type 2 USB webcam detected.\n");
+			PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
 			name = "Askey VC010 webcam";
 			type_id = 646;
 			break;
 		case 0x0307:
-			Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
 			name = "Philips 675 webcam";
 			type_id = 675;
 			break;
 		case 0x0308:
-			Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
 			name = "Philips 680 webcam";
 			type_id = 680;
 			break;
 		case 0x030C:
-			Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
 			name = "Philips 690 webcam";
 			type_id = 690;
 			break;
 		case 0x0310:
-			Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
 			name = "Philips 730 webcam";
 			type_id = 730;
 			break;
 		case 0x0311:
-			Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
 			name = "Philips 740 webcam";
 			type_id = 740;
 			break;
 		case 0x0312:
-			Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
 			name = "Philips 750 webcam";
 			type_id = 750;
 			break;
 		case 0x0313:
-			Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+			PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
 			name = "Philips 720K/40 webcam";
 			type_id = 720;
 			break;
+		case 0x0329:
+			PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
+			name = "Philips SPC 900NC webcam";
+			type_id = 720;
+			break;
 		default:
 			return -ENODEV;
 			break;
@@ -1721,7 +1492,7 @@
 	else if (vendor_id == 0x069A) {
 		switch(product_id) {
 		case 0x0001:
-			Info("Askey VC010 type 1 USB webcam detected.\n");
+			PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
 			name = "Askey VC010 webcam";
 			type_id = 645;
 			break;
@@ -1733,32 +1504,33 @@
 	else if (vendor_id == 0x046d) {
 		switch(product_id) {
 		case 0x08b0:
-			Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+			PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
 			name = "Logitech QuickCam Pro 3000";
 			type_id = 740; /* CCD sensor */
 			break;
 		case 0x08b1:
-			Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+			PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
 			name = "Logitech QuickCam Notebook Pro";
 			type_id = 740; /* CCD sensor */
 			break;
 		case 0x08b2:
-			Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+			PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
 			name = "Logitech QuickCam Pro 4000";
 			type_id = 740; /* CCD sensor */
 			break;
 		case 0x08b3:
-			Info("Logitech QuickCam Zoom USB webcam detected.\n");
+			PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
 			name = "Logitech QuickCam Zoom";
 			type_id = 740; /* CCD sensor */
 			break;
 		case 0x08B4:
-			Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+			PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
 			name = "Logitech QuickCam Zoom";
 			type_id = 740; /* CCD sensor */
+			power_save = 1;
 			break;
 		case 0x08b5:
-			Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+			PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
 			name = "Logitech QuickCam Orbit";
 			type_id = 740; /* CCD sensor */
 			features |= FEATURE_MOTOR_PANTILT;
@@ -1766,7 +1538,7 @@
 		case 0x08b6:
 		case 0x08b7:
 		case 0x08b8:
-			Info("Logitech QuickCam detected (reserved ID).\n");
+			PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
 			name = "Logitech QuickCam (res.)";
 			type_id = 730; /* Assuming CMOS */
 			break;
@@ -1782,15 +1554,20 @@
 		 */
 		switch(product_id) {
 		case 0x9000:
-			Info("Samsung MPC-C10 USB webcam detected.\n");
+			PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
 			name = "Samsung MPC-C10";
 			type_id = 675;
 			break;
 		case 0x9001:
-			Info("Samsung MPC-C30 USB webcam detected.\n");
+			PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
 			name = "Samsung MPC-C30";
 			type_id = 675;
 			break;
+		case 0x9002:
+			PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
+			name = "Samsung MPC-C30";
+			type_id = 740;
+			break;
 		default:
 			return -ENODEV;
 			break;
@@ -1799,12 +1576,12 @@
 	else if (vendor_id == 0x041e) {
 		switch(product_id) {
 		case 0x400c:
-			Info("Creative Labs Webcam 5 detected.\n");
+			PWC_INFO("Creative Labs Webcam 5 detected.\n");
 			name = "Creative Labs Webcam 5";
 			type_id = 730;
 			break;
 		case 0x4011:
-			Info("Creative Labs Webcam Pro Ex detected.\n");
+			PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
 			name = "Creative Labs Webcam Pro Ex";
 			type_id = 740;
 			break;
@@ -1816,7 +1593,7 @@
 	else if (vendor_id == 0x04cc) {
 		switch(product_id) {
 		case 0x8116:
-			Info("Sotec Afina Eye USB webcam detected.\n");
+			PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
 			name = "Sotec Afina Eye";
 			type_id = 730;
 			break;
@@ -1829,7 +1606,7 @@
 		switch(product_id) {
 		case 0x8116:
 			/* This is essentially the same cam as the Sotec Afina Eye */
-			Info("AME Co. Afina Eye USB webcam detected.\n");
+			PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
 			name = "AME Co. Afina Eye";
 			type_id = 750;
 			break;
@@ -1842,12 +1619,12 @@
 	else if (vendor_id == 0x0d81) {
 		switch(product_id) {
 		case 0x1900:
-			Info("Visionite VCS-UC300 USB webcam detected.\n");
+			PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
 			name = "Visionite VCS-UC300";
 			type_id = 740; /* CCD sensor */
 			break;
 		case 0x1910:
-			Info("Visionite VCS-UM100 USB webcam detected.\n");
+			PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
 			name = "Visionite VCS-UM100";
 			type_id = 730; /* CMOS sensor */
 			break;
@@ -1861,15 +1638,15 @@
 
 	memset(serial_number, 0, 30);
 	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
-	Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+	PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
 
 	if (udev->descriptor.bNumConfigurations > 1)
-		Info("Warning: more than 1 configuration available.\n");
+		PWC_WARNING("Warning: more than 1 configuration available.\n");
 
 	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
 	pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
 	if (pdev == NULL) {
-		Err("Oops, could not allocate memory for pwc_device.\n");
+		PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
 		return -ENOMEM;
 	}
 	pdev->type = type_id;
@@ -1900,17 +1677,18 @@
 	pdev->vdev = video_device_alloc();
 	if (pdev->vdev == 0)
 	{
-		Err("Err, cannot allocate video_device struture. Failing probe.");
+		PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
 		kfree(pdev);
 		return -ENOMEM;
 	}
 	memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+	pdev->vdev->dev = &(udev->dev);
 	strcpy(pdev->vdev->name, name);
 	pdev->vdev->owner = THIS_MODULE;
 	video_set_drvdata(pdev->vdev, pdev);
 
 	pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
-	Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+	PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
 
 	/* Now search device_hint[] table for a match, so we can hint a node number. */
 	for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
@@ -1918,10 +1696,10 @@
 		     (device_hint[hint].pdev == NULL)) {
 			/* so far, so good... try serial number */
 			if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
-			    	/* match! */
-			    	video_nr = device_hint[hint].device_node;
-			    	Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
-			    	break;
+				/* match! */
+				video_nr = device_hint[hint].device_node;
+				PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
+				break;
 			}
 		}
 	}
@@ -1929,21 +1707,27 @@
 	pdev->vdev->release = video_device_release;
 	i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
 	if (i < 0) {
-		Err("Failed to register as video device (%d).\n", i);
+		PWC_ERROR("Failed to register as video device (%d).\n", i);
 		video_device_release(pdev->vdev); /* Drip... drip... drip... */
 		kfree(pdev); /* Oops, no memory leaks please */
 		return -EIO;
 	}
 	else {
-		Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+		PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
 	}
 
 	/* occupy slot */
 	if (hint < MAX_DEV_HINTS)
 		device_hint[hint].pdev = pdev;
 
-	Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+	PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
 	usb_set_intfdata (intf, pdev);
+	pwc_create_sysfs_files(pdev->vdev);
+
+	/* Set the leds off */
+	pwc_set_leds(pdev, 0, 0);
+	pwc_camera_power(pdev, 0);
+
 	return 0;
 }
 
@@ -1957,27 +1741,21 @@
 	pdev = usb_get_intfdata (intf);
 	usb_set_intfdata (intf, NULL);
 	if (pdev == NULL) {
-		Err("pwc_disconnect() Called without private pointer.\n");
+		PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
 		goto disconnect_out;
 	}
 	if (pdev->udev == NULL) {
-		Err("pwc_disconnect() already called for %p\n", pdev);
+		PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
 		goto disconnect_out;
 	}
 	if (pdev->udev != interface_to_usbdev(intf)) {
-		Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+		PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
 		goto disconnect_out;
 	}
-#ifdef PWC_MAGIC
-	if (pdev->magic != PWC_MAGIC) {
-		Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
-		goto disconnect_out;
-	}
-#endif
 
 	/* We got unplugged; this is signalled by an EPIPE error code */
 	if (pdev->vopen) {
-		Info("Disconnected while webcam is in use!\n");
+		PWC_INFO("Disconnected while webcam is in use!\n");
 		pdev->error_status = EPIPE;
 	}
 
@@ -1987,7 +1765,8 @@
 	while (pdev->vopen)
 		schedule();
 	/* Device is now closed, so we can safely unregister it */
-	Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+	PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+	pwc_remove_sysfs_files(pdev->vdev);
 	video_unregister_device(pdev->vdev);
 
 	/* Free memory (don't set pdev to 0 just yet) */
@@ -2021,58 +1800,64 @@
  * Initialization code & module stuff
  */
 
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
+static char *size;
+static int fps;
+static int fbufs;
+static int mbufs;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
+static int leds_nargs;
+static char *dev_hint[MAX_DEV_HINTS];
+static int dev_hint_nargs;
 
-module_param_string(size, size, sizeof(size), 0);
+module_param(size, charp, 0444);
+module_param(fps, int, 0444);
+module_param(fbufs, int, 0444);
+module_param(mbufs, int, 0444);
+#if CONFIG_PWC_DEBUG
+module_param_named(trace, pwc_trace, int, 0644);
+#endif
+module_param(power_save, int, 0444);
+module_param(compression, int, 0444);
+module_param_array(leds, int, &leds_nargs, 0444);
+module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
+
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
 MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
 MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
 MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
 MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
 MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
 MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("pwcx");
+MODULE_VERSION( PWC_VERSION );
 
 static int __init usb_pwc_init(void)
 {
 	int i, sz;
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
-	Info("Philips webcam module version " PWC_VERSION " loaded.\n");
-	Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
-	Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
-	Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+	PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
+	PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+	PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+	PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
 	if (fps) {
 		if (fps < 4 || fps > 30) {
-			Err("Framerate out of bounds (4-30).\n");
+			PWC_ERROR("Framerate out of bounds (4-30).\n");
 			return -EINVAL;
 		}
 		default_fps = fps;
-		Info("Default framerate set to %d.\n", default_fps);
+		PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
 	}
 
-	if (size[0]) {
+	if (size) {
 		/* string; try matching with array */
 		for (sz = 0; sz < PSZ_MAX; sz++) {
 			if (!strcmp(sizenames[sz], size)) { /* Found! */
@@ -2081,41 +1866,42 @@
 			}
 		}
 		if (sz == PSZ_MAX) {
-			Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+			PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
 			return -EINVAL;
 		}
-		Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+		PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
 	}
 	if (mbufs) {
 		if (mbufs < 1 || mbufs > MAX_IMAGES) {
-			Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+			PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
 			return -EINVAL;
 		}
-		default_mbufs = mbufs;
-		Info("Number of image buffers set to %d.\n", default_mbufs);
+		pwc_mbufs = mbufs;
+		PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
 	}
 	if (fbufs) {
 		if (fbufs < 2 || fbufs > MAX_FRAMES) {
-			Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+			PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
 			return -EINVAL;
 		}
 		default_fbufs = fbufs;
-		Info("Number of frame buffers set to %d.\n", default_fbufs);
+		PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
 	}
-	if (trace >= 0) {
-		Info("Trace options: 0x%04x\n", trace);
-		pwc_trace = trace;
+#if CONFIG_PWC_DEBUG
+	if (pwc_trace >= 0) {
+		PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
 	}
+#endif
 	if (compression >= 0) {
 		if (compression > 3) {
-			Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+			PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
 			return -EINVAL;
 		}
 		pwc_preferred_compression = compression;
-		Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+		PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
 	}
 	if (power_save)
-		Info("Enabling power save on open/close.\n");
+		PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
 	if (leds[0] >= 0)
 		led_on = leds[0];
 	if (leds[1] >= 0)
@@ -2146,14 +1932,14 @@
 				dot++;
 			/* Few sanity checks */
 			if (*dot != '\0' && dot > colon) {
-				Err("Malformed camera hint: the colon must be after the dot.\n");
+				PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
 				return -EINVAL;
 			}
 
 			if (*colon == '\0') {
 				/* No colon */
 				if (*dot != '\0') {
-					Err("Malformed camera hint: no colon + device node given.\n");
+					PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
 					return -EINVAL;
 				}
 				else {
@@ -2178,28 +1964,27 @@
 					device_hint[i].serial_number[k] = '\0';
 				}
 			}
-#if PWC_DEBUG
-			Debug("device_hint[%d]:\n", i);
-			Debug("  type    : %d\n", device_hint[i].type);
-			Debug("  serial# : %s\n", device_hint[i].serial_number);
-			Debug("  node    : %d\n", device_hint[i].device_node);
-#endif
+			PWC_TRACE("device_hint[%d]:\n", i);
+			PWC_TRACE("  type    : %d\n", device_hint[i].type);
+			PWC_TRACE("  serial# : %s\n", device_hint[i].serial_number);
+			PWC_TRACE("  node    : %d\n", device_hint[i].device_node);
 		}
 		else
 			device_hint[i].type = 0; /* not filled */
 	} /* ..for MAX_DEV_HINTS */
 
-	Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+	PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
 	return usb_register(&pwc_driver);
 }
 
 static void __exit usb_pwc_exit(void)
 {
-	Trace(TRACE_MODULE, "Deregistering driver.\n");
+	PWC_DEBUG_MODULE("Deregistering driver.\n");
 	usb_deregister(&pwc_driver);
-	Info("Philips webcam module removed.\n");
+	PWC_INFO("Philips webcam module removed.\n");
 }
 
 module_init(usb_pwc_init);
 module_exit(usb_pwc_exit);
 
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c
index 4c96037..fec39cc 100644
--- a/drivers/media/video/pwc/pwc-kiara.c
+++ b/drivers/media/video/pwc/pwc-kiara.c
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -316,3 +316,576 @@
    },
 };
 
+
+/*
+ * Rom table for kiara chips
+ *
+ * 32 roms tables (one for each resolution ?)
+ *  2 tables per roms (one for each passes) (Y, and U&V)
+ * 128 bytes per passes
+ */
+
+const unsigned int KiaraRomTable [8][2][16][8] =
+{
+ { /* version 0 */
+  { /* version 0, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009292,0x00009292,0x00009493,0x000124db},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x0000a493,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x000124db,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 0, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000001,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009292,
+    0x00009492,0x00009493,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000126dc,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 1 */
+  { /* version 1, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 1, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000049,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 2 */
+  { /* version 2, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x0000a49b},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 2, passes 1 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x0000a49b,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 3 */
+  { /* version 3, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 3, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 4 */
+  { /* version 4, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 4, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 5 */
+  { /* version 5, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 5, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x00009252,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 6 */
+  { /* version 6, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 6, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 7 */
+  { /* version 7, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 7, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ }
+};
+
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
index 12929ab..0bdb225 100644
--- a/drivers/media/video/pwc/pwc-kiara.h
+++ b/drivers/media/video/pwc/pwc-kiara.h
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -27,7 +27,7 @@
 #ifndef PWC_KIARA_H
 #define PWC_KIARA_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Kiara_table_entry
 {
@@ -37,8 +37,8 @@
 	unsigned char mode[12];		/* precomputed mode settings for cam */
 };
 
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const unsigned int KiaraRomTable[8][2][16][8];
 
 #endif
 
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
index 58fe797..589c687 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/video/pwc/pwc-misc.c
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    Various miscellaneous functions and tables.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -24,18 +24,17 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#include <linux/slab.h>
 
 #include "pwc.h"
 
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
 {
-	{ 128,  96, 0 },
-	{ 160, 120, 0 },
-	{ 176, 144, 0 },
-	{ 320, 240, 0 },
-	{ 352, 288, 0 },
-	{ 640, 480, 0 },
+	{ 128,  96, 0 }, /* sqcif */
+	{ 160, 120, 0 }, /* qsif */
+	{ 176, 144, 0 }, /* qcif */
+	{ 320, 240, 0 }, /* sif */
+	{ 352, 288, 0 }, /* cif */
+	{ 640, 480, 0 }, /* vga */
 };
 
 /* x,y -> PSZ_ */
@@ -52,7 +51,7 @@
 	{
 		if (width > pdev->abs_max.x || height > pdev->abs_max.y)
 		{
-			Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+			PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
 			return -1;
 		}
 	}
@@ -60,7 +59,7 @@
 	{
 		if (width > pdev->view_max.x || height > pdev->view_max.y)
 		{
-			Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+			PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
 			return -1;
 		}
 	}
@@ -81,9 +80,8 @@
 /* initialize variables depending on type and decompressor*/
 void pwc_construct(struct pwc_device *pdev)
 {
-	switch(pdev->type) {
-	case 645:
-	case 646:
+	if (DEVICE_USE_CODEC1(pdev->type)) {
+
 		pdev->view_min.x = 128;
 		pdev->view_min.y =  96;
 		pdev->view_max.x = 352;
@@ -95,10 +93,23 @@
 		pdev->vendpoint = 4;
 		pdev->frame_header_size = 0;
 		pdev->frame_trailer_size = 0;
-		break;
-	case 675:
-	case 680:
-	case 690:
+
+	} else if (DEVICE_USE_CODEC3(pdev->type)) {
+
+		pdev->view_min.x = 160;
+		pdev->view_min.y = 120;
+		pdev->view_max.x = 640;
+		pdev->view_max.y = 480;
+		pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+		pdev->abs_max.x = 640;
+		pdev->abs_max.y = 480;
+		pdev->vcinterface = 3;
+		pdev->vendpoint = 5;
+		pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+		pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+
+	} else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
+
 		pdev->view_min.x = 128;
 		pdev->view_min.y =  96;
 		/* Anthill bug #38: PWC always reports max size, even without PWCX */
@@ -111,30 +122,12 @@
 		pdev->vendpoint = 4;
 		pdev->frame_header_size = 0;
 		pdev->frame_trailer_size = 0;
-		break;
-	case 720:
-	case 730:
-	case 740:
-	case 750:
-		pdev->view_min.x = 160;
-		pdev->view_min.y = 120;
-		pdev->view_max.x = 640;
-		pdev->view_max.y = 480;
-		pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
-		pdev->abs_max.x = 640;
-		pdev->abs_max.y = 480;
-		pdev->vcinterface = 3;
-		pdev->vendpoint = 5;
-		pdev->frame_header_size = TOUCAM_HEADER_SIZE;
-		pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
-		break;
 	}
-	Debug("type = %d\n",pdev->type);
 	pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
 	pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
 	pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
 	/* length of image, in YUV format; always allocate enough memory. */
-	pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+	pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 }
 
 
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c
index 175250d..be65bdc 100644
--- a/drivers/media/video/pwc/pwc-timon.c
+++ b/drivers/media/video/pwc/pwc-timon.c
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -314,3 +314,1133 @@
    },
 };
 
+/*
+ * 16 versions:
+ *   2 tables  (one for Y, and one for U&V)
+ *   16 levels of details per tables
+ *   8 blocs
+ */
+
+const unsigned int TimonRomTable [16][2][16][8] =
+{
+ { /* version 0 */
+  { /* version 0, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000001,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000001,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 0, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000001,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000001,
+    0x00000001,0x00000009,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000009,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000009,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 1 */
+  { /* version 1, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 1, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000001,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000049,0x00000249,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 2 */
+  { /* version 2, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 2, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000049,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 3 */
+  { /* version 3, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009292,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 3, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00000049,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009292,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 4 */
+  { /* version 4, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x0000a49b},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 4, passes 1 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x0000a49b,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 5 */
+  { /* version 5, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 5, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x000124db,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009493,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 6 */
+  { /* version 6, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 6, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 7 */
+  { /* version 7, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x0002496e},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0002496d,0x00025bb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 7, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001b724,0x0001b925,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 8 */
+  { /* version 8, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x00024b76,0x00024b77},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x00024b76,0x00025bbf},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001c92d,0x00024b76,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 8, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0002496d,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 9 */
+  { /* version 9, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 9, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 10 */
+  { /* version 10, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0002496d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 10, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x00009493,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009493,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 11 */
+  { /* version 11, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 11, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x00009252,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 12 */
+  { /* version 12, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 12, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 13 */
+  { /* version 13, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 13, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 14 */
+  { /* version 14, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0002496d,0x00024b76,0x00024b77},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 14, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000136e4,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 15 */
+  { /* version 15, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0002496d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x00024b6d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 15, passes 1 */
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009292,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000124db,0x0001b724,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x0001b724,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x0001b724,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x0001b724,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001c924,0x0001b724,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001c924,0x0001b724,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002496d,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ }
+};
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
index a86b378..eef9e2c 100644
--- a/drivers/media/video/pwc/pwc-timon.h
+++ b/drivers/media/video/pwc/pwc-timon.h
@@ -1,5 +1,5 @@
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -42,7 +42,7 @@
 #ifndef PWC_TIMON_H
 #define PWC_TIMON_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Timon_table_entry
 {
@@ -52,8 +52,8 @@
 	unsigned char mode[13];		/* precomputed mode settings for cam */
 };
 
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const unsigned int TimonRomTable [16][2][16][8];
 
 
 #endif
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
index b37a89a..5d82028 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/video/pwc/pwc-uncompress.c
@@ -1,7 +1,7 @@
 /* Linux driver for Philips webcam
    Decompression frontend.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -22,6 +22,8 @@
    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
+
+   vim: set ts=8:
 */
 
 #include <asm/current.h>
@@ -29,6 +31,8 @@
 
 #include "pwc.h"
 #include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 int pwc_decompress(struct pwc_device *pdev)
 {
@@ -40,107 +44,95 @@
 
 	if (pdev == NULL)
 		return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
-	if (pdev->magic != PWC_MAGIC) {
-		Err("pwc_decompress(): magic failed.\n");
-		return -EFAULT;
-	}
-#endif
 
 	fbuf = pdev->read_frame;
 	if (fbuf == NULL)
 		return -EFAULT;
-	image = pdev->image_ptr[pdev->fill_image];
-	if (!image)
-		return -EFAULT;
+	image  = pdev->image_data;
+	image += pdev->images[pdev->fill_image].offset;
 
 	yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
 
 	/* Raw format; that's easy... */
 	if (pdev->vpalette == VIDEO_PALETTE_RAW)
 	{
-		memcpy(image, yuv, pdev->frame_size);
+		struct pwc_raw_frame *raw_frame = image;
+		raw_frame->type = cpu_to_le16(pdev->type);
+		raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength);
+			/* cmd_buf is always 4 bytes, but sometimes, only the
+			 * first 3 bytes is filled (Nala case). We can
+			 * determine this using the type of the webcam */
+		memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
+		memcpy(raw_frame+1, yuv, pdev->frame_size);
 		return 0;
 	}
 
 	if (pdev->vbandlength == 0) {
-		/* Uncompressed mode. We copy the data into the output buffer,
-		   using the viewport size (which may be larger than the image
-		   size). Unfortunately we have to do a bit of byte stuffing
-		   to get the desired output format/size.
+		/* Uncompressed mode.
+		 * We copy the data into the output buffer, using the viewport
+		 * size (which may be larger than the image size).
+		 * Unfortunately we have to do a bit of byte stuffing to get
+		 * the desired output format/size.
+		 *
+		 * We do some byte shuffling here to go from the
+		 * native format to YUV420P.
 		 */
-			/*
-			 * We do some byte shuffling here to go from the
-			 * native format to YUV420P.
-			 */
-			src = (u16 *)yuv;
-			n = pdev->view.x * pdev->view.y;
+		src = (u16 *)yuv;
+		n = pdev->view.x * pdev->view.y;
 
-			/* offset in Y plane */
-			stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
-			dsty = (u16 *)(image + stride);
+		/* offset in Y plane */
+		stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+		dsty = (u16 *)(image + stride);
 
-			/* offsets in U/V planes */
-			stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
-			dstu = (u16 *)(image + n +         stride);
-			dstv = (u16 *)(image + n + n / 4 + stride);
+		/* offsets in U/V planes */
+		stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+		dstu = (u16 *)(image + n +         stride);
+		dstv = (u16 *)(image + n + n / 4 + stride);
 
-			/* increment after each line */
-			stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+		/* increment after each line */
+		stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
 
-			for (line = 0; line < pdev->image.y; line++) {
-				for (col = 0; col < pdev->image.x; col += 4) {
-					*dsty++ = *src++;
-					*dsty++ = *src++;
-					if (line & 1)
-						*dstv++ = *src++;
-					else
-						*dstu++ = *src++;
-				}
-				dsty += stride;
+		for (line = 0; line < pdev->image.y; line++) {
+			for (col = 0; col < pdev->image.x; col += 4) {
+				*dsty++ = *src++;
+				*dsty++ = *src++;
 				if (line & 1)
-					dstv += (stride >> 1);
+					*dstv++ = *src++;
 				else
-					dstu += (stride >> 1);
+					*dstu++ = *src++;
 			}
+			dsty += stride;
+			if (line & 1)
+				dstv += (stride >> 1);
+			else
+				dstu += (stride >> 1);
+		}
+
+		return 0;
 	}
-	else {
-		/* Compressed; the decompressor routines will write the data
-		   in planar format immediately.
-		 */
-		int flags;
 
-		flags = PWCX_FLAG_PLANAR;
-		if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
-		 {
-		   printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
-		   flags |= PWCX_FLAG_BAYER;
-		   return -ENXIO; /* No such device or address: missing decompressor */
-		 }
+	/*
+	 * Compressed;
+	 * the decompressor routines will write the data in planar format
+	 * immediately.
+	 */
+	if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
+		PWC_ERROR("Mode Bayer is not supported for now\n");
+		/* flags |= PWCX_FLAG_BAYER; */
+		return -ENXIO; /* No such device or address: missing decompressor */
+	}
 
-#if 0
-		switch (pdev->type)
-		 {
-		  case 675:
-		  case 680:
-		  case 690:
-		  case 720:
-		  case 730:
-		  case 740:
-		  case 750:
-		    pwc_dec23_decompress(&pdev->image, &pdev->view,
-				&pdev->offset, yuv, image, flags,
-				pdev->decompress_data, pdev->vbandlength);
-		    break;
-		  case 645:
-		  case 646:
-		    /* TODO & FIXME */
-		    return -ENXIO; /* Missing decompressor */
-		    break;
-		 }
-#endif
+	if (DEVICE_USE_CODEC1(pdev->type)) {
+
+		/* TODO & FIXME */
+		PWC_ERROR("This chipset is not supported for now\n");
+		return -ENXIO; /* No such device or address: missing decompressor */
+
+	} else {
+		pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
 	}
 	return 0;
 }
 
 
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
index f75e1b6..041227f 100644
--- a/drivers/media/video/pwc/pwc-uncompress.h
+++ b/drivers/media/video/pwc/pwc-uncompress.h
@@ -1,5 +1,5 @@
 /* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -32,7 +32,7 @@
 
 #include <linux/config.h>
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 /* from pwc-dec.h */
 #define PWCX_FLAG_PLANAR        0x0001
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
new file mode 100644
index 0000000..b7eb3ce
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -0,0 +1,1202 @@
+/* Linux driver for Philips webcam
+   USB and Video4Linux interface part.
+   (C) 1999-2004 Nemosoft Unv.
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   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/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+
+static struct v4l2_queryctrl pwc_controls[] = {
+	{
+	    .id      = V4L2_CID_BRIGHTNESS,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Brightness",
+	    .minimum = 0,
+	    .maximum = 128,
+	    .step    = 1,
+	    .default_value = 64,
+	},
+	{
+	    .id      = V4L2_CID_CONTRAST,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Contrast",
+	    .minimum = 0,
+	    .maximum = 64,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_SATURATION,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Saturation",
+	    .minimum = -100,
+	    .maximum = 100,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_GAMMA,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Gamma",
+	    .minimum = 0,
+	    .maximum = 32,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_RED_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Red Gain",
+	    .minimum = 0,
+	    .maximum = 256,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_BLUE_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Blue Gain",
+	    .minimum = 0,
+	    .maximum = 256,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_AUTO_WHITE_BALANCE,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Auto White Balance",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_EXPOSURE,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Shutter Speed (Exposure)",
+	    .minimum = 0,
+	    .maximum = 256,
+	    .step    = 1,
+	    .default_value = 200,
+	},
+	{
+	    .id      = V4L2_CID_AUTOGAIN,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Auto Gain Enabled",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+	    .default_value = 1,
+	},
+	{
+	    .id      = V4L2_CID_GAIN,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Gain Level",
+	    .minimum = 0,
+	    .maximum = 256,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_SAVE_USER,
+	    .type    = V4L2_CTRL_TYPE_BUTTON,
+	    .name    = "Save User Settings",
+	    .minimum = 0,
+	    .maximum = 0,
+	    .step    = 0,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_RESTORE_USER,
+	    .type    = V4L2_CTRL_TYPE_BUTTON,
+	    .name    = "Restore User Settings",
+	    .minimum = 0,
+	    .maximum = 0,
+	    .step    = 0,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_RESTORE_FACTORY,
+	    .type    = V4L2_CTRL_TYPE_BUTTON,
+	    .name    = "Restore Factory Settings",
+	    .minimum = 0,
+	    .maximum = 0,
+	    .step    = 0,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_COLOUR_MODE,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Colour mode",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_AUTOCONTOUR,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Auto contour",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_CONTOUR,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Contour",
+	    .minimum = 0,
+	    .maximum = 63,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_BACKLIGHT,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Backlight compensation",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	  .id      = V4L2_CID_PRIVATE_FLICKERLESS,
+	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
+	    .name    = "Flickerless",
+	    .minimum = 0,
+	    .maximum = 1,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+	{
+	    .id      = V4L2_CID_PRIVATE_NOISE_REDUCTION,
+	    .type    = V4L2_CTRL_TYPE_INTEGER,
+	    .name    = "Noise reduction",
+	    .minimum = 0,
+	    .maximum = 3,
+	    .step    = 1,
+	    .default_value = 0,
+	},
+};
+
+
+static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+{
+	memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+	f->fmt.pix.width        = pdev->view.x;
+	f->fmt.pix.height       = pdev->view.y;
+	f->fmt.pix.field        = V4L2_FIELD_NONE;
+	if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
+		f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
+		f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	} else {
+		/* vbandlength contains 4 lines ...  */
+		f->fmt.pix.bytesperline = pdev->vbandlength/4;
+		f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
+		if (DEVICE_USE_CODEC1(pdev->type))
+			f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
+		else
+			f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
+	}
+	PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
+			"width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
+			f->fmt.pix.width,
+			f->fmt.pix.height,
+			f->fmt.pix.bytesperline,
+			f->fmt.pix.sizeimage,
+			(f->fmt.pix.pixelformat)&255,
+			(f->fmt.pix.pixelformat>>8)&255,
+			(f->fmt.pix.pixelformat>>16)&255,
+			(f->fmt.pix.pixelformat>>24)&255);
+}
+
+/* ioctl(VIDIOC_TRY_FMT) */
+static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+		return -EINVAL;
+	}
+
+	switch (f->fmt.pix.pixelformat) {
+		case V4L2_PIX_FMT_YUV420:
+			break;
+		case V4L2_PIX_FMT_PWC1:
+			if (DEVICE_USE_CODEC23(pdev->type)) {
+				PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
+				return -EINVAL;
+			}
+			break;
+		case V4L2_PIX_FMT_PWC2:
+			if (DEVICE_USE_CODEC1(pdev->type)) {
+				PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
+				return -EINVAL;
+			}
+			break;
+		default:
+			PWC_DEBUG_IOCTL("Unsupported pixel format\n");
+			return -EINVAL;
+
+	}
+
+	if (f->fmt.pix.width > pdev->view_max.x)
+		f->fmt.pix.width = pdev->view_max.x;
+	else if (f->fmt.pix.width < pdev->view_min.x)
+		f->fmt.pix.width = pdev->view_min.x;
+
+	if (f->fmt.pix.height > pdev->view_max.y)
+		f->fmt.pix.height = pdev->view_max.y;
+	else if (f->fmt.pix.height < pdev->view_min.y)
+		f->fmt.pix.height = pdev->view_min.y;
+
+	return 0;
+}
+
+/* ioctl(VIDIOC_SET_FMT) */
+static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+	int ret, fps, snapshot, compression, pixelformat;
+
+	ret = pwc_vidioc_try_fmt(pdev, f);
+	if (ret<0)
+		return ret;
+
+	pixelformat = f->fmt.pix.pixelformat;
+	compression = pdev->vcompression;
+	snapshot = 0;
+	fps = pdev->vframes;
+	if (f->fmt.pix.priv) {
+		compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
+		snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
+		fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+		if (fps == 0)
+			fps = pdev->vframes;
+	}
+
+	if (pixelformat == V4L2_PIX_FMT_YUV420)
+		pdev->vpalette = VIDEO_PALETTE_YUV420P;
+	else
+		pdev->vpalette = VIDEO_PALETTE_RAW;
+
+	PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+			"compression=%d snapshot=%d format=%c%c%c%c\n",
+			f->fmt.pix.width, f->fmt.pix.height, fps,
+			compression, snapshot,
+			(pixelformat)&255,
+			(pixelformat>>8)&255,
+			(pixelformat>>16)&255,
+			(pixelformat>>24)&255);
+
+	ret = pwc_try_video_mode(pdev,
+				 f->fmt.pix.width,
+				 f->fmt.pix.height,
+				 fps,
+				 compression,
+				 snapshot);
+
+	PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+
+	if (ret)
+		return ret;
+
+	pwc_vidioc_fill_fmt(pdev, f);
+
+	return 0;
+
+}
+
+int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct pwc_device *pdev;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (vdev == NULL)
+		return -EFAULT;
+	pdev = vdev->priv;
+	if (pdev == NULL)
+		return -EFAULT;
+
+#if CONFIG_PWC_DEBUG
+	if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+		v4l_printk_ioctl(cmd);
+#endif
+
+
+	switch (cmd) {
+		/* Query cabapilities */
+		case VIDIOCGCAP:
+		{
+			struct video_capability *caps = arg;
+
+			strcpy(caps->name, vdev->name);
+			caps->type = VID_TYPE_CAPTURE;
+			caps->channels = 1;
+			caps->audios = 1;
+			caps->minwidth  = pdev->view_min.x;
+			caps->minheight = pdev->view_min.y;
+			caps->maxwidth  = pdev->view_max.x;
+			caps->maxheight = pdev->view_max.y;
+			break;
+		}
+
+		/* Channel functions (simulate 1 channel) */
+		case VIDIOCGCHAN:
+		{
+			struct video_channel *v = arg;
+
+			if (v->channel != 0)
+				return -EINVAL;
+			v->flags = 0;
+			v->tuners = 0;
+			v->type = VIDEO_TYPE_CAMERA;
+			strcpy(v->name, "Webcam");
+			return 0;
+		}
+
+		case VIDIOCSCHAN:
+		{
+			/* The spec says the argument is an integer, but
+			   the bttv driver uses a video_channel arg, which
+			   makes sense becasue it also has the norm flag.
+			 */
+			struct video_channel *v = arg;
+			if (v->channel != 0)
+				return -EINVAL;
+			return 0;
+		}
+
+
+		/* Picture functions; contrast etc. */
+		case VIDIOCGPICT:
+		{
+			struct video_picture *p = arg;
+			int val;
+
+			val = pwc_get_brightness(pdev);
+			if (val >= 0)
+				p->brightness = (val<<9);
+			else
+				p->brightness = 0xffff;
+			val = pwc_get_contrast(pdev);
+			if (val >= 0)
+				p->contrast = (val<<10);
+			else
+				p->contrast = 0xffff;
+			/* Gamma, Whiteness, what's the difference? :) */
+			val = pwc_get_gamma(pdev);
+			if (val >= 0)
+				p->whiteness = (val<<11);
+			else
+				p->whiteness = 0xffff;
+			if (pwc_get_saturation(pdev, &val)<0)
+				p->colour = 0xffff;
+			else
+				p->colour = 32768 + val * 327;
+			p->depth = 24;
+			p->palette = pdev->vpalette;
+			p->hue = 0xFFFF; /* N/A */
+			break;
+		}
+
+		case VIDIOCSPICT:
+		{
+			struct video_picture *p = arg;
+			/*
+			 *	FIXME:	Suppose we are mid read
+				ANSWER: No problem: the firmware of the camera
+					can handle brightness/contrast/etc
+					changes at _any_ time, and the palette
+					is used exactly once in the uncompress
+					routine.
+			 */
+			pwc_set_brightness(pdev, p->brightness);
+			pwc_set_contrast(pdev, p->contrast);
+			pwc_set_gamma(pdev, p->whiteness);
+			pwc_set_saturation(pdev, (p->colour-32768)/327);
+			if (p->palette && p->palette != pdev->vpalette) {
+				switch (p->palette) {
+					case VIDEO_PALETTE_YUV420P:
+					case VIDEO_PALETTE_RAW:
+						pdev->vpalette = p->palette;
+						return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+						break;
+					default:
+						return -EINVAL;
+						break;
+				}
+			}
+			break;
+		}
+
+		/* Window/size parameters */
+		case VIDIOCGWIN:
+		{
+			struct video_window *vw = arg;
+
+			vw->x = 0;
+			vw->y = 0;
+			vw->width = pdev->view.x;
+			vw->height = pdev->view.y;
+			vw->chromakey = 0;
+			vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+				   (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+			break;
+		}
+
+		case VIDIOCSWIN:
+		{
+			struct video_window *vw = arg;
+			int fps, snapshot, ret;
+
+			fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+			snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+			if (fps == 0)
+				fps = pdev->vframes;
+			if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+				return 0;
+			ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+			if (ret)
+				return ret;
+			break;
+		}
+
+		/* We don't have overlay support (yet) */
+		case VIDIOCGFBUF:
+		{
+			struct video_buffer *vb = arg;
+
+			memset(vb,0,sizeof(*vb));
+			break;
+		}
+
+		/* mmap() functions */
+		case VIDIOCGMBUF:
+		{
+			/* Tell the user program how much memory is needed for a mmap() */
+			struct video_mbuf *vm = arg;
+			int i;
+
+			memset(vm, 0, sizeof(*vm));
+			vm->size = pwc_mbufs * pdev->len_per_image;
+			vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
+			for (i = 0; i < pwc_mbufs; i++)
+				vm->offsets[i] = i * pdev->len_per_image;
+			break;
+		}
+
+		case VIDIOCMCAPTURE:
+		{
+			/* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+			struct video_mmap *vm = arg;
+
+			PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+			if (vm->frame < 0 || vm->frame >= pwc_mbufs)
+				return -EINVAL;
+
+			/* xawtv is nasty. It probes the available palettes
+			   by setting a very small image size and trying
+			   various palettes... The driver doesn't support
+			   such small images, so I'm working around it.
+			 */
+			if (vm->format)
+			{
+				switch (vm->format)
+				{
+					case VIDEO_PALETTE_YUV420P:
+					case VIDEO_PALETTE_RAW:
+						break;
+					default:
+						return -EINVAL;
+						break;
+				}
+			}
+
+			if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+			    (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+				int ret;
+
+				PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+				ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+				if (ret)
+					return ret;
+			} /* ... size mismatch */
+
+			/* FIXME: should we lock here? */
+			if (pdev->image_used[vm->frame])
+				return -EBUSY;	/* buffer wasn't available. Bummer */
+			pdev->image_used[vm->frame] = 1;
+
+			/* Okay, we're done here. In the SYNC call we wait until a
+			   frame comes available, then expand image into the given
+			   buffer.
+			   In contrast to the CPiA cam the Philips cams deliver a
+			   constant stream, almost like a grabber card. Also,
+			   we have separate buffers for the rawdata and the image,
+			   meaning we can nearly always expand into the requested buffer.
+			 */
+			PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
+			break;
+		}
+
+		case VIDIOCSYNC:
+		{
+			/* The doc says: "Whenever a buffer is used it should
+			   call VIDIOCSYNC to free this frame up and continue."
+
+			   The only odd thing about this whole procedure is
+			   that MCAPTURE flags the buffer as "in use", and
+			   SYNC immediately unmarks it, while it isn't
+			   after SYNC that you know that the buffer actually
+			   got filled! So you better not start a CAPTURE in
+			   the same frame immediately (use double buffering).
+			   This is not a problem for this cam, since it has
+			   extra intermediate buffers, but a hardware
+			   grabber card will then overwrite the buffer
+			   you're working on.
+			 */
+			int *mbuf = arg;
+			int ret;
+
+			PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
+
+			/* bounds check */
+			if (*mbuf < 0 || *mbuf >= pwc_mbufs)
+				return -EINVAL;
+			/* check if this buffer was requested anyway */
+			if (pdev->image_used[*mbuf] == 0)
+				return -EINVAL;
+
+			/* Add ourselves to the frame wait-queue.
+
+			   FIXME: needs auditing for safety.
+			   QUESTION: In what respect? I think that using the
+				     frameq is safe now.
+			 */
+			add_wait_queue(&pdev->frameq, &wait);
+			while (pdev->full_frames == NULL) {
+				/* Check for unplugged/etc. here */
+				if (pdev->error_status) {
+					remove_wait_queue(&pdev->frameq, &wait);
+					set_current_state(TASK_RUNNING);
+					return -pdev->error_status;
+				}
+
+				if (signal_pending(current)) {
+					remove_wait_queue(&pdev->frameq, &wait);
+					set_current_state(TASK_RUNNING);
+					return -ERESTARTSYS;
+				}
+				schedule();
+				set_current_state(TASK_INTERRUPTIBLE);
+			}
+			remove_wait_queue(&pdev->frameq, &wait);
+			set_current_state(TASK_RUNNING);
+
+			/* The frame is ready. Expand in the image buffer
+			   requested by the user. I don't care if you
+			   mmap() 5 buffers and request data in this order:
+			   buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+			   Grabber hardware may not be so forgiving.
+			 */
+			PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
+			pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+			/* Decompress, etc */
+			ret = pwc_handle_frame(pdev);
+			pdev->image_used[*mbuf] = 0;
+			if (ret)
+				return -EFAULT;
+			break;
+		}
+
+		case VIDIOCGAUDIO:
+		{
+			struct video_audio *v = arg;
+
+			strcpy(v->name, "Microphone");
+			v->audio = -1; /* unknown audio minor */
+			v->flags = 0;
+			v->mode = VIDEO_SOUND_MONO;
+			v->volume = 0;
+			v->bass = 0;
+			v->treble = 0;
+			v->balance = 0x8000;
+			v->step = 1;
+			break;
+		}
+
+		case VIDIOCSAUDIO:
+		{
+			/* Dummy: nothing can be set */
+			break;
+		}
+
+		case VIDIOCGUNIT:
+		{
+			struct video_unit *vu = arg;
+
+			vu->video = pdev->vdev->minor & 0x3F;
+			vu->audio = -1; /* not known yet */
+			vu->vbi = -1;
+			vu->radio = -1;
+			vu->teletext = -1;
+			break;
+		}
+
+		/* V4L2 Layer */
+		case VIDIOC_QUERYCAP:
+		{
+		    struct v4l2_capability *cap = arg;
+
+		    PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
+				       "try to use the v4l2 layer\n");
+		    strcpy(cap->driver,PWC_NAME);
+		    strlcpy(cap->card, vdev->name, sizeof(cap->card));
+		    usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
+		    cap->version = PWC_VERSION_CODE;
+		    cap->capabilities =
+			V4L2_CAP_VIDEO_CAPTURE	|
+			V4L2_CAP_STREAMING	|
+			V4L2_CAP_READWRITE;
+		    return 0;
+		}
+
+		case VIDIOC_ENUMINPUT:
+		{
+		    struct v4l2_input *i = arg;
+
+		    if ( i->index )	/* Only one INPUT is supported */
+			  return -EINVAL;
+
+		    memset(i, 0, sizeof(struct v4l2_input));
+		    strcpy(i->name, "usb");
+		    return 0;
+		}
+
+		case VIDIOC_G_INPUT:
+		{
+		    int *i = arg;
+		    *i = 0;	/* Only one INPUT is supported */
+		    return 0;
+		}
+		case VIDIOC_S_INPUT:
+		{
+			int *i = arg;
+
+			if ( *i ) {	/* Only one INPUT is supported */
+				PWC_DEBUG_IOCTL("Only one input source is"\
+					" supported with this webcam.\n");
+				return -EINVAL;
+			}
+			return 0;
+		}
+
+		/* TODO: */
+		case VIDIOC_QUERYCTRL:
+		{
+			struct v4l2_queryctrl *c = arg;
+			int i;
+
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
+			for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
+				if (pwc_controls[i].id == c->id) {
+					PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+					memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
+					return 0;
+				}
+			}
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+
+			return -EINVAL;
+		}
+		case VIDIOC_G_CTRL:
+		{
+			struct v4l2_control *c = arg;
+			int ret;
+
+			switch (c->id)
+			{
+				case V4L2_CID_BRIGHTNESS:
+					c->value = pwc_get_brightness(pdev);
+					if (c->value<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_CONTRAST:
+					c->value = pwc_get_contrast(pdev);
+					if (c->value<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_SATURATION:
+					ret = pwc_get_saturation(pdev, &c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_GAMMA:
+					c->value = pwc_get_gamma(pdev);
+					if (c->value<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_RED_BALANCE:
+					ret = pwc_get_red_gain(pdev, &c->value);
+					if (ret<0)
+						return -EINVAL;
+					c->value >>= 8;
+					return 0;
+				case V4L2_CID_BLUE_BALANCE:
+					ret = pwc_get_blue_gain(pdev, &c->value);
+					if (ret<0)
+						return -EINVAL;
+					c->value >>= 8;
+					return 0;
+				case V4L2_CID_AUTO_WHITE_BALANCE:
+					ret = pwc_get_awb(pdev);
+					if (ret<0)
+						return -EINVAL;
+					c->value = (ret == PWC_WB_MANUAL)?0:1;
+					return 0;
+				case V4L2_CID_GAIN:
+					ret = pwc_get_agc(pdev, &c->value);
+					if (ret<0)
+						return -EINVAL;
+					c->value >>= 8;
+					return 0;
+				case V4L2_CID_AUTOGAIN:
+					ret = pwc_get_agc(pdev, &c->value);
+					if (ret<0)
+						return -EINVAL;
+					c->value = (c->value < 0)?1:0;
+					return 0;
+				case V4L2_CID_EXPOSURE:
+					ret = pwc_get_shutter_speed(pdev, &c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_COLOUR_MODE:
+					ret = pwc_get_colour_mode(pdev, &c->value);
+					if (ret < 0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_AUTOCONTOUR:
+					ret = pwc_get_contour(pdev, &c->value);
+					if (ret < 0)
+						return -EINVAL;
+					c->value=(c->value == -1?1:0);
+					return 0;
+				case V4L2_CID_PRIVATE_CONTOUR:
+					ret = pwc_get_contour(pdev, &c->value);
+					if (ret < 0)
+						return -EINVAL;
+					c->value >>= 10;
+					return 0;
+				case V4L2_CID_PRIVATE_BACKLIGHT:
+					ret = pwc_get_backlight(pdev, &c->value);
+					if (ret < 0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_FLICKERLESS:
+					ret = pwc_get_flicker(pdev, &c->value);
+					if (ret < 0)
+						return -EINVAL;
+					c->value=(c->value?1:0);
+					return 0;
+				case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+					ret = pwc_get_dynamic_noise(pdev, &c->value);
+					if (ret < 0)
+						return -EINVAL;
+					return 0;
+
+				case V4L2_CID_PRIVATE_SAVE_USER:
+				case V4L2_CID_PRIVATE_RESTORE_USER:
+				case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+					return -EINVAL;
+			}
+			return -EINVAL;
+		}
+		case VIDIOC_S_CTRL:
+		{
+			struct v4l2_control *c = arg;
+			int ret;
+
+			switch (c->id)
+			{
+				case V4L2_CID_BRIGHTNESS:
+					c->value <<= 9;
+					ret = pwc_set_brightness(pdev, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_CONTRAST:
+					c->value <<= 10;
+					ret = pwc_set_contrast(pdev, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_SATURATION:
+					ret = pwc_set_saturation(pdev, c->value);
+					if (ret<0)
+					  return -EINVAL;
+					return 0;
+				case V4L2_CID_GAMMA:
+					c->value <<= 11;
+					ret = pwc_set_gamma(pdev, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_RED_BALANCE:
+					c->value <<= 8;
+					ret = pwc_set_red_gain(pdev, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_BLUE_BALANCE:
+					c->value <<= 8;
+					ret = pwc_set_blue_gain(pdev, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_AUTO_WHITE_BALANCE:
+					c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
+					ret = pwc_set_awb(pdev, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_EXPOSURE:
+					c->value <<= 8;
+					ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_AUTOGAIN:
+					/* autogain off means nothing without a gain */
+					if (c->value == 0)
+						return 0;
+					ret = pwc_set_agc(pdev, c->value, 0);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_GAIN:
+					c->value <<= 8;
+					ret = pwc_set_agc(pdev, 0, c->value);
+					if (ret<0)
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_SAVE_USER:
+					if (pwc_save_user(pdev))
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_RESTORE_USER:
+					if (pwc_restore_user(pdev))
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+					if (pwc_restore_factory(pdev))
+						return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_COLOUR_MODE:
+					ret = pwc_set_colour_mode(pdev, c->value);
+					if (ret < 0)
+					  return -EINVAL;
+					return 0;
+				case V4L2_CID_PRIVATE_AUTOCONTOUR:
+				  c->value=(c->value == 1)?-1:0;
+				  ret = pwc_set_contour(pdev, c->value);
+				  if (ret < 0)
+				    return -EINVAL;
+				  return 0;
+				case V4L2_CID_PRIVATE_CONTOUR:
+				  c->value <<= 10;
+				  ret = pwc_set_contour(pdev, c->value);
+				  if (ret < 0)
+				    return -EINVAL;
+				  return 0;
+				case V4L2_CID_PRIVATE_BACKLIGHT:
+				  ret = pwc_set_backlight(pdev, c->value);
+				  if (ret < 0)
+				    return -EINVAL;
+				  return 0;
+				case V4L2_CID_PRIVATE_FLICKERLESS:
+				  ret = pwc_set_flicker(pdev, c->value);
+				  if (ret < 0)
+				    return -EINVAL;
+				case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+				  ret = pwc_set_dynamic_noise(pdev, c->value);
+				  if (ret < 0)
+				    return -EINVAL;
+				  return 0;
+
+			}
+			return -EINVAL;
+		}
+
+		case VIDIOC_ENUM_FMT:
+		{
+			struct v4l2_fmtdesc *f = arg;
+			int index;
+
+			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			      return -EINVAL;
+
+			/* We only support two format: the raw format, and YUV */
+			index = f->index;
+			memset(f,0,sizeof(struct v4l2_fmtdesc));
+			f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			f->index = index;
+			switch(index)
+			{
+				case 0:
+					/* RAW format */
+					f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
+					f->flags = V4L2_FMT_FLAG_COMPRESSED;
+					strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
+					break;
+				case 1:
+					f->pixelformat = V4L2_PIX_FMT_YUV420;
+					strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
+					break;
+				default:
+					return -EINVAL;
+			}
+			return 0;
+		}
+
+		case VIDIOC_G_FMT:
+		{
+			struct v4l2_format *f = arg;
+
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
+			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			      return -EINVAL;
+
+			pwc_vidioc_fill_fmt(pdev, f);
+
+			return 0;
+		}
+
+		case VIDIOC_TRY_FMT:
+			return pwc_vidioc_try_fmt(pdev, arg);
+
+		case VIDIOC_S_FMT:
+			return pwc_vidioc_set_fmt(pdev, arg);
+
+		case VIDIOC_G_STD:
+		{
+			v4l2_std_id *std = arg;
+			*std = V4L2_STD_UNKNOWN;
+			return 0;
+		}
+
+		case VIDIOC_S_STD:
+		{
+			v4l2_std_id *std = arg;
+			if (*std != V4L2_STD_UNKNOWN)
+				return -EINVAL;
+			return 0;
+		}
+
+		case VIDIOC_ENUMSTD:
+		{
+			struct v4l2_standard *std = arg;
+			if (std->index != 0)
+				return -EINVAL;
+			std->id = V4L2_STD_UNKNOWN;
+			strncpy(std->name, "webcam", sizeof(std->name));
+			return 0;
+		}
+
+		case VIDIOC_REQBUFS:
+		{
+			struct v4l2_requestbuffers *rb = arg;
+			int nbuffers;
+
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
+			if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+			if (rb->memory != V4L2_MEMORY_MMAP)
+				return -EINVAL;
+
+			nbuffers = rb->count;
+			if (nbuffers < 2)
+				nbuffers = 2;
+			else if (nbuffers > pwc_mbufs)
+				nbuffers = pwc_mbufs;
+			/* Force to use our # of buffers */
+			rb->count = pwc_mbufs;
+			return 0;
+		}
+
+		case VIDIOC_QUERYBUF:
+		{
+			struct v4l2_buffer *buf = arg;
+			int index;
+
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
+			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+				return -EINVAL;
+			}
+			if (buf->memory != V4L2_MEMORY_MMAP) {
+				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
+				return -EINVAL;
+			}
+			index = buf->index;
+			if (index < 0 || index >= pwc_mbufs) {
+				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+				return -EINVAL;
+			}
+
+			memset(buf, 0, sizeof(struct v4l2_buffer));
+			buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+			buf->index = index;
+			buf->m.offset = index * pdev->len_per_image;
+			if (pdev->vpalette == VIDEO_PALETTE_RAW)
+				buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+			else
+				buf->bytesused = pdev->view.size;
+			buf->field = V4L2_FIELD_NONE;
+			buf->memory = V4L2_MEMORY_MMAP;
+			//buf->flags = V4L2_BUF_FLAG_MAPPED;
+			buf->length = pdev->len_per_image;
+
+			PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
+			PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
+			PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+
+			return 0;
+		}
+
+		case VIDIOC_QBUF:
+		{
+			struct v4l2_buffer *buf = arg;
+
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
+			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+			if (buf->memory != V4L2_MEMORY_MMAP)
+				return -EINVAL;
+			if (buf->index < 0 || buf->index >= pwc_mbufs)
+				return -EINVAL;
+
+			buf->flags |= V4L2_BUF_FLAG_QUEUED;
+			buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+			return 0;
+		}
+
+		case VIDIOC_DQBUF:
+		{
+			struct v4l2_buffer *buf = arg;
+			int ret;
+
+			PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+
+			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+				return -EINVAL;
+
+			/* Add ourselves to the frame wait-queue.
+
+			   FIXME: needs auditing for safety.
+			   QUESTION: In what respect? I think that using the
+				     frameq is safe now.
+			 */
+			add_wait_queue(&pdev->frameq, &wait);
+			while (pdev->full_frames == NULL) {
+				if (pdev->error_status) {
+					remove_wait_queue(&pdev->frameq, &wait);
+					set_current_state(TASK_RUNNING);
+					return -pdev->error_status;
+				}
+
+				if (signal_pending(current)) {
+					remove_wait_queue(&pdev->frameq, &wait);
+					set_current_state(TASK_RUNNING);
+					return -ERESTARTSYS;
+				}
+				schedule();
+				set_current_state(TASK_INTERRUPTIBLE);
+			}
+			remove_wait_queue(&pdev->frameq, &wait);
+			set_current_state(TASK_RUNNING);
+
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+			/* Decompress data in pdev->images[pdev->fill_image] */
+			ret = pwc_handle_frame(pdev);
+			if (ret)
+				return -EFAULT;
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+			buf->index = pdev->fill_image;
+			if (pdev->vpalette == VIDEO_PALETTE_RAW)
+				buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+			else
+				buf->bytesused = pdev->view.size;
+			buf->flags = V4L2_BUF_FLAG_MAPPED;
+			buf->field = V4L2_FIELD_NONE;
+			do_gettimeofday(&buf->timestamp);
+			buf->sequence = 0;
+			buf->memory = V4L2_MEMORY_MMAP;
+			buf->m.offset = pdev->fill_image * pdev->len_per_image;
+			buf->length = buf->bytesused;
+			pwc_next_image(pdev);
+
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
+			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+			return 0;
+
+		}
+
+		case VIDIOC_STREAMON:
+		{
+			/* WARNING: pwc_try_video_mode() called pwc_isoc_init */
+			pwc_isoc_init(pdev);
+			return 0;
+		}
+
+		case VIDIOC_STREAMOFF:
+		{
+			pwc_isoc_cleanup(pdev);
+			return 0;
+		}
+
+		default:
+			return pwc_ioctl(pdev, cmd, arg);
+	} /* ..switch */
+	return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 1b0ee0c..629f79e 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -1,5 +1,5 @@
 /* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -29,51 +29,87 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/spinlock.h>
-#include <linux/videodev.h>
 #include <linux/wait.h>
 #include <linux/smp_lock.h>
+#include <linux/version.h>
 #include <asm/semaphore.h>
 #include <asm/errno.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
+#include <media/pwc-ioctl.h>
 
 /* Turn some debugging options on/off */
-#define PWC_DEBUG 0
+#ifndef CONFIG_PWC_DEBUG
+#define CONFIG_PWC_DEBUG 1
+#endif
+
+/* Version block */
+#define PWC_MAJOR	10
+#define PWC_MINOR	0
+#define PWC_EXTRAMINOR	12
+#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
+#define PWC_VERSION 	"10.0.12"
+#define PWC_NAME 	"pwc"
+#define PFX		PWC_NAME ": "
+
 
 /* Trace certain actions in the driver */
-#define TRACE_MODULE	0x0001
-#define TRACE_PROBE	0x0002
-#define TRACE_OPEN	0x0004
-#define TRACE_READ	0x0008
-#define TRACE_MEMORY	0x0010
-#define TRACE_FLOW	0x0020
-#define TRACE_SIZE	0x0040
-#define TRACE_PWCX	0x0080
-#define TRACE_SEQUENCE	0x1000
+#define PWC_DEBUG_LEVEL_MODULE	(1<<0)
+#define PWC_DEBUG_LEVEL_PROBE	(1<<1)
+#define PWC_DEBUG_LEVEL_OPEN	(1<<2)
+#define PWC_DEBUG_LEVEL_READ	(1<<3)
+#define PWC_DEBUG_LEVEL_MEMORY	(1<<4)
+#define PWC_DEBUG_LEVEL_FLOW	(1<<5)
+#define PWC_DEBUG_LEVEL_SIZE	(1<<6)
+#define PWC_DEBUG_LEVEL_IOCTL	(1<<7)
+#define PWC_DEBUG_LEVEL_TRACE	(1<<8)
 
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
-#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
+#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
+#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
+#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args)
+#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args)
+#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args)
+#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args)
+#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args)
+#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args)
+#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
 
 
+#if CONFIG_PWC_DEBUG
+
+#define PWC_DEBUG_LEVEL	(PWC_DEBUG_LEVEL_MODULE)
+
+#define PWC_DEBUG(level, fmt, args...) do {\
+	  if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+	     printk(KERN_DEBUG PFX fmt, ##args); \
+	  } while(0)
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+#else /* if ! CONFIG_PWC_DEBUG */
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) do { } while(0)
+#define PWC_DEBUG(level, fmt, args...) do { } while(0)
+
+#define pwc_trace 0
+
+#endif
+
 /* Defines for ToUCam cameras */
 #define TOUCAM_HEADER_SIZE		8
 #define TOUCAM_TRAILER_SIZE		4
 
 #define FEATURE_MOTOR_PANTILT		0x0001
-
-/* Version block */
-#define PWC_MAJOR	9
-#define PWC_MINOR	0
-#define PWC_VERSION 	"9.0.2-unofficial"
-#define PWC_NAME 	"pwc"
+#define FEATURE_CODEC1			0x0002
+#define FEATURE_CODEC2			0x0004
 
 /* Turn certain features on/off */
 #define PWC_INT_PIPE 0
@@ -95,6 +131,18 @@
 /* Absolute maximum number of buffers available for mmap() */
 #define MAX_IMAGES 		10
 
+/* Some macros to quickly find the type of a webcam */
+#define DEVICE_USE_CODEC1(x) ((x)<675)
+#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700)
+#define DEVICE_USE_CODEC3(x) ((x)>=700)
+#define DEVICE_USE_CODEC23(x) ((x)>=675)
+
+
+#ifndef V4L2_PIX_FMT_PWC1
+#define V4L2_PIX_FMT_PWC1	v4l2_fourcc('P','W','C','1')
+#define V4L2_PIX_FMT_PWC2	v4l2_fourcc('P','W','C','2')
+#endif
+
 /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
 struct pwc_iso_buf
 {
@@ -110,17 +158,19 @@
    void *data;
    volatile int filled;		/* number of bytes filled */
    struct pwc_frame_buf *next;	/* list */
-#if PWC_DEBUG
-   int sequence;		/* Sequence number */
-#endif
+};
+
+/* additionnal informations used when dealing image between kernel and userland */
+struct pwc_imgbuf
+{
+	unsigned long offset;	/* offset of this buffer in the big array of image_data */
+	int   vma_use_count;	/* count the number of time this memory is mapped */
 };
 
 struct pwc_device
 {
    struct video_device *vdev;
-#ifdef PWC_MAGIC
-   int magic;
-#endif
+
    /* Pointer to our usb_device */
    struct usb_device *udev;
 
@@ -177,12 +227,8 @@
    int frame_size;
    int frame_total_size; /* including header & trailer */
    int drop_frames;
-#if PWC_DEBUG
-   int sequence;			/* Debugging aid */
-#endif
 
    /* 3: decompression */
-   struct pwc_decompressor *decompressor;	/* function block with decompression routines */
    void *decompress_data;		/* private data for decompression engine */
 
    /* 4: image */
@@ -198,7 +244,7 @@
    struct pwc_coord offset;		/* offset within the viewport */
 
    void *image_data;			/* total buffer, which is subdivided into ... */
-   void *image_ptr[MAX_IMAGES];		/* ...several images... */
+   struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */
    int fill_image;			/* ...which are rotated. */
    int len_per_image;			/* length per image */
    int image_read_pos;			/* In case we read data in pieces, keep track of were we are in the imagebuffer */
@@ -211,6 +257,7 @@
    struct pwc_mpt_range angle_range;
    int pan_angle;			/* in degrees * 100 */
    int tilt_angle;			/* absolute angle; 0,0 is home position */
+   int snapshot_button_status;		/* set to 1 when the user push the button, reset to 0 when this value is read */
 
    /*** Misc. data ***/
    wait_queue_head_t frameq;		/* When waiting for a frame to finish... */
@@ -219,20 +266,26 @@
 #endif
 };
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* Global variable */
+/* Global variables */
+#if CONFIG_PWC_DEBUG
 extern int pwc_trace;
+#endif
+extern int pwc_mbufs;
 
 /** functions in pwc-if.c */
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+int pwc_handle_frame(struct pwc_device *pdev);
+void pwc_next_image(struct pwc_device *pdev);
+int pwc_isoc_init(struct pwc_device *pdev);
+void pwc_isoc_cleanup(struct pwc_device *pdev);
 
 /** Functions in pwc-misc.c */
 /* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
 
 int pwc_decode_size(struct pwc_device *pdev, int width, int height);
 void pwc_construct(struct pwc_device *pdev);
@@ -240,6 +293,9 @@
 /** Functions in pwc-ctrl.c */
 /* Request a certain video mode. Returns < 0 if not possible */
 extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+/* Calculate the number of bytes per image (not frame) */
+extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
+extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
 
 /* Various controls; should be obvious. Value 0..65535, or < 0 on error */
 extern int pwc_get_brightness(struct pwc_device *pdev);
@@ -248,10 +304,36 @@
 extern int pwc_set_contrast(struct pwc_device *pdev, int value);
 extern int pwc_get_gamma(struct pwc_device *pdev);
 extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
 extern int pwc_set_saturation(struct pwc_device *pdev, int value);
 extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
 extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+extern int pwc_restore_user(struct pwc_device *pdev);
+extern int pwc_save_user(struct pwc_device *pdev);
+extern int pwc_restore_factory(struct pwc_device *pdev);
+
+/* exported for use by v4l2 controls */
+extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_awb(struct pwc_device *pdev);
+extern int pwc_set_awb(struct pwc_device *pdev, int mode);
+extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_agc(struct pwc_device *pdev, int *value);
+extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
+
+extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
+extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
+extern int pwc_set_contour(struct pwc_device *pdev, int contour);
+extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
+extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
+extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
+extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
+extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
+extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
+extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
 
 /* Power down or up the camera; not supported by all models */
 extern int pwc_camera_power(struct pwc_device *pdev, int power);
@@ -259,6 +341,9 @@
 /* Private ioctl()s; see pwc-ioctl.h */
 extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
 
+/** Functions in pwc-v4l.c */
+extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+			      unsigned int cmd, void *arg);
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
@@ -270,3 +355,4 @@
 
 
 #endif
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index dd830e0..59a1872 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -46,6 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 #include "saa5246a.h"
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 531e946..19a8d65 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -56,6 +56,7 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
 
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 41d951d..676b997 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -43,6 +43,7 @@
 #define I2C_NAME(s) (s)->name
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 
 static int debug = 0;
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index dceebc0..b59c117 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -72,6 +72,10 @@
 	int sat;
 	enum v4l2_chip_ident ident;
 	u32 audclk_freq;
+	u32 crystal_freq;
+	u8 ucgc;
+	u8 cgcdiv;
+	u8 apll;
 };
 
 /* ----------------------------------------------------------------------- */
@@ -375,10 +379,6 @@
 };
 
 static const unsigned char saa7115_init_misc[] = {
-	0x38, 0x03,		/* audio stuff */
-	0x39, 0x10,
-	0x3a, 0x08,
-
 	0x81, 0x01,		/* reg 0x15,0x16 define blanking window */
 	0x82, 0x00,
 	0x83, 0x01,		/* I port settings */
@@ -584,6 +584,7 @@
 	u32 acni;
 	u32 hz;
 	u64 f;
+	u8 acc = 0; 	/* reg 0x3a, audio clock control */
 
 	v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
 
@@ -591,18 +592,34 @@
 	if (freq < 32000 || freq > 48000)
 		return -EINVAL;
 
+	/* The saa7113 has no audio clock */
+	if (state->ident == V4L2_IDENT_SAA7113)
+		return 0;
+
 	/* hz is the refresh rate times 100 */
 	hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
 	/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
 	acpf = (25600 * freq) / hz;
 	/* acni = (256 * freq * 2^23) / crystal_frequency =
 		  (freq * 2^(8+23)) / crystal_frequency =
-		  (freq << 31) / 32.11 MHz */
+		  (freq << 31) / crystal_frequency */
 	f = freq;
 	f = f << 31;
-	do_div(f, 32110000);
+	do_div(f, state->crystal_freq);
 	acni = f;
+	if (state->ucgc) {
+		acpf = acpf * state->cgcdiv / 16;
+		acni = acni * state->cgcdiv / 16;
+		acc = 0x80;
+		if (state->cgcdiv == 3)
+			acc |= 0x40;
+	}
+	if (state->apll)
+		acc |= 0x08;
 
+	saa7115_write(client, 0x38, 0x03);
+	saa7115_write(client, 0x39, 0x10);
+	saa7115_write(client, 0x3a, acc);
 	saa7115_write(client, 0x30, acpf & 0xff);
 	saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
 	saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
@@ -1073,48 +1090,6 @@
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
-static struct v4l2_queryctrl saa7115_qctrl[] = {
-	{
-		.id            = V4L2_CID_BRIGHTNESS,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Brightness",
-		.minimum       = 0,
-		.maximum       = 255,
-		.step          = 1,
-		.default_value = 128,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_CONTRAST,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Contrast",
-		.minimum       = 0,
-		.maximum       = 127,
-		.step          = 1,
-		.default_value = 64,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_SATURATION,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Saturation",
-		.minimum       = 0,
-		.maximum       = 127,
-		.step          = 1,
-		.default_value = 64,
-		.flags         = 0,
-	}, {
-		.id            = V4L2_CID_HUE,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-		.name          = "Hue",
-		.minimum       = -128,
-		.maximum       = 127,
-		.step          = 1,
-		.default_value = 0,
-		.flags 	       = 0,
-	},
-};
-
-/* ----------------------------------------------------------------------- */
-
 static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1158,14 +1133,16 @@
 	case VIDIOC_QUERYCTRL:
 	{
 		struct v4l2_queryctrl *qc = arg;
-		int i;
 
-		for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
-			if (qc->id && qc->id == saa7115_qctrl[i].id) {
-				memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
-				return 0;
-			}
-		return -EINVAL;
+		switch (qc->id) {
+			case V4L2_CID_BRIGHTNESS:
+			case V4L2_CID_CONTRAST:
+			case V4L2_CID_SATURATION:
+			case V4L2_CID_HUE:
+				return v4l2_ctrl_query_fill_std(qc);
+			default:
+				return -EINVAL;
+		}
 	}
 
 	case VIDIOC_G_STD:
@@ -1221,34 +1198,6 @@
 		break;
 	}
 
-	case VIDIOC_G_INPUT:
-		*(int *)arg = state->input;
-		break;
-
-	case VIDIOC_S_INPUT:
-		v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg);
-		/* inputs from 0-9 are available */
-		if (*iarg < 0 || *iarg > 9) {
-			return -EINVAL;
-		}
-
-		if (state->input == *iarg)
-			break;
-		v4l_dbg(1, debug, client, "now setting %s input\n",
-			*iarg >= 6 ? "S-Video" : "Composite");
-		state->input = *iarg;
-
-		/* select mode */
-		saa7115_write(client, 0x02,
-			      (saa7115_read(client, 0x02) & 0xf0) |
-			       state->input);
-
-		/* bypass chrominance trap for modes 6..9 */
-		saa7115_write(client, 0x09,
-			      (saa7115_read(client, 0x09) & 0x7f) |
-			       (state->input < 6 ? 0x0 : 0x80));
-		break;
-
 	case VIDIOC_STREAMON:
 	case VIDIOC_STREAMOFF:
 		v4l_dbg(1, debug, client, "%s output\n",
@@ -1260,6 +1209,21 @@
 		}
 		break;
 
+	case VIDIOC_INT_S_CRYSTAL_FREQ:
+	{
+		struct v4l2_crystal_freq *freq = arg;
+
+		if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+		    freq->freq != SAA7115_FREQ_24_576_MHZ)
+			return -EINVAL;
+		state->crystal_freq = freq->freq;
+		state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+		state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+		state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+		saa7115_set_audio_clock_freq(client, state->audclk_freq);
+		break;
+	}
+
 	case VIDIOC_INT_DECODE_VBI_LINE:
 		saa7115_decode_vbi_line(client, arg);
 		break;
@@ -1401,10 +1365,13 @@
 	v4l_dbg(1, debug, client, "writing init values\n");
 
 	/* init to 60hz/48khz */
-	if (state->ident == V4L2_IDENT_SAA7113)
+	if (state->ident == V4L2_IDENT_SAA7113) {
+		state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
 		saa7115_writeregs(client, saa7113_init_auto_input);
-	else
+	} else {
+		state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
 		saa7115_writeregs(client, saa7115_init_auto_input);
+	}
 	saa7115_writeregs(client, saa7115_init_misc);
 	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
 	saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index c271e2e..ad401bd 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -270,7 +270,7 @@
 	"letterbox 16:9 top",
 	"invalid",
 	"invalid",
-	"16:9 full format anamorphic"
+	"16:9 full format anamorphic",
 	"4:3 full format",
 	"invalid",
 	"invalid",
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 0e0ba50..de7b9e6 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -39,6 +39,23 @@
 	SAA6752HS_VF_UNKNOWN,
 };
 
+struct saa6752hs_mpeg_params {
+	/* transport streams */
+	__u16				ts_pid_pmt;
+	__u16				ts_pid_audio;
+	__u16				ts_pid_video;
+	__u16				ts_pid_pcr;
+
+	/* audio */
+	enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+
+	/* video */
+	enum v4l2_mpeg_video_aspect	vi_aspect;
+	enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
+	__u32 				vi_bitrate;
+	__u32 				vi_bitrate_peak;
+};
+
 static const struct v4l2_format v4l2_format_table[] =
 {
 	[SAA6752HS_VF_D1] =
@@ -55,18 +72,19 @@
 
 struct saa6752hs_state {
 	struct i2c_client             client;
-	struct v4l2_mpeg_compression  params;
+	struct v4l2_mpeg_compression  old_params;
+	struct saa6752hs_mpeg_params  params;
 	enum saa6752hs_videoformat    video_format;
 	v4l2_std_id                   standard;
 };
 
 enum saa6752hs_command {
 	SAA6752HS_COMMAND_RESET = 0,
-    	SAA6752HS_COMMAND_STOP = 1,
-    	SAA6752HS_COMMAND_START = 2,
-    	SAA6752HS_COMMAND_PAUSE = 3,
-    	SAA6752HS_COMMAND_RECONFIGURE = 4,
-    	SAA6752HS_COMMAND_SLEEP = 5,
+	SAA6752HS_COMMAND_STOP = 1,
+	SAA6752HS_COMMAND_START = 2,
+	SAA6752HS_COMMAND_PAUSE = 3,
+	SAA6752HS_COMMAND_RECONFIGURE = 4,
+	SAA6752HS_COMMAND_SLEEP = 5,
 	SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
 
 	SAA6752HS_COMMAND_MAX
@@ -129,7 +147,22 @@
 	0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
-static struct v4l2_mpeg_compression param_defaults =
+static struct saa6752hs_mpeg_params param_defaults =
+{
+	.ts_pid_pmt      = 16,
+	.ts_pid_video    = 260,
+	.ts_pid_audio    = 256,
+	.ts_pid_pcr      = 259,
+
+	.vi_aspect       = V4L2_MPEG_VIDEO_ASPECT_4x3,
+	.vi_bitrate      = 4000,
+	.vi_bitrate_peak = 6000,
+	.vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+
+	.au_l2_bitrate   = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+};
+
+static struct v4l2_mpeg_compression old_param_defaults =
 {
 	.st_type         = V4L2_MPEG_TS_2,
 	.st_bitrate      = {
@@ -228,45 +261,57 @@
 
 
 static int saa6752hs_set_bitrate(struct i2c_client* client,
-				 struct v4l2_mpeg_compression* params)
+				 struct saa6752hs_mpeg_params* params)
 {
 	u8 buf[3];
+	int tot_bitrate;
 
 	/* set the bitrate mode */
 	buf[0] = 0x71;
-	buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
+	buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
 	i2c_master_send(client, buf, 2);
 
 	/* set the video bitrate */
-	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
+	if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
 		/* set the target bitrate */
 		buf[0] = 0x80;
-	    	buf[1] = params->vi_bitrate.target >> 8;
-		buf[2] = params->vi_bitrate.target & 0xff;
+		buf[1] = params->vi_bitrate >> 8;
+		buf[2] = params->vi_bitrate & 0xff;
 		i2c_master_send(client, buf, 3);
 
 		/* set the max bitrate */
 		buf[0] = 0x81;
-	    	buf[1] = params->vi_bitrate.max >> 8;
-		buf[2] = params->vi_bitrate.max & 0xff;
+		buf[1] = params->vi_bitrate_peak >> 8;
+		buf[2] = params->vi_bitrate_peak & 0xff;
 		i2c_master_send(client, buf, 3);
+		tot_bitrate = params->vi_bitrate_peak;
 	} else {
 		/* 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[1] = params->vi_bitrate >> 8;
+		buf[2] = params->vi_bitrate & 0xff;
 		i2c_master_send(client, buf, 3);
+		tot_bitrate = params->vi_bitrate;
 	}
 
 	/* set the audio bitrate */
 	buf[0] = 0x94;
-	buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
+	buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
 	i2c_master_send(client, buf, 2);
+	tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+
+	/* Note: the total max bitrate is determined by adding the video and audio
+	   bitrates together and also adding an extra 768kbit/s to stay on the
+	   safe side. If more control should be required, then an extra MPEG control
+	   should be added. */
+	tot_bitrate += 768;
+	if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
+		tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
 
 	/* set the total bitrate */
 	buf[0] = 0xb1;
-	buf[1] = params->st_bitrate.target >> 8;
-	buf[2] = params->st_bitrate.target & 0xff;
+	buf[1] = tot_bitrate >> 8;
+	buf[2] = tot_bitrate & 0xff;
 	i2c_master_send(client, buf, 3);
 
 	return 0;
@@ -318,50 +363,188 @@
 }
 
 
-static void saa6752hs_set_params(struct i2c_client* client,
+static void saa6752hs_old_set_params(struct i2c_client* client,
 				 struct v4l2_mpeg_compression* params)
 {
 	struct saa6752hs_state *h = i2c_get_clientdata(client);
 
 	/* check PIDs */
-	if (params->ts_pid_pmt <= MPEG_PID_MAX)
+	if (params->ts_pid_pmt <= MPEG_PID_MAX) {
+		h->old_params.ts_pid_pmt = params->ts_pid_pmt;
 		h->params.ts_pid_pmt = params->ts_pid_pmt;
-	if (params->ts_pid_pcr <= MPEG_PID_MAX)
+	}
+	if (params->ts_pid_pcr <= MPEG_PID_MAX) {
+		h->old_params.ts_pid_pcr = params->ts_pid_pcr;
 		h->params.ts_pid_pcr = params->ts_pid_pcr;
-	if (params->ts_pid_video <= MPEG_PID_MAX)
+	}
+	if (params->ts_pid_video <= MPEG_PID_MAX) {
+		h->old_params.ts_pid_video = params->ts_pid_video;
 		h->params.ts_pid_video = params->ts_pid_video;
-	if (params->ts_pid_audio <= MPEG_PID_MAX)
+	}
+	if (params->ts_pid_audio <= MPEG_PID_MAX) {
+		h->old_params.ts_pid_audio = params->ts_pid_audio;
 		h->params.ts_pid_audio = params->ts_pid_audio;
+	}
 
 	/* check bitrate parameters */
 	if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
-	    (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
-		h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+	    (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
+		h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
+		h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
+		       V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+	}
 	if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
-		h->params.st_bitrate.target = params->st_bitrate.target;
+		h->old_params.st_bitrate.target = params->st_bitrate.target;
 	if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
-		h->params.vi_bitrate.target = params->vi_bitrate.target;
+		h->old_params.vi_bitrate.target = params->vi_bitrate.target;
 	if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
-		h->params.vi_bitrate.max = params->vi_bitrate.max;
+		h->old_params.vi_bitrate.max = params->vi_bitrate.max;
 	if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
-		h->params.au_bitrate.target = params->au_bitrate.target;
+		h->old_params.au_bitrate.target = params->au_bitrate.target;
 
 	/* aspect ratio */
 	if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
-	    params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
-		h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+	    params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
+		h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
+		if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
+			h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+		else
+			h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
+	}
 
 	/* range checks */
-	if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
-		h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
-	if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
-		h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
-	if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
-		h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
-	if (h->params.au_bitrate.target <= 256)
-		h->params.au_bitrate.target = 256;
+	if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+		h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+	if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+		h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+	if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+		h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+	h->params.vi_bitrate = params->vi_bitrate.target;
+	h->params.vi_bitrate_peak = params->vi_bitrate.max;
+	if (h->old_params.au_bitrate.target <= 256) {
+		h->old_params.au_bitrate.target = 256;
+		h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+	}
+	else {
+		h->old_params.au_bitrate.target = 384;
+		h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+	}
+}
+
+static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+		struct v4l2_ext_control *ctrl, int cmd)
+{
+	int old = 0, new;
+	int set = cmd == VIDIOC_S_EXT_CTRLS;
+
+	new = ctrl->value;
+	switch (ctrl->id) {
+		case V4L2_CID_MPEG_STREAM_TYPE:
+			old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+			if (set && new != old)
+				return -ERANGE;
+			new = old;
+			break;
+		case V4L2_CID_MPEG_STREAM_PID_PMT:
+			old = params->ts_pid_pmt;
+			if (set && new > MPEG_PID_MAX)
+				return -ERANGE;
+			if (new > MPEG_PID_MAX)
+				new = MPEG_PID_MAX;
+			params->ts_pid_pmt = new;
+			break;
+		case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+			old = params->ts_pid_audio;
+			if (set && new > MPEG_PID_MAX)
+				return -ERANGE;
+			if (new > MPEG_PID_MAX)
+				new = MPEG_PID_MAX;
+			params->ts_pid_audio = new;
+			break;
+		case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+			old = params->ts_pid_video;
+			if (set && new > MPEG_PID_MAX)
+				return -ERANGE;
+			if (new > MPEG_PID_MAX)
+				new = MPEG_PID_MAX;
+			params->ts_pid_video = new;
+			break;
+		case V4L2_CID_MPEG_STREAM_PID_PCR:
+			old = params->ts_pid_pcr;
+			if (set && new > MPEG_PID_MAX)
+				return -ERANGE;
+			if (new > MPEG_PID_MAX)
+				new = MPEG_PID_MAX;
+			params->ts_pid_pcr = new;
+			break;
+		case V4L2_CID_MPEG_AUDIO_ENCODING:
+			old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
+			if (set && new != old)
+				return -ERANGE;
+			new = old;
+			break;
+		case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+			old = params->au_l2_bitrate;
+			if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+				   new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+				return -ERANGE;
+			if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+				new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+			else
+				new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+			params->au_l2_bitrate = new;
+			break;
+		case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+			old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+			if (set && new != old)
+				return -ERANGE;
+			new = old;
+			break;
+		case V4L2_CID_MPEG_VIDEO_ENCODING:
+			old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+			if (set && new != old)
+				return -ERANGE;
+			new = old;
+			break;
+		case V4L2_CID_MPEG_VIDEO_ASPECT:
+			old = params->vi_aspect;
+			if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+				   new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+				return -ERANGE;
+			if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+				new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+			params->vi_aspect = new;
+			break;
+		case V4L2_CID_MPEG_VIDEO_BITRATE:
+			old = params->vi_bitrate * 1000;
+			new = 1000 * (new / 1000);
+			if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+				return -ERANGE;
+			if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+				new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+			params->vi_bitrate = new / 1000;
+			break;
+		case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+			old = params->vi_bitrate_peak * 1000;
+			new = 1000 * (new / 1000);
+			if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+				return -ERANGE;
+			if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+				new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+			params->vi_bitrate_peak = new / 1000;
+			break;
+		case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+			old = params->vi_bitrate_mode;
+			params->vi_bitrate_mode = new;
+			break;
+		default:
+			return -EINVAL;
+	}
+	if (cmd == VIDIOC_G_EXT_CTRLS)
+		ctrl->value = old;
 	else
-		h->params.au_bitrate.target = 384;
+		ctrl->value = new;
+	return 0;
 }
 
 static int saa6752hs_init(struct i2c_client* client)
@@ -395,22 +578,22 @@
 	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);
@@ -441,7 +624,7 @@
 	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;
@@ -489,11 +672,11 @@
 	buf[3] = 0x82;
 	buf[4] = 0xB0;
 	buf[5] = buf2[0];
-	switch(h->params.vi_aspect_ratio) {
-	case V4L2_MPEG_ASPECT_16_9:
+	switch(h->params.vi_aspect) {
+	case V4L2_MPEG_VIDEO_ASPECT_16x9:
 		buf[6] = buf2[1] | 0x40;
 		break;
-	case V4L2_MPEG_ASPECT_4_3:
+	case V4L2_MPEG_VIDEO_ASPECT_4x3:
 	default:
 		buf[6] = buf2[1] & 0xBF;
 		break;
@@ -515,6 +698,7 @@
 		return -ENOMEM;
 	h->client = client_template;
 	h->params = param_defaults;
+	h->old_params = old_param_defaults;
 	h->client.adapter = adap;
 	h->client.addr = addr;
 
@@ -550,20 +734,45 @@
 saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct saa6752hs_state *h = i2c_get_clientdata(client);
-	struct v4l2_mpeg_compression *params = arg;
+	struct v4l2_ext_controls *ctrls = arg;
+	struct v4l2_mpeg_compression *old_params = arg;
+	struct saa6752hs_mpeg_params params;
 	int err = 0;
+	int i;
 
 	switch (cmd) {
 	case VIDIOC_S_MPEGCOMP:
-		if (NULL == params) {
+		if (NULL == old_params) {
 			/* apply settings and start encoder */
 			saa6752hs_init(client);
 			break;
 		}
-		saa6752hs_set_params(client, params);
+		saa6752hs_old_set_params(client, old_params);
 		/* fall through */
 	case VIDIOC_G_MPEGCOMP:
-		*params = h->params;
+		*old_params = h->old_params;
+		break;
+	case VIDIOC_S_EXT_CTRLS:
+		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		if (ctrls->count == 0) {
+			/* apply settings and start encoder */
+			saa6752hs_init(client);
+			break;
+		}
+		/* fall through */
+	case VIDIOC_TRY_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS:
+		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		params = h->params;
+		for (i = 0; i < ctrls->count; i++) {
+			if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+				ctrls->error_idx = i;
+				return err;
+			}
+		}
+		h->params = params;
 		break;
 	case VIDIOC_G_FMT:
 	{
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index bb3e0ba..d77e6a8 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -818,7 +818,7 @@
 				break;
 		}
 
-	    	/* output xbar always main channel */
+		/* 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
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 86eae35..927413a 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2160,7 +2160,7 @@
 		.radio = {
 			  .name = name_radio,
 			  .amux = LINE2,
-    		},
+		},
 	},
 	[SAA7134_BOARD_GOTVIEW_7135] = {
 		/* Mike Baikov <mike@baikov.com> */
@@ -2842,6 +2842,55 @@
 			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
 		},
 	},
+	[SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+		/* "Zac Bowling" <zac@zacbowling.com> */
+		.name           = "LifeView FlyVIDEO3000 (NTSC)",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+
+		.gpiomask       = 0xe000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.gpio = 0x8000,
+			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_comp2,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x4000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0x2000,
+		},
+			.mute = {
+			.name = name_mute,
+			.amux = TV,
+			.gpio = 0x8000,
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2901,6 +2950,12 @@
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5169,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO3000_NTSC,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x5168,
 		.subdevice    = 0x0138,
 		.driver_data  = SAA7134_BOARD_FLYVIDEO3000,
@@ -3459,6 +3514,7 @@
 	switch (dev->board) {
 	case SAA7134_BOARD_FLYVIDEO2000:
 	case SAA7134_BOARD_FLYVIDEO3000:
+	case SAA7134_BOARD_FLYVIDEO3000_NTSC:
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		board_flyvideo(dev);
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 222a36c..279828b 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -132,9 +132,8 @@
 	return 0;
 }
 
-static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
-				  struct dvb_frontend_parameters* params,
-				  u8* pllbuf)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
+					   struct dvb_frontend_parameters* params)
 {
 	u8 off[] = { 0x00, 0xf1};
 	u8 on[]  = { 0x00, 0x71};
@@ -147,30 +146,31 @@
 	f.tuner     = 0;
 	f.type      = V4L2_TUNER_DIGITAL_TV;
 	f.frequency = params->frequency / 1000 * 16 / 1000;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 	saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
 	msg.buf = on;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
 	pinnacle_antenna_pwr(dev, antenna_pwr);
 
 	/* mt352 setup */
-	mt352_pinnacle_init(fe);
-	pllbuf[0] = 0xc2;
-	pllbuf[1] = 0x00;
-	pllbuf[2] = 0x00;
-	pllbuf[3] = 0x80;
-	pllbuf[4] = 0x00;
-	return 0;
+	return mt352_pinnacle_init(fe);
 }
 
-static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
-	pllbuf[0] = 0xc2;
+	if (buf_len < 5)
+		return -EINVAL;
+
+	pllbuf[0] = 0x61;
 	dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
 			  params->frequency,
 			  params->u.ofdm.bandwidth);
-	return 0;
+	return 5;
 }
 
 static struct mt352_config pinnacle_300i = {
@@ -179,13 +179,11 @@
 	.if2           = 36150,
 	.no_tuner      = 1,
 	.demod_init    = mt352_pinnacle_init,
-	.pll_set       = mt352_pinnacle_pll_set,
 };
 
 static struct mt352_config avermedia_777 = {
 	.demod_address = 0xf,
 	.demod_init    = mt352_aver777_init,
-	.pll_set       = mt352_aver777_pll_set,
 };
 #endif
 
@@ -268,6 +266,8 @@
 	tuner_buf[2] = 0xca;
 	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 	msleep(1);
@@ -281,6 +281,8 @@
 	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
 
 	/* setup PLL configuration */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 	msleep(1);
@@ -290,12 +292,12 @@
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_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)
+static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	return philips_tda6651_pll_set(0x60, fe, params);
 }
@@ -315,20 +317,17 @@
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_DEFAULT,
 	.if_freq       = TDA10046_FREQ_3617,
-	.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)
+static int philips_tu1216_tuner_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)
+static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	return philips_tda6651_pll_set(0x61, fe, params);
 }
@@ -341,21 +340,20 @@
 	.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)
+static int philips_europa_tuner_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 (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
 		return -EIO;
 	msleep(1);
@@ -365,18 +363,20 @@
 	init_msg.len  = 0x02;
 	msg[0] = 0x00;
 	msg[1] = 0x40;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	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)
+static int philips_td1316_tuner_set_params(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)
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	/* this message actually turns the tuner back to analog mode */
@@ -391,7 +391,20 @@
 	analog_msg.len  = 0x02;
 	msg[0] = 0x00;
 	msg[1] = 0x14;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+	return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+
+	if (dev->original_demod_sleep)
+		dev->original_demod_sleep(fe);
+	fe->ops.i2c_gate_ctrl(fe, 1);
+	return 0;
 }
 
 static struct tda1004x_config philips_europa_config = {
@@ -402,21 +415,20 @@
 	.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)
+static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	/* this message is to set up ATC and ALC */
 	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
 	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 	msleep(1);
@@ -424,22 +436,27 @@
 	return 0;
 }
 
-static void philips_fmd1216_analog(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	/* this message actually turns the tuner back to analog mode */
 	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
 	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
 	msleep(1);
 	fmd1216_init[2] = 0x86;
 	fmd1216_init[3] = 0x54;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
 	msleep(1);
+	return 0;
 }
 
-static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	u8 tuner_buf[4];
@@ -516,6 +533,8 @@
 	tuner_buf[2] = 0x80 | (cp << 6) | (mode  << 3) | 4;
 	tuner_buf[3] = 0x40 | band;
 
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 	return 0;
@@ -528,9 +547,6 @@
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_IFO_AUTO_NEG,
 	.if_freq       = TDA10046_FREQ_3613,
-	.pll_init      = philips_fmd1216_pll_init,
-	.pll_set       = philips_fmd1216_pll_set,
-	.pll_sleep	   = philips_fmd1216_analog,
 	.request_firmware = NULL,
 };
 
@@ -578,12 +594,12 @@
 	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
 };
 
-static int philips_tda827x_pll_init(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
 {
 	return 0;
 }
 
-static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	u8 tuner_buf[14];
@@ -630,6 +646,8 @@
 	tuner_buf[13] = 0x40;
 
 	tuner_msg.len = 14;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
 		return -EIO;
 
@@ -638,18 +656,23 @@
 	tuner_buf[0] = 0x30;
 	tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
 	tuner_msg.len = 2;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
 
 	return 0;
 }
 
-static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
 {
 	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) };
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+	return 0;
 }
 
 static struct tda1004x_config tda827x_lifeview_config = {
@@ -659,9 +682,6 @@
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.if_freq       = TDA10046_FREQ_045,
-	.pll_init      = philips_tda827x_pll_init,
-	.pll_set       = philips_tda827x_pll_set,
-	.pll_sleep	   = philips_tda827x_pll_sleep,
 	.request_firmware = NULL,
 };
 
@@ -753,6 +773,8 @@
 	tuner_buf[12] = 0x00;
 	tuner_buf[13] = 0x39;  // lpsel
 	msg.len = 14;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
 		return -EIO;
 
@@ -760,10 +782,14 @@
 	msg.len = 2;
 	reg2[0] = 0x60;
 	reg2[1] = 0x3c;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
 	reg2[0] = 0xa0;
 	reg2[1] = 0x40;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
 	msleep(2);
@@ -771,36 +797,43 @@
 	reg2[0] = 0x30;
 	reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
 	msg.len = 2;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
 	msleep(550);
 	reg2[0] = 0x50;
 	reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &msg, 1);
 
 	return 0;
 
 }
 
-static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827xa_tuner_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) };
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
+	return 0;
 }
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tiger_tuner_set_params(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);
@@ -816,7 +849,7 @@
 	return ret;
 }
 
-static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	static u8 data[] = { 0x3c, 0x33, 0x6a};
@@ -827,14 +860,15 @@
 	return 0;
 }
 
-static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_sleep(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);
+	philips_tda827xa_tuner_sleep( 0x61, fe);
+	return 0;
 }
 
 static struct tda1004x_config philips_tiger_config = {
@@ -844,15 +878,12 @@
 	.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,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	int ret;
 
@@ -860,16 +891,12 @@
 	return ret;
 }
 
-static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
 {
+	philips_tda827xa_tuner_sleep(0x60, fe);
 	return 0;
 }
 
-static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
-{
-	philips_tda827xa_pll_sleep(0x60, fe);
-}
-
 static struct tda1004x_config lifeview_trio_config = {
 	.demod_address = 0x09,
 	.invert        = 1,
@@ -877,15 +904,12 @@
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_TDA827X_GPL,
 	.if_freq       = TDA10046_FREQ_045,
-	.pll_init      = lifeview_trio_dvb_mode,
-	.pll_set       = lifeview_trio_pll_set,
-	.pll_sleep     = lifeview_trio_analog_mode,
 	.request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	int ret;
 
@@ -893,7 +917,7 @@
 	return ret;
 }
 
-static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	/* route TDA8275a AGC input to the channel decoder */
@@ -901,12 +925,13 @@
 	return 0;
 }
 
-static void ads_duo_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
 	/* route TDA8275a AGC input to the analog IF chip*/
 	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
-	philips_tda827xa_pll_sleep( 0x61, fe);
+	philips_tda827xa_tuner_sleep( 0x61, fe);
+	return 0;
 }
 
 static struct tda1004x_config ads_tech_duo_config = {
@@ -916,31 +941,24 @@
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_TDA827X_GPL,
 	.if_freq       = TDA10046_FREQ_045,
-	.pll_init      = ads_duo_dvb_mode,
-	.pll_set       = ads_duo_pll_set,
-	.pll_sleep     = ads_duo_analog_mode,
 	.request_firmware = NULL,
 };
 
 /* ------------------------------------------------------------------ */
 
-static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	int ret;
 	ret = philips_tda827xa_pll_set(0x60, fe, params);
 	return ret;
 }
 
-static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
 {
+	philips_tda827xa_tuner_sleep( 0x61, fe);
 	return 0;
 }
 
-static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
-{
-	philips_tda827xa_pll_sleep( 0x61, fe);
-}
-
 static struct tda1004x_config tevion_dvbt220rf_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -948,9 +966,6 @@
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_TDA827X,
 	.if_freq       = TDA10046_FREQ_045,
-	.pll_init      = tevion_dvb220rf_pll_init,
-	.pll_set       = tevion_dvb220rf_pll_set,
-	.pll_sleep     = tevion_dvb220rf_pll_sleep,
 	.request_firmware = NULL,
 };
 
@@ -961,8 +976,6 @@
 #ifdef HAVE_NXT200X
 static struct nxt200x_config avertvhda180 = {
 	.demod_address    = 0x0a,
-	.pll_address      = 0x61,
-	.pll_desc         = &dvb_pll_tdhu2,
 };
 
 static int nxt200x_set_pll_input(u8 *buf, int input)
@@ -976,8 +989,6 @@
 
 static struct nxt200x_config kworldatsc110 = {
 	.demod_address    = 0x0a,
-	.pll_address      = 0x61,
-	.pll_desc         = &dvb_pll_tuv1236d,
 	.set_pll_input    = nxt200x_set_pll_input,
 };
 #endif
@@ -1003,78 +1014,158 @@
 		printk("%s: pinnacle 300i dvb setup\n",dev->name);
 		dev->dvb.frontend = mt352_attach(&pinnacle_300i,
 						 &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+		}
 		break;
 
 	case SAA7134_BOARD_AVERMEDIA_777:
 		printk("%s: avertv 777 dvb setup\n",dev->name);
 		dev->dvb.frontend = mt352_attach(&avermedia_777,
 						 &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+		}
 		break;
 #endif
 #ifdef HAVE_TDA1004X
 	case SAA7134_BOARD_MD7134:
 		dev->dvb.frontend = tda10046_attach(&medion_cardbus,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TOUGH:
 		dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+		}
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
 		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
 		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
 		dev->dvb.frontend = tda10046_attach(&philips_europa_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+			dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+			dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_300:
 		dev->dvb.frontend = tda10046_attach(&philips_europa_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200:
 		dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
 		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 		dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_FLYDVBT_LR301:
 		dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_FLYDVB_TRIO:
 		dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
 		dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
 		dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
+		}
 		break;
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
 		dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
 						    &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+			dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+			dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+		}
 		break;
 #endif
 #ifdef HAVE_NXT200X
 	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
 		dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+		}
 		break;
 	case SAA7134_BOARD_KWORLD_ATSC110:
 		dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+		if (dev->dvb.frontend) {
+			dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+		}
 		break;
 #endif
 	default:
@@ -1088,7 +1179,7 @@
 	}
 
 	/* register everything else */
-	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 1d972ed..65d0440 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -64,8 +64,10 @@
 
 static int ts_init_encoder(struct saa7134_dev* dev)
 {
+	struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+
 	ts_reset_encoder(dev);
-	saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+	saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
 	dev->empress_started = 1;
 	return 0;
 }
@@ -162,6 +164,7 @@
 		       unsigned int cmd, void *arg)
 {
 	struct saa7134_dev *dev = file->private_data;
+	struct v4l2_ext_controls *ctrls = arg;
 
 	if (debug > 1)
 		v4l_print_ioctl(dev->name,cmd);
@@ -278,12 +281,31 @@
 		return saa7134_common_ioctl(dev, cmd, arg);
 
 	case VIDIOC_S_MPEGCOMP:
+		printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+				    "Replace with VIDIOC_S_EXT_CTRLS!");
 		saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
 		ts_init_encoder(dev);
 		return 0;
 	case VIDIOC_G_MPEGCOMP:
+		printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+				    "Replace with VIDIOC_G_EXT_CTRLS!");
 		saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
 		return 0;
+	case VIDIOC_S_EXT_CTRLS:
+		/* count == 0 is abused in saa6752hs.c, so that special
+		   case is handled here explicitly. */
+		if (ctrls->count == 0)
+			return 0;
+		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
+		ts_init_encoder(dev);
+		return 0;
+	case VIDIOC_G_EXT_CTRLS:
+		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+			return -EINVAL;
+		saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+		return 0;
 
 	default:
 		return -ENOIOCTLCMD;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 1426e4c..7c59549 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -37,6 +37,10 @@
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
+static int pinnacle_remote = 0;
+module_param(pinnacle_remote, int, 0644);    /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
 #define dprintk(fmt, arg...)	if (ir_debug) \
 	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
@@ -316,8 +320,13 @@
 	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;
+		if (pinnacle_remote == 0) {
+			ir->get_key   = get_key_pinnacle_color;
+			ir->ir_codes = ir_codes_pinnacle_color;
+		} else {
+			ir->get_key   = get_key_pinnacle_grey;
+			ir->ir_codes = ir_codes_pinnacle_grey;
+		}
 		break;
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
 		snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 353af3a..d5ee99c 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -33,6 +33,7 @@
 
 #include <asm/io.h>
 
+#include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
@@ -221,6 +222,7 @@
 #define SAA7134_BOARD_AVERMEDIA_A169_B1 92
 #define SAA7134_BOARD_MD7134_BRIDGE_2     93
 #define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -531,6 +533,7 @@
 
 	/* SAA7134_MPEG_DVB only */
 	struct videobuf_dvb        dvb;
+	int (*original_demod_sleep)(struct dvb_frontend* fe);
 };
 
 /* ----------------------------------------------------------- */
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
index a7a216b..c0891b3 100644
--- a/drivers/media/video/se401.h
+++ b/drivers/media/video/se401.h
@@ -4,6 +4,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/smp_lock.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index ea4394d..48d138a 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -2608,11 +2608,9 @@
 	case VIDIOC_G_CTRL:
 		return sn9c102_vidioc_g_ctrl(cam, arg);
 
-	case VIDIOC_S_CTRL_OLD:
 	case VIDIOC_S_CTRL:
 		return sn9c102_vidioc_s_ctrl(cam, arg);
 
-	case VIDIOC_CROPCAP_OLD:
 	case VIDIOC_CROPCAP:
 		return sn9c102_vidioc_cropcap(cam, arg);
 
@@ -2659,7 +2657,6 @@
 	case VIDIOC_G_PARM:
 		return sn9c102_vidioc_g_parm(cam, arg);
 
-	case VIDIOC_S_PARM_OLD:
 	case VIDIOC_S_PARM:
 		return sn9c102_vidioc_s_parm(cam, arg);
 
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 07476c7..6be9c11 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -42,6 +42,7 @@
 #include <asm/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include "saa7146.h"
 #include "saa7146reg.h"
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index b38bda8..351b182 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -66,6 +66,7 @@
 #include <linux/pagemap.h>
 #include <linux/errno.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 103ccb9..827633b 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -26,6 +26,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
@@ -163,7 +164,7 @@
 	struct tda9875 *t = i2c_get_clientdata(client);
 	dprintk("In tda9875_init\n");
 	tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
-    	tda9875_write(client, TDA9875_MSR, 0x03 );    /* Monitor 0b00000XXX*/
+	tda9875_write(client, TDA9875_MSR, 0x03 );    /* Monitor 0b00000XXX*/
 	tda9875_write(client, TDA9875_C1MSB, 0x00 );  /*Car1(FM) MSB XMHz*/
 	tda9875_write(client, TDA9875_C1MIB, 0x00 );  /*Car1(FM) MIB XMHz*/
 	tda9875_write(client, TDA9875_C1LSB, 0x00 );  /*Car1(FM) LSB XMHz*/
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 0d54f6c..b6ae969 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -18,49 +18,21 @@
    TDA9886 (PAL, SECAM, NTSC)
    TDA9887 (PAL, SECAM, NTSC, FM Radio)
 
-   found on:
-   - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
-      TDA9887 (world), TDA9885 (USA)
-      Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
-   - KNC One TV-Station RDS (saa7134)
-   - Hauppauge PVR-150/500 (possibly more)
+   Used as part of several tuners
 */
 
+#define tda9887_info(fmt, arg...) do {\
+	printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+	if (tuner_debug) \
+		printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
-	0x84 >>1,
-	0x86 >>1,
-	0x96 >>1,
-	I2C_CLIENT_END,
-};
-I2C_CLIENT_INSMOD;
-
-/* insmod options */
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_LICENSE("GPL");
 
 /* ---------------------------------------------------------------------- */
 
 #define UNSET       (-1U)
-#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;
-	v4l2_std_id        std;
-	enum tuner_mode    mode;
-	unsigned int       config;
-	unsigned int       using_v4l2;
-	unsigned int 	   radio_mode;
-	unsigned char 	   data[4];
-};
 
 struct tvnorm {
 	v4l2_std_id       std;
@@ -70,9 +42,6 @@
 	unsigned char     e;
 };
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* ---------------------------------------------------------------------- */
 
 //
@@ -281,7 +250,7 @@
 
 /* ---------------------------------------------------------------------- */
 
-static void dump_read_message(struct tda9887 *t, unsigned char *buf)
+static void dump_read_message(struct tuner *t, unsigned char *buf)
 {
 	static char *afc[16] = {
 		"- 12.5 kHz",
@@ -309,7 +278,7 @@
 	tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
 }
 
-static void dump_write_message(struct tda9887 *t, unsigned char *buf)
+static void dump_write_message(struct tuner *t, unsigned char *buf)
 {
 	static char *sound[4] = {
 		"AM/TV",
@@ -405,13 +374,13 @@
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
+static int tda9887_set_tvnorm(struct tuner *t, char *buf)
 {
 	struct tvnorm *norm = NULL;
 	int i;
 
-	if (t->mode == T_RADIO) {
-		if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+	if (t->mode == V4L2_TUNER_RADIO) {
+		if (t->audmode == V4L2_TUNER_MODE_MONO)
 			norm = &radio_mono;
 		else
 			norm = &radio_stereo;
@@ -445,7 +414,7 @@
 module_param(qss, int, 0644);
 module_param(adjust, int, 0644);
 
-static int tda9887_set_insmod(struct tda9887 *t, char *buf)
+static int tda9887_set_insmod(struct tuner *t, char *buf)
 {
 	if (UNSET != port1) {
 		if (port1)
@@ -474,27 +443,27 @@
 	return 0;
 }
 
-static int tda9887_set_config(struct tda9887 *t, char *buf)
+static int tda9887_set_config(struct tuner *t, char *buf)
 {
-	if (t->config & TDA9887_PORT1_ACTIVE)
+	if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
 		buf[1] &= ~cOutputPort1Inactive;
-	if (t->config & TDA9887_PORT1_INACTIVE)
+	if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
 		buf[1] |= cOutputPort1Inactive;
-	if (t->config & TDA9887_PORT2_ACTIVE)
+	if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
 		buf[1] &= ~cOutputPort2Inactive;
-	if (t->config & TDA9887_PORT2_INACTIVE)
+	if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
 		buf[1] |= cOutputPort2Inactive;
 
-	if (t->config & TDA9887_QSS)
+	if (t->tda9887_config & TDA9887_QSS)
 		buf[1] |= cQSS;
-	if (t->config & TDA9887_INTERCARRIER)
+	if (t->tda9887_config & TDA9887_INTERCARRIER)
 		buf[1] &= ~cQSS;
 
-	if (t->config & TDA9887_AUTOMUTE)
+	if (t->tda9887_config & TDA9887_AUTOMUTE)
 		buf[1] |= cAutoMuteFmActive;
-	if (t->config & TDA9887_DEEMPHASIS_MASK) {
+	if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
 		buf[2] &= ~0x60;
-		switch (t->config & TDA9887_DEEMPHASIS_MASK) {
+		switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
 		case TDA9887_DEEMPHASIS_NONE:
 			buf[2] |= cDeemphasisOFF;
 			break;
@@ -506,153 +475,36 @@
 			break;
 		}
 	}
-	if (t->config & TDA9887_TOP_SET) {
+	if (t->tda9887_config & TDA9887_TOP_SET) {
 		buf[2] &= ~cTopMask;
-		buf[2] |= (t->config >> 8) & cTopMask;
+		buf[2] |= (t->tda9887_config >> 8) & cTopMask;
 	}
-	if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
 		buf[1] &= ~cQSS;
 	return 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-module_param_string(pal, pal, sizeof(pal), 0644);
-module_param_string(secam, secam, sizeof(secam), 0644);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-
-static int tda9887_fixup_std(struct tda9887 *t)
-{
-	/* get more precise norm info from insmod option */
-	if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
-		switch (pal[0]) {
-		case 'b':
-		case 'B':
-		case 'g':
-		case 'G':
-		case 'h':
-		case 'H':
-		case 'n':
-		case 'N':
-			if (pal[1] == 'c' || pal[1] == 'C') {
-				tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
-				t->std = V4L2_STD_PAL_Nc;
-			} else {
-				tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
-				t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
-			}
-			break;
-		case 'i':
-		case 'I':
-			tda9887_dbg("insmod fixup: PAL => PAL-I\n");
-			t->std = V4L2_STD_PAL_I;
-			break;
-		case 'd':
-		case 'D':
-		case 'k':
-		case 'K':
-			tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
-			t->std = V4L2_STD_PAL_DK;
-			break;
-		case 'm':
-		case 'M':
-			tda9887_dbg("insmod fixup: PAL => PAL-M\n");
-			t->std = V4L2_STD_PAL_M;
-			break;
-		case '-':
-			/* default parameter, do nothing */
-			break;
-		default:
-			tda9887_info("pal= argument not recognised\n");
-			break;
-		}
-	}
-	if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
-		switch (secam[0]) {
-		case 'b':
-		case 'B':
-		case 'g':
-		case 'G':
-		case 'h':
-		case 'H':
-			tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
-			t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
-			break;
-		case 'd':
-		case 'D':
-		case 'k':
-		case 'K':
-			tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
-			t->std = V4L2_STD_SECAM_DK;
-			break;
-		case 'l':
-		case 'L':
-			if (secam[1] == 'c' || secam[1] == 'C') {
-				tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
-				t->std = V4L2_STD_SECAM_LC;
-			} else {
-				tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
-				t->std = V4L2_STD_SECAM_L;
-			}
-			break;
-		case '-':
-			/* default parameter, do nothing */
-			break;
-		default:
-			tda9887_info("secam= argument not recognised\n");
-			break;
-		}
-	}
-	if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
-		switch (ntsc[0]) {
-		case 'm':
-		case 'M':
-			tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
-			t->std = V4L2_STD_NTSC_M;
-			break;
-		case 'j':
-		case 'J':
-			tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
-			t->std = V4L2_STD_NTSC_M_JP;
-			break;
-		case 'k':
-		case 'K':
-			tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
-			t->std = V4L2_STD_NTSC_M_KR;
-			break;
-		case '-':
-			/* default parameter, do nothing */
-			break;
-		default:
-			tda9887_info("ntsc= argument not recognised\n");
-			break;
-		}
-	}
-	return 0;
-}
-
-static int tda9887_status(struct tda9887 *t)
+static int tda9887_status(struct tuner *t)
 {
 	unsigned char buf[1];
 	int rc;
 
 	memset(buf,0,sizeof(buf));
-	if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+	if (1 != (rc = i2c_master_recv(&t->i2c,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)
+static void tda9887_configure(struct i2c_client *client)
 {
+	struct tuner *t = i2c_get_clientdata(client);
 	int rc;
 
-	memset(t->data,0,sizeof(t->data));
-	tda9887_set_tvnorm(t,t->data);
+	memset(t->tda9887_data,0,sizeof(t->tda9887_data));
+	tda9887_set_tvnorm(t,t->tda9887_data);
 
 	/* A note on the port settings:
 	   These settings tend to depend on the specifics of the board.
@@ -667,249 +519,84 @@
 	   the ports should be set to active (0), but, again, that may
 	   differ depending on the precise hardware configuration.
 	 */
-	t->data[1] |= cOutputPort1Inactive;
-	t->data[1] |= cOutputPort2Inactive;
+	t->tda9887_data[1] |= cOutputPort1Inactive;
+	t->tda9887_data[1] |= cOutputPort2Inactive;
 
-	tda9887_set_config(t,t->data);
-	tda9887_set_insmod(t,t->data);
+	tda9887_set_config(t,t->tda9887_data);
+	tda9887_set_insmod(t,t->tda9887_data);
 
 	if (t->mode == T_STANDBY) {
-		t->data[1] |= cForcedMuteAudioON;
+		t->tda9887_data[1] |= cForcedMuteAudioON;
 	}
 
 	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(t, t->data);
+		t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+	if (tuner_debug > 1)
+		dump_write_message(t, t->tda9887_data);
 
-	if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+	if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
 		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
-	if (debug > 2) {
+	if (tuner_debug > 2) {
 		msleep_interruptible(1000);
 		tda9887_status(t);
 	}
-	return 0;
 }
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
+static void tda9887_tuner_status(struct i2c_client *client)
 {
-	struct tda9887 *t;
+	struct tuner *t = i2c_get_clientdata(client);
+	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+}
 
-	client_template.adapter = adap;
-	client_template.addr    = addr;
+static int tda9887_get_afc(struct i2c_client *client)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+	static int AFC_BITS_2_kHz[] = {
+		-12500,  -37500,  -62500,  -97500,
+		-112500, -137500, -162500, -187500,
+		187500,  162500,  137500,  112500,
+		97500 ,  62500,   37500 ,  12500
+	};
+	int afc=0;
+	__u8 reg = 0;
 
-	if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
-		return -ENOMEM;
+	if (1 == i2c_master_recv(&t->i2c,&reg,1))
+		afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
 
-	t->client      = client_template;
-	t->std         = 0;
-	t->radio_mode = V4L2_TUNER_MODE_STEREO;
+	return afc;
+}
 
-	tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
+static void tda9887_standby(struct i2c_client *client)
+{
+	tda9887_configure(client);
+}
 
-	i2c_set_clientdata(&t->client, t);
-	i2c_attach_client(&t->client);
+static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
+{
+	tda9887_configure(client);
+}
+
+int tda9887_tuner_init(struct i2c_client *c)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+
+	strlcpy(c->name, "tda9887", sizeof(c->name));
+
+	tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
+						t->i2c.driver->driver.name);
+
+	t->set_tv_freq = tda9887_set_freq;
+	t->set_radio_freq = tda9887_set_freq;
+	t->standby = tda9887_standby;
+	t->tuner_status=tda9887_tuner_status;
+	t->get_afc=tda9887_get_afc;
 
 	return 0;
 }
 
-static int tda9887_probe(struct i2c_adapter *adap)
-{
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, tda9887_attach);
-	return 0;
-}
-
-static int tda9887_detach(struct i2c_client *client)
-{
-	struct tda9887 *t = i2c_get_clientdata(client);
-
-	i2c_detach_client(client);
-	kfree(t);
-	return 0;
-}
-
-#define SWITCH_V4L2	if (!t->using_v4l2 && debug) \
-			  tda9887_info("switching to v4l2\n"); \
-			  t->using_v4l2 = 1;
-#define CHECK_V4L2	if (t->using_v4l2) { if (debug) \
-			  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) {
-
-	/* --- configuration --- */
-	case AUDC_SET_RADIO:
-	{
-		t->mode = T_RADIO;
-		tda9887_configure(t);
-		break;
-	}
-	case TUNER_SET_STANDBY:
-	{
-		t->mode = T_STANDBY;
-		tda9887_configure(t);
-		break;
-	}
-	case TDA9887_SET_CONFIG:
-	{
-		int *i = arg;
-
-		t->config = *i;
-		tda9887_configure(t);
-		break;
-	}
-	/* --- v4l ioctls --- */
-	/* take care: bttv does userspace copying, we'll get a
-	   kernel pointer here... */
-	case VIDIOCSCHAN:
-	{
-		static const v4l2_std_id map[] = {
-			[ VIDEO_MODE_PAL   ] = V4L2_STD_PAL,
-			[ VIDEO_MODE_NTSC  ] = V4L2_STD_NTSC_M,
-			[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
-			[ 4 /* bttv */     ] = V4L2_STD_PAL_M,
-			[ 5 /* bttv */     ] = V4L2_STD_PAL_N,
-			[ 6 /* bttv */     ] = V4L2_STD_NTSC_M_JP,
-		};
-		struct video_channel *vc = arg;
-
-		CHECK_V4L2;
-		t->mode = T_ANALOG_TV;
-		if (vc->norm < ARRAY_SIZE(map))
-			t->std = map[vc->norm];
-		tda9887_fixup_std(t);
-		tda9887_configure(t);
-		break;
-	}
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-
-		SWITCH_V4L2;
-		t->mode = T_ANALOG_TV;
-		t->std   = *id;
-		tda9887_fixup_std(t);
-		tda9887_configure(t);
-		break;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
-
-		SWITCH_V4L2;
-		if (V4L2_TUNER_ANALOG_TV == f->type) {
-			if (t->mode == T_ANALOG_TV)
-				return 0;
-			t->mode = T_ANALOG_TV;
-		}
-		if (V4L2_TUNER_RADIO == f->type) {
-			if (t->mode == T_RADIO)
-				return 0;
-			t->mode = T_RADIO;
-		}
-		tda9887_configure(t);
-		break;
-	}
-	case VIDIOC_G_TUNER:
-	{
-		static int AFC_BITS_2_kHz[] = {
-			-12500,  -37500,  -62500,  -97500,
-			-112500, -137500, -162500, -187500,
-			187500,  162500,  137500,  112500,
-			97500 ,  62500,   37500 ,  12500
-		};
-		struct v4l2_tuner* tuner = arg;
-
-		if (t->mode == T_RADIO) {
-			__u8 reg = 0;
-			tuner->afc=0;
-			if (1 == i2c_master_recv(&t->client,&reg,1))
-				tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
-		}
-		break;
-	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner* tuner = arg;
-
-		if (t->mode == T_RADIO) {
-			t->radio_mode = tuner->audmode;
-			tda9887_configure (t);
-		}
-		break;
-	}
-	case VIDIOC_LOG_STATUS:
-	{
-		tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
-		break;
-	}
-	default:
-		/* nothing */
-		break;
-	}
-	return 0;
-}
-
-static int tda9887_suspend(struct device * dev, pm_message_t state)
-{
-	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
-	struct tda9887 *t = i2c_get_clientdata(c);
-
-	tda9887_dbg("suspend\n");
-	return 0;
-}
-
-static int tda9887_resume(struct device * dev)
-{
-	struct i2c_client *c = container_of(dev, struct i2c_client, dev);
-	struct tda9887 *t = i2c_get_clientdata(c);
-
-	tda9887_dbg("resume\n");
-	tda9887_configure(t);
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
-	.id             = I2C_DRIVERID_TDA9887,
-	.attach_adapter = tda9887_probe,
-	.detach_client  = tda9887_detach,
-	.command        = tda9887_command,
-	.driver = {
-		.name    = "tda9887",
-		.suspend = tda9887_suspend,
-		.resume  = tda9887_resume,
-	},
-};
-static struct i2c_client client_template =
-{
-	.name      = "tda9887",
-	.driver    = &driver,
-};
-
-static int __init tda9887_init_module(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit tda9887_cleanup_module(void)
-{
-	i2c_del_driver(&driver);
-}
-
-module_init(tda9887_init_module);
-module_exit(tda9887_cleanup_module);
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index c2b98f8..d1c4178 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -3,7 +3,7 @@
  * I2C address is allways 0xC0.
  *
  *
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
  * This code is placed under the terms of the GNU General Public License
  *
  * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
new file mode 100644
index 0000000..76b2e96
--- /dev/null
+++ b/drivers/media/video/tlv320aic23b.c
@@ -0,0 +1,217 @@
+/*
+ * tlv320aic23b - driver version 0.0.1
+ *
+ * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
+ *
+ * Based on wm8775 driver
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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/v4l2-common.h>
+
+MODULE_DESCRIPTION("tlv320aic23b driver");
+MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct tlv320aic23b_state {
+	u8 muted;
+};
+
+static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+{
+	int i;
+
+	if ((reg < 0 || reg > 9) && (reg != 15)) {
+		v4l_err(client, "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;
+		}
+	}
+	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+	return -1;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg)
+{
+	struct tlv320aic23b_state *state = i2c_get_clientdata(client);
+	struct v4l2_control *ctrl = arg;
+	u32* freq = arg;
+
+	switch (cmd) {
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+		switch (*freq) {
+			case 32000: /* set sample rate to 32 kHz */
+				tlv320aic23b_write(client, 8, 0x018);
+				break;
+			case 44100: /* set sample rate to 44.1 kHz */
+				tlv320aic23b_write(client, 8, 0x022);
+				break;
+			case 48000: /* set sample rate to 48 kHz */
+				tlv320aic23b_write(client, 8, 0x000);
+				break;
+			default:
+				return -EINVAL;
+		}
+		break;
+
+	case VIDIOC_G_CTRL:
+		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		ctrl->value = state->muted;
+		break;
+
+	case VIDIOC_S_CTRL:
+		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		state->muted = ctrl->value;
+		tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
+		/* set gain on both channels to +3.0 dB */
+		if (!state->muted)
+			tlv320aic23b_write(client, 0, 0x119);
+		break;
+
+	case VIDIOC_LOG_STATUS:
+		v4l_info(client, "Input: %s\n",
+			    state->muted ? "muted" : "active");
+		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 tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct tlv320aic23b_state *state;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver;
+	snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+	state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	state->muted = 0;
+	i2c_set_clientdata(client, state);
+
+	/* initialize tlv320aic23b */
+	tlv320aic23b_write(client, 15, 0x000);	/* RESET */
+	tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
+	tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
+	tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
+	tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
+	tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
+
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+{
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+		return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
+	return 0;
+}
+
+static int tlv320aic23b_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 = {
+	.driver = {
+		.name = "tlv320aic23b",
+	},
+	.id             = I2C_DRIVERID_TLV320AIC23B,
+	.attach_adapter = tlv320aic23b_probe,
+	.detach_client  = tlv320aic23b_detach,
+	.command        = tlv320aic23b_command,
+};
+
+
+static int __init tlv320aic23b_init_module(void)
+{
+	return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit tlv320aic23b_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver);
+}
+
+module_init(tlv320aic23b_init_module);
+module_exit(tlv320aic23b_cleanup_module);
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
index 74ab48c..bdf506e 100644
--- a/drivers/media/video/tuner-3036.c
+++ b/drivers/media/video/tuner-3036.c
@@ -25,6 +25,7 @@
 
 #include <linux/i2c.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include <media/tuner.h>
 
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 1013b4d..a26ded7 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -199,7 +199,7 @@
 		i2c_master_send(c, buffer, 4);
 		default_tuner_init(c);
 		break;
-	case TUNER_LG_TDVS_H062F:
+	case TUNER_LG_TDVS_H06XF:
 		/* Set the Auxiliary Byte. */
 		buffer[2] &= ~0x20;
 		buffer[2] |= 0x18;
@@ -215,6 +215,9 @@
 		i2c_master_send(c,buffer,4);
 		default_tuner_init(c);
 		break;
+	case TUNER_TDA9887:
+		tda9887_tuner_init(c);
+		break;
 	default:
 		default_tuner_init(c);
 		break;
@@ -241,6 +244,8 @@
 {
 	struct tuner *t = i2c_get_clientdata(c);
 
+	tuner_dbg("set addr for type %i\n", t->type);
+
 	if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
 		(t->mode_mask & tun_setup->mode_mask)) ||
 		tun_setup->addr == c->addr)) {
@@ -436,6 +441,7 @@
 	t->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
 	t->audmode = V4L2_TUNER_MODE_STEREO;
 	t->mode_mask = T_UNINITIALIZED;
+	t->tuner_status = tuner_status;
 	if (tuner_debug_old) {
 		tuner_debug = tuner_debug_old;
 		printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
@@ -462,10 +468,14 @@
 		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;
+			if (tda8290_probe(&t->i2c) == 0) {
+				tuner_dbg("chip at addr %x is a tda8290\n", addr);
+			} else {
+				/* Default is being tda9887 */
+				t->type = TUNER_TDA9887;
+				t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+				t->mode = T_STANDBY;
+				goto register_client;
 			}
 			break;
 		case 0x60:
@@ -592,6 +602,7 @@
 	case TUNER_SET_STANDBY:
 		if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
 			return 0;
+		t->mode = T_STANDBY;
 		if (t->standby)
 			t->standby (client);
 		break;
@@ -604,6 +615,14 @@
 		/* Should be implemented, since bttv calls it */
 		tuner_dbg("VIDIOCSAUDIO not implemented.\n");
 		break;
+	case TDA9887_SET_CONFIG:
+	{
+		int *i = arg;
+
+		t->tda9887_config = *i;
+		set_freq(client, t->tv_freq);
+		break;
+	}
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
@@ -711,14 +730,10 @@
 		{
 			struct v4l2_frequency *f = arg;
 
+			if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+					== EINVAL)
+				return 0;
 			switch_v4l2();
-			if ((V4L2_TUNER_RADIO == f->type && V4L2_TUNER_RADIO != t->mode)
-				|| (V4L2_TUNER_DIGITAL_TV == f->type
-					&& V4L2_TUNER_DIGITAL_TV != t->mode)) {
-				if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
-					    == EINVAL)
-					return 0;
-			}
 			set_freq(client,f->frequency);
 
 			break;
@@ -744,6 +759,8 @@
 			switch_v4l2();
 
 			tuner->type = t->mode;
+			if (t->get_afc)
+				tuner->afc=t->get_afc(client);
 			if (t->mode == V4L2_TUNER_ANALOG_TV)
 				tuner->capability |= V4L2_TUNER_CAP_NORM;
 			if (t->mode != V4L2_TUNER_RADIO) {
@@ -787,7 +804,8 @@
 			break;
 		}
 	case VIDIOC_LOG_STATUS:
-		tuner_status(client);
+		if (t->tuner_status)
+			t->tuner_status(client);
 		break;
 	}
 
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 5d7abed..6da6f82 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -105,7 +105,7 @@
 
 	switch (t->type) {
 		case TUNER_PHILIPS_FM1216ME_MK3:
-    		case TUNER_PHILIPS_FM1236_MK3:
+		case TUNER_PHILIPS_FM1236_MK3:
 		case TUNER_PHILIPS_FM1256_IH3:
 			stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
 			break;
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index a1ae036..9d9226c 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -874,7 +874,7 @@
 };
 
 
-/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
+/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
 
 static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
 	{ 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
@@ -883,7 +883,7 @@
 };
 
 
-static struct tuner_params tuner_tua6034_params[] = {
+static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_tua6034_ntsc_ranges,
@@ -1024,6 +1024,22 @@
 	},
 };
 
+/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
+
+static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
+	{ 16 * 146.25 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 428.50 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 999.99        , 0xce, 0x08, },
+};
+
+static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
+	},
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1354,10 +1370,10 @@
 		.params = tuner_philips_fmd1216me_mk3_params,
 		.count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
 	},
-	[TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
-		.name   = "LG TDVS-H062F/TUA6034",
-		.params = tuner_tua6034_params,
-		.count  = ARRAY_SIZE(tuner_tua6034_params),
+	[TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
+		.name   = "LG TDVS-H06xF", /* H061F, H062F & H064F */
+		.params = tuner_lg_tdvs_h06xf_params,
+		.count  = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
 	},
 	[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
 		.name   = "Ymec TVF66T5-B/DFF",
@@ -1400,6 +1416,16 @@
 		.params = tuner_thomson_fe6600_params,
 		.count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
 	},
+	[TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
+		.name   = "Samsung TCPG 6121P30A",
+		.params = tuner_samsung_tcpg_6121p30a_params,
+		.count  = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
+	},
+	[TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
+				This chip is part of some modern tuners */
+		.name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
+		/* see tda9887.c for details */
+	},
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index b463e99..30f8d80 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -200,7 +200,7 @@
 	{ TUNER_ABSENT,        "Philips FQ1286A MK4"},
 	{ TUNER_ABSENT,        "Philips FQ1216ME MK5"},
 	{ TUNER_ABSENT,        "Philips FQ1236 MK5"},
-	{ TUNER_ABSENT,        "Samsung TCPG_6121P30A"},
+	{ TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
 	{ TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
 	{ TUNER_ABSENT,        "TCL 2002MI_3H"},
 	{ TUNER_TCL_2002N,     "TCL 2002N 5H"},
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 9e86cae..1654576 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -198,10 +198,6 @@
 
 	/* lock bttv in memory while the mixer is in use  */
 	file->private_data = mix;
-#ifndef I2C_PEC
-	if (client->adapter->inc_use)
-		client->adapter->inc_use(client->adapter);
-#endif
 	if (client->adapter->owner)
 		try_module_get(client->adapter->owner);
 	return 0;
@@ -217,10 +213,6 @@
 		return -ENODEV;
 	}
 
-#ifndef I2C_PEC
-	if (client->adapter->dec_use)
-		client->adapter->dec_use(client->adapter);
-#endif
 	if (client->adapter->owner)
 		module_put(client->adapter->owner);
 	return 0;
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index dab4973..b167ffa 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -10,6 +10,7 @@
 #include <linux/delay.h>
 #include <linux/video_decoder.h>
 #include <media/v4l2-common.h>
+#include <media/tvp5150.h>
 
 #include "tvp5150_reg.h"
 
@@ -89,7 +90,7 @@
 	struct i2c_client *client;
 
 	v4l2_std_id norm;	/* Current set standard */
-	int input;
+	struct v4l2_routing route;
 	int enable;
 	int bright;
 	int contrast;
@@ -283,29 +284,26 @@
 /****************************************************************************
 			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)
+static inline void tvp5150_selmux(struct i2c_client *c)
 {
 	int opmode=0;
-
 	struct tvp5150 *decoder = i2c_get_clientdata(c);
+	int input = 0;
 
-	if (!decoder->enable)
-		input |= TVP5150_BLACK_SCREEN;
+	if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+		input = 8;
 
 	switch (input) {
-	case TVP5150_ANALOG_CH0:
-	case TVP5150_ANALOG_CH1:
+	case TVP5150_COMPOSITE1:
+		input |= 2;
+		/* fall through */
+	case TVP5150_COMPOSITE0:
 		opmode=0x30;		/* TV Mode */
 		break;
+	case TVP5150_SVIDEO:
 	default:
+		input |= 1;
 		opmode=0;		/* Auto Mode */
 		break;
 	}
@@ -790,7 +788,7 @@
 	tvp5150_vdp_init(c, vbi_ram_default);
 
 	/* Selects decoder input */
-	tvp5150_selmux(c, decoder->input);
+	tvp5150_selmux(c);
 
 	/* Initializes TVP5150 to stream enabled values */
 	tvp5150_write_inittab(c, tvp5150_init_enable);
@@ -860,6 +858,21 @@
 	case VIDIOC_INT_RESET:
 		tvp5150_reset(c);
 		break;
+	case VIDIOC_INT_G_VIDEO_ROUTING:
+	{
+		struct v4l2_routing *route = arg;
+
+		*route = decoder->route;
+		break;
+	}
+	case VIDIOC_INT_S_VIDEO_ROUTING:
+	{
+		struct v4l2_routing *route = arg;
+
+		decoder->route = *route;
+		tvp5150_selmux(c);
+		break;
+	}
 	case VIDIOC_S_STD:
 		if (decoder->norm == *(v4l2_std_id *)arg)
 			break;
@@ -1063,7 +1076,7 @@
 	rv = i2c_attach_client(c);
 
 	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
-	core->input = 2;
+	core->route.input = TVP5150_COMPOSITE1;
 	core->enable = 1;
 	core->bright = 32768;
 	core->contrast = 32768;
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index 39269a2..59fb899 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -36,3 +36,15 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called konicawc.
+
+config USB_QUICKCAM_MESSENGER
+	tristate "USB Logitech Quickcam Messenger"
+	depends on USB && VIDEO_DEV
+	select VIDEO_USBVIDEO
+	---help---
+	  Say Y or M here to enable support for the USB Logitech Quickcam
+	  Messenger webcam.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called quickcam_messenger.
+
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
index bb52eb8..4a1b144 100644
--- a/drivers/media/video/usbvideo/Makefile
+++ b/drivers/media/video/usbvideo/Makefile
@@ -2,3 +2,4 @@
 obj-$(CONFIG_USB_IBMCAM)        += ibmcam.o ultracam.o
 obj-$(CONFIG_USB_KONICAWC)      += konicawc.o
 obj-$(CONFIG_USB_VICAM)         += vicam.o
+obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
new file mode 100644
index 0000000..56e01b6
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -0,0 +1,1120 @@
+/*
+ * Driver for Logitech Quickcam Messenger usb video camera
+ * Copyright (C) Jaya Kumar
+ *
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ * History:
+ * 05/08/2006 - Jaya Kumar
+ * I wrote this based on the konicawc by Simon Evans.
+ * -
+ * Full credit for reverse engineering and creating an initial
+ * working linux driver for the VV6422 goes to the qce-ga project by
+ * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
+ * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
+ * others.
+ * ---
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb/input.h>
+
+#include "usbvideo.h"
+#include "quickcam_messenger.h"
+
+/*
+ * Version Information
+ */
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define DRIVER_VERSION "v0.01"
+#define DRIVER_DESC "Logitech Quickcam Messenger USB"
+
+#define USB_LOGITECH_VENDOR_ID	0x046D
+#define USB_QCM_PRODUCT_ID	0x08F0
+
+#define MAX_CAMERAS	1
+
+#define MAX_COLOUR	32768
+#define MAX_HUE		32768
+#define MAX_BRIGHTNESS	32768
+#define MAX_CONTRAST	32768
+#define MAX_WHITENESS	32768
+
+static int size = SIZE_320X240;
+static int colour = MAX_COLOUR;
+static int hue = MAX_HUE;
+static int brightness =	MAX_BRIGHTNESS;
+static int contrast =	MAX_CONTRAST;
+static int whiteness =	MAX_WHITENESS;
+
+static struct usbvideo *cams;
+
+static struct usb_device_id qcm_table [] = {
+	{ USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, qcm_table);
+
+#ifdef CONFIG_INPUT
+static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
+{
+	struct input_dev *input_dev;
+
+	usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+	strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+
+	cam->input = input_dev = input_allocate_device();
+	if (!input_dev) {
+		warn("insufficient mem for cam input device");
+		return;
+	}
+
+	input_dev->name = "QCM button";
+	input_dev->phys = cam->input_physname;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->cdev.dev = &dev->dev;
+
+	input_dev->evbit[0] = BIT(EV_KEY);
+	input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+	input_dev->private = cam;
+
+	input_register_device(cam->input);
+}
+
+static void qcm_unregister_input(struct qcm *cam)
+{
+	if (cam->input) {
+		input_unregister_device(cam->input);
+		cam->input = NULL;
+	}
+}
+
+static void qcm_report_buttonstat(struct qcm *cam)
+{
+	if (cam->input) {
+		input_report_key(cam->input, BTN_0, cam->button_sts);
+		input_sync(cam->input);
+	}
+}
+
+static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
+{
+	int ret;
+	struct uvd *uvd = urb->context;
+	struct qcm *cam;
+
+	if (!CAMERA_IS_OPERATIONAL(uvd))
+		return;
+
+	if (!uvd->streaming)
+		return;
+
+	uvd->stats.urb_count++;
+
+	if (urb->status < 0)
+		uvd->stats.iso_err_count++;
+	else {
+		if (urb->actual_length > 0 ) {
+			cam = (struct qcm *) uvd->user_data;
+			if (cam->button_sts_buf == 0x88)
+				cam->button_sts = 0x0;
+			else if (cam->button_sts_buf == 0x80)
+				cam->button_sts = 0x1;
+			qcm_report_buttonstat(cam);
+		}
+	}
+
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret < 0)
+		err("usb_submit_urb error (%d)", ret);
+}
+
+static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
+{
+	int errflag;
+	usb_fill_int_urb(cam->button_urb, uvd->dev,
+			usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
+			&cam->button_sts_buf,
+			1,
+			qcm_int_irq,
+			uvd, 16);
+
+	errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
+	if (errflag)
+		err ("usb_submit_int ret %d", errflag);
+	return errflag;
+}
+
+static void qcm_stop_int_data(struct qcm *cam)
+{
+	usb_kill_urb(cam->button_urb);
+}
+
+static int qcm_alloc_int_urb(struct qcm *cam)
+{
+	cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+	if (!cam->button_urb)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void qcm_free_int(struct qcm *cam)
+{
+	if (cam->button_urb)
+		usb_free_urb(cam->button_urb);
+}
+#endif /* CONFIG_INPUT */
+
+static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
+{
+	int ret;
+
+	/* we'll wait up to 3 slices but no more */
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+		reg, 0, &val, 1, 3*HZ);
+	return ret;
+}
+
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+{
+	int ret;
+
+	/* we'll wait up to 3 slices but no more */
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+		reg, 0, &val, 2, 3*HZ);
+	return ret;
+}
+
+static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
+							__le16 *val)
+{
+	int ret;
+
+	/* we'll wait up to 3 slices but no more */
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+		reg, 0, val, 2, 3*HZ);
+	return ret;
+}
+
+static int qcm_camera_on(struct uvd *uvd)
+{
+	int ret;
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
+	return 0;
+}
+
+static int qcm_camera_off(struct uvd *uvd)
+{
+	int ret;
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+	return 0;
+}
+
+static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
+{
+	unsigned int segment, valsat;
+	signed int   h = (signed int) hue;
+	unsigned int s = (sat - 32768) * 2;	/* rescale */
+	unsigned int v = val;
+	unsigned int p;
+
+	/*
+	the registers controling gain are 8 bit of which
+	we affect only the last 4 bits with our gain.
+	we know that if saturation is 0, (unsaturated) then
+	we're grayscale (center axis of the colour cone) so
+	we set rgb=value. we use a formula obtained from
+	wikipedia to map the cone to the RGB plane. it's
+	as follows for the human value case of h=0..360,
+	s=0..1, v=0..1
+	h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
+	q = v(1 - f*s) , t = v(1 - (1-f)s)
+	h_i==0 => r=v , g=t, b=p
+	h_i==1 => r=q , g=v, b=p
+	h_i==2 => r=p , g=v, b=t
+	h_i==3 => r=p , g=q, b=v
+	h_i==4 => r=t , g=p, b=v
+	h_i==5 => r=v , g=p, b=q
+	the bottom side (the point) and the stuff just up
+	of that is black so we simplify those two cases.
+	*/
+	if (sat < 32768) {
+		/* anything less than this is unsaturated */
+		*r = val;
+		*g = val;
+		*b = val;
+		return;
+	}
+	if (val <= (0xFFFF/8)) {
+		/* anything less than this is black */
+		*r = 0;
+		*g = 0;
+		*b = 0;
+		return;
+	}
+
+	/* the rest of this code is copying tukkat's
+	implementation of the hsv2rgb conversion as taken
+	from qc-usb-messenger code. the 10923 is 0xFFFF/6
+	to divide the cone into 6 sectors.  */
+
+	segment = (h + 10923) & 0xFFFF;
+	segment = segment*3 >> 16;		/* 0..2: 0=R, 1=G, 2=B */
+	hue -= segment * 21845;			/* -10923..10923 */
+	h = hue;
+	h *= 3;
+	valsat = v*s >> 16;			/* 0..65534 */
+	p = v - valsat;
+	if (h >= 0) {
+		unsigned int t = v - (valsat * (32769 - h) >> 15);
+		switch (segment) {
+		case 0:	/* R-> */
+			*r = v;
+			*g = t;
+			*b = p;
+			break;
+		case 1:	/* G-> */
+			*r = p;
+			*g = v;
+			*b = t;
+			break;
+		case 2:	/* B-> */
+			*r = t;
+			*g = p;
+			*b = v;
+			break;
+		}
+	} else {
+		unsigned int q = v - (valsat * (32769 + h) >> 15);
+		switch (segment) {
+		case 0:	/* ->R */
+			*r = v;
+			*g = p;
+			*b = q;
+			break;
+		case 1:	/* ->G */
+			*r = q;
+			*g = v;
+			*b = p;
+			break;
+		case 2:	/* ->B */
+			*r = p;
+			*g = q;
+			*b = v;
+			break;
+		}
+	}
+}
+
+static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
+	u16 saturation, u16 value)
+{
+	int ret;
+	u16 r=0,g=0,b=0;
+
+	/* this code is based on qc-usb-messenger */
+	qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
+
+	r >>= 12;
+	g >>= 12;
+	b >>= 12;
+
+	/* min val is 8 */
+	r = max((u16) 8, r);
+	g = max((u16) 8, g);
+	b = max((u16) 8, b);
+
+	r |= 0x30;
+	g |= 0x30;
+	b |= 0x30;
+
+	/* set the r,g,b gain registers */
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
+
+	/* doing as qc-usb did */
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+	return 0;
+}
+
+static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
+{
+	int ret;
+	int formedval;
+
+	/* calculation was from qc-usb-messenger driver */
+	formedval = ( exposure >> 12 );
+
+	/* max value for formedval is 14 */
+	formedval = min(formedval, 14);
+
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+			0x143A, 0xF0 | formedval));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+	return 0;
+}
+
+static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
+					int hue, int colour)
+{
+	int ret;
+	/* brightness is exposure, contrast is gain, colour is saturation */
+	CHECK_RET(ret,
+		qcm_sensor_set_exposure(uvd, brightness));
+	CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
+
+	return 0;
+}
+
+static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
+{
+	int ret;
+
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
+	return 0;
+}
+
+static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
+{
+	int ret;
+	/* some rescaling as done by the qc-usb-messenger code */
+	if (whiteness > 0xC000)
+		whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
+
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
+				(whiteness >> 8) & 0xFF));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
+				(whiteness >> 16) & 0x03));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+	return 0;
+}
+
+static int qcm_sensor_init(struct uvd *uvd)
+{
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+	int ret;
+	int i;
+
+	for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+		CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+					regval_table[i].reg,
+					regval_table[i].val));
+	}
+
+	CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
+				cpu_to_le16(ISOC_PACKET_SIZE)));
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
+	CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+
+	CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+
+	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+	CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
+			uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
+
+	CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+	return 0;
+}
+
+static int qcm_set_camera_size(struct uvd *uvd)
+{
+	int ret;
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+
+	CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+	cam->width = camera_sizes[cam->size].width;
+	cam->height = camera_sizes[cam->size].height;
+	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+	return 0;
+}
+
+static int qcm_setup_on_open(struct uvd *uvd)
+{
+	int ret;
+
+	CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
+				uvd->vpic.colour, uvd->vpic.contrast));
+	CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
+	CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+	CHECK_RET(ret, qcm_set_camera_size(uvd));
+	CHECK_RET(ret, qcm_camera_on(uvd));
+	return 0;
+}
+
+static void qcm_adjust_picture(struct uvd *uvd)
+{
+	int ret;
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+
+	ret = qcm_camera_off(uvd);
+	if (ret) {
+		err("can't turn camera off. abandoning pic adjustment");
+		return;
+	}
+
+	/* if there's been a change in contrast, hue, or
+	colour then we need to recalculate hsv in order
+	to update gains */
+	if ((cam->contrast != uvd->vpic.contrast) ||
+		(cam->hue != uvd->vpic.hue) ||
+		(cam->colour != uvd->vpic.colour)) {
+		cam->contrast = uvd->vpic.contrast;
+		cam->hue = uvd->vpic.hue;
+		cam->colour = uvd->vpic.colour;
+		ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
+						cam->contrast);
+		if (ret) {
+			err("can't set gains. abandoning pic adjustment");
+			return;
+		}
+	}
+
+	if (cam->brightness != uvd->vpic.brightness) {
+		cam->brightness = uvd->vpic.brightness;
+		ret = qcm_sensor_set_exposure(uvd, cam->brightness);
+		if (ret) {
+			err("can't set exposure. abandoning pic adjustment");
+			return;
+		}
+	}
+
+	if (cam->whiteness != uvd->vpic.whiteness) {
+		cam->whiteness = uvd->vpic.whiteness;
+		qcm_sensor_set_shutter(uvd, cam->whiteness);
+		if (ret) {
+			err("can't set shutter. abandoning pic adjustment");
+			return;
+		}
+	}
+
+	ret = qcm_camera_on(uvd);
+	if (ret) {
+		err("can't reenable camera. pic adjustment failed");
+		return;
+	}
+}
+
+static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
+{
+	int datalen;
+	int totaldata;
+	struct framehdr {
+		__be16 id;
+		__be16 len;
+	};
+	struct framehdr *fhdr;
+
+	totaldata = 0;
+	while (framelen) {
+		fhdr = (struct framehdr *) cdata;
+		datalen = be16_to_cpu(fhdr->len);
+		framelen -= 4;
+		cdata += 4;
+
+		if ((fhdr->id) == cpu_to_be16(0x8001)) {
+			RingQueue_Enqueue(&uvd->dp, marker, 4);
+			totaldata += 4;
+			continue;
+		}
+		if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
+			RingQueue_Enqueue(&uvd->dp, cdata, datalen);
+			totaldata += datalen;
+		}
+		framelen -= datalen;
+		cdata += datalen;
+	}
+	return totaldata;
+}
+
+static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
+{
+	int totlen;
+	int i;
+	unsigned char *cdata;
+
+	totlen=0;
+	for (i = 0; i < dataurb->number_of_packets; i++) {
+		int n = dataurb->iso_frame_desc[i].actual_length;
+		int st = dataurb->iso_frame_desc[i].status;
+
+		cdata = dataurb->transfer_buffer +
+			dataurb->iso_frame_desc[i].offset;
+
+		if (st < 0) {
+			warn("Data error: packet=%d. len=%d. status=%d.",
+			      i, n, st);
+			uvd->stats.iso_err_count++;
+			continue;
+		}
+		if (!n)
+			continue;
+
+		totlen += qcm_process_frame(uvd, cdata, n);
+	}
+	return totlen;
+}
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+	int ret;
+
+	urb->dev = uvd->dev;
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret)
+		err("usb_submit_urb error (%d)", ret);
+}
+
+static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+	int len;
+	struct uvd *uvd = urb->context;
+
+	if (!CAMERA_IS_OPERATIONAL(uvd))
+		return;
+
+	if (!uvd->streaming)
+		return;
+
+	uvd->stats.urb_count++;
+
+	if (!urb->actual_length) {
+		resubmit_urb(uvd, urb);
+		return;
+	}
+
+	len = qcm_compress_iso(uvd, urb);
+	resubmit_urb(uvd, urb);
+	uvd->stats.urb_length = len;
+	uvd->stats.data_count += len;
+	if (len)
+		RingQueue_WakeUpInterruptible(&uvd->dp);
+}
+
+static int qcm_start_data(struct uvd *uvd)
+{
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+	int i;
+	int errflag;
+	int pktsz;
+	int err;
+
+	pktsz = uvd->iso_packet_len;
+	if (!CAMERA_IS_OPERATIONAL(uvd)) {
+		err("Camera is not operational");
+		return -EFAULT;
+	}
+
+	err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
+	if (err < 0) {
+		err("usb_set_interface error");
+		uvd->last_error = err;
+		return -EBUSY;
+	}
+
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		int j, k;
+		struct urb *urb = uvd->sbuf[i].urb;
+		urb->dev = uvd->dev;
+		urb->context = uvd;
+		urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
+		urb->interval = 1;
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = uvd->sbuf[i].data;
+		urb->complete = qcm_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+		for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length = pktsz;
+		}
+	}
+
+	uvd->streaming = 1;
+	uvd->curframe = -1;
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+		if (errflag)
+			err ("usb_submit_isoc(%d) ret %d", i, errflag);
+	}
+
+	CHECK_RET(err, qcm_setup_input_int(cam, uvd));
+	CHECK_RET(err, qcm_camera_on(uvd));
+	return 0;
+}
+
+static void qcm_stop_data(struct uvd *uvd)
+{
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+	int i, j;
+	int ret;
+
+	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+		return;
+
+	ret = qcm_camera_off(uvd);
+	if (ret)
+		warn("couldn't turn the cam off.");
+
+	uvd->streaming = 0;
+
+	/* Unschedule all of the iso td's */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++)
+		usb_kill_urb(uvd->sbuf[i].urb);
+
+	qcm_stop_int_data(cam);
+
+	if (!uvd->remove_pending) {
+		/* Set packet size to 0 */
+		j = usb_set_interface(uvd->dev, uvd->iface,
+					uvd->ifaceAltInactive);
+		if (j < 0) {
+			err("usb_set_interface() error %d.", j);
+			uvd->last_error = j;
+		}
+	}
+}
+
+static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+	int x;
+	struct rgb *rgbL0;
+	struct rgb *rgbL1;
+	struct bayL0 *bayL0;
+	struct bayL1 *bayL1;
+	int hor,ver,hordel,verdel;
+	assert(frame != NULL);
+
+	switch (cam->size) {
+	case SIZE_160X120:
+		hor = 162; ver = 124; hordel = 1; verdel = 2;
+		break;
+	case SIZE_320X240:
+	default:
+		hor = 324; ver = 248; hordel = 2; verdel = 4;
+		break;
+	}
+
+	if (frame->scanstate == ScanState_Scanning) {
+		while (RingQueue_GetLength(&uvd->dp) >=
+			 4 + (hor*verdel + hordel)) {
+			if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
+				frame->curline = 0;
+				frame->scanstate = ScanState_Lines;
+				frame->frameState = FrameState_Grabbing;
+				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+			/*
+			* if we're starting, we need to discard the first
+			* 4 lines of y bayer data
+			* and the first 2 gr elements of x bayer data
+			*/
+				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
+							(hor*verdel + hordel));
+				break;
+			}
+			RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+		}
+	}
+
+	if (frame->scanstate == ScanState_Scanning)
+		return;
+
+	/* now we can start processing bayer data so long as we have at least
+	* 2 lines worth of data. this is the simplest demosaicing method that
+	* I could think of. I use each 2x2 bayer element without interpolation
+	* to generate 4 rgb pixels.
+	*/
+	while ( frame->curline < cam->height &&
+		(RingQueue_GetLength(&uvd->dp) >= hor*2)) {
+		/* get 2 lines of bayer for demosaicing
+		 * into 2 lines of RGB */
+		RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
+		bayL0 = (struct bayL0 *) cam->scratch;
+		bayL1 = (struct bayL1 *) (cam->scratch + hor);
+		/* frame->curline is the rgb y line */
+		rgbL0 = (struct rgb *)
+				( frame->data + (cam->width*3*frame->curline));
+		/* w/2 because we're already doing 2 pixels */
+		rgbL1 = rgbL0 + (cam->width/2);
+
+		for (x=0; x < cam->width; x+=2) {
+			rgbL0->r = bayL0->r;
+			rgbL0->g = bayL0->g;
+			rgbL0->b = bayL1->b;
+
+			rgbL0->r2 = bayL0->r;
+			rgbL0->g2 = bayL1->g;
+			rgbL0->b2 = bayL1->b;
+
+			rgbL1->r = bayL0->r;
+			rgbL1->g = bayL1->g;
+			rgbL1->b = bayL1->b;
+
+			rgbL1->r2 = bayL0->r;
+			rgbL1->g2 = bayL1->g;
+			rgbL1->b2 = bayL1->b;
+
+			rgbL0++;
+			rgbL1++;
+
+			bayL0++;
+			bayL1++;
+		}
+
+		frame->seqRead_Length += cam->width*3*2;
+		frame->curline += 2;
+	}
+	/* See if we filled the frame */
+	if (frame->curline == cam->height) {
+		frame->frameState = FrameState_Done_Hold;
+		frame->curline = 0;
+		uvd->curframe = -1;
+		uvd->stats.frame_num++;
+	}
+}
+
+/* taken from konicawc */
+static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+	int ret;
+	int newsize;
+	int oldsize;
+	int x = vw->width;
+	int y = vw->height;
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+
+	if (x > 0 && y > 0) {
+		DEBUG(2, "trying to find size %d,%d", x, y);
+		for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+			if ((camera_sizes[newsize].width == x) &&
+				(camera_sizes[newsize].height == y))
+				break;
+		}
+	} else
+		newsize = cam->size;
+
+	if (newsize > MAX_FRAME_SIZE) {
+		DEBUG(1, "couldn't find size %d,%d", x, y);
+		return -EINVAL;
+	}
+
+	if (newsize == cam->size) {
+		DEBUG(1, "Nothing to do");
+		return 0;
+	}
+
+	qcm_stop_data(uvd);
+
+	if (cam->size != newsize) {
+		oldsize = cam->size;
+		cam->size = newsize;
+		ret = qcm_set_camera_size(uvd);
+		if (ret) {
+			err("Couldn't set camera size, err=%d",ret);
+			/* restore the original size */
+			cam->size = oldsize;
+			return ret;
+		}
+	}
+
+	/* Flush the input queue and clear any current frame in progress */
+
+	RingQueue_Flush(&uvd->dp);
+	if (uvd->curframe != -1) {
+		uvd->frame[uvd->curframe].curline = 0;
+		uvd->frame[uvd->curframe].seqRead_Length = 0;
+		uvd->frame[uvd->curframe].seqRead_Index = 0;
+	}
+
+	CHECK_RET(ret, qcm_start_data(uvd));
+	return 0;
+}
+
+static int qcm_configure_video(struct uvd *uvd)
+{
+	int ret;
+	memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+	memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+	uvd->vpic.colour = colour;
+	uvd->vpic.hue = hue;
+	uvd->vpic.brightness = brightness;
+	uvd->vpic.contrast = contrast;
+	uvd->vpic.whiteness = whiteness;
+	uvd->vpic.depth = 24;
+	uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+	memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+	strcpy(uvd->vcap.name, "QCM USB Camera");
+	uvd->vcap.type = VID_TYPE_CAPTURE;
+	uvd->vcap.channels = 1;
+	uvd->vcap.audios = 0;
+
+	uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+	uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+	uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+	uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+	memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+	uvd->vchan.flags = 0 ;
+	uvd->vchan.tuners = 0;
+	uvd->vchan.channel = 0;
+	uvd->vchan.type = VIDEO_TYPE_CAMERA;
+	strcpy(uvd->vchan.name, "Camera");
+
+	CHECK_RET(ret, qcm_sensor_init(uvd));
+	return 0;
+}
+
+static int qcm_probe(struct usb_interface *intf,
+			const struct usb_device_id *devid)
+{
+	int err;
+	struct uvd *uvd;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct qcm *cam;
+	size_t buffer_size;
+	unsigned char video_ep;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	int i,j;
+	unsigned int ifacenum, ifacenum_inact=0;
+	__le16 sensor_id;
+
+	/* we don't support multiconfig cams */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return -ENODEV;
+
+	/* first check for the video interface and not
+	* the audio interface */
+	interface = &intf->cur_altsetting[0];
+	if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+		|| (interface->desc.bInterfaceSubClass !=
+			USB_CLASS_VENDOR_SPEC))
+		return -ENODEV;
+
+	/*
+	walk through each endpoint in each setting in the interface
+	stop when we find the one that's an isochronous IN endpoint.
+	*/
+	for (i=0; i < intf->num_altsetting; i++) {
+		interface = &intf->cur_altsetting[i];
+		ifacenum = interface->desc.bAlternateSetting;
+		/* walk the end points */
+		for (j=0; j < interface->desc.bNumEndpoints; j++) {
+			endpoint = &interface->endpoint[j].desc;
+
+			if ((endpoint->bEndpointAddress &
+				USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+				continue; /* not input then not good */
+
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+			if (!buffer_size) {
+				ifacenum_inact = ifacenum;
+				continue; /* 0 pkt size is not what we want */
+			}
+
+			if ((endpoint->bmAttributes &
+				USB_ENDPOINT_XFERTYPE_MASK) ==
+				USB_ENDPOINT_XFER_ISOC) {
+				video_ep = endpoint->bEndpointAddress;
+				/* break out of the search */
+				goto good_videoep;
+			}
+		}
+	}
+	/* failed out since nothing useful was found */
+	err("No suitable endpoint was found\n");
+	return -ENODEV;
+
+good_videoep:
+	/* disable isochronous stream before doing anything else */
+	err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
+	if (err < 0) {
+		err("Failed to disable sensor stream");
+		return -EIO;
+	}
+
+	/*
+	Check that this is the same unknown sensor that is known to work. This
+	sensor is suspected to be the ST VV6422C001. I'll check the same value
+	that the qc-usb driver checks. This value is probably not even the
+	sensor ID since it matches the USB dev ID. Oh well. If it doesn't
+	match, it's probably a diff sensor so exit and apologize.
+	*/
+	err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
+	if (err < 0) {
+		err("Couldn't read sensor values. Err %d\n",err);
+		return err;
+	}
+	if (sensor_id != cpu_to_le16(0x08F0)) {
+		err("Sensor ID %x != %x. Unsupported. Sorry\n",
+			le16_to_cpu(sensor_id), (0x08F0));
+		return -ENODEV;
+	}
+
+	uvd = usbvideo_AllocateDevice(cams);
+	if (!uvd)
+		return -ENOMEM;
+
+	cam = (struct qcm *) uvd->user_data;
+
+	/* buf for doing demosaicing */
+	cam->scratch = kmalloc(324*2, GFP_KERNEL);
+	if (!cam->scratch) /* uvd freed in dereg */
+		return -ENOMEM;
+
+	/* yes, if we fail after here, cam->scratch gets freed
+	by qcm_free_uvd */
+
+	err = qcm_alloc_int_urb(cam);
+	if (err < 0)
+		return err;
+
+	/* yes, if we fail after here, int urb gets freed
+	by qcm_free_uvd */
+
+	RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+	cam->width = camera_sizes[size].width;
+	cam->height = camera_sizes[size].height;
+	cam->size = size;
+
+	uvd->debug = debug;
+	uvd->flags = 0;
+	uvd->dev = dev;
+	uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+	uvd->ifaceAltActive = ifacenum;
+	uvd->ifaceAltInactive = ifacenum_inact;
+	uvd->video_endp = video_ep;
+	uvd->iso_packet_len = buffer_size;
+	uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+	uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+	uvd->canvas = VIDEOSIZE(320, 240);
+	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+	err = qcm_configure_video(uvd);
+	if (err) {
+		err("failed to configure video settings");
+		return err;
+	}
+
+	err = usbvideo_RegisterVideoDevice(uvd);
+	if (err) { /* the uvd gets freed in Deregister */
+		err("usbvideo_RegisterVideoDevice() failed.");
+		return err;
+	}
+
+	uvd->max_frame_size = (320 * 240 * 3);
+	qcm_register_input(cam, dev);
+	usb_set_intfdata(intf, uvd);
+	return 0;
+}
+
+static void qcm_free_uvd(struct uvd *uvd)
+{
+	struct qcm *cam = (struct qcm *) uvd->user_data;
+
+	kfree(cam->scratch);
+	qcm_unregister_input(cam);
+	qcm_free_int(cam);
+}
+
+static struct usbvideo_cb qcm_driver = {
+	.probe = 		qcm_probe,
+	.setupOnOpen = 		qcm_setup_on_open,
+	.processData = 		qcm_process_isoc,
+	.setVideoMode = 	qcm_set_video_mode,
+	.startDataPump = 	qcm_start_data,
+	.stopDataPump = 	qcm_stop_data,
+	.adjustPicture = 	qcm_adjust_picture,
+	.userFree = 		qcm_free_uvd
+};
+
+static int __init qcm_init(void)
+{
+	info(DRIVER_DESC " " DRIVER_VERSION);
+
+	return usbvideo_register(
+		&cams,
+		MAX_CAMERAS,
+		sizeof(struct qcm),
+		"QCM",
+		&qcm_driver,
+		THIS_MODULE,
+		qcm_table);
+}
+
+static void __exit qcm_exit(void)
+{
+	usbvideo_Deregister(&cams);
+}
+
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
+module_param(colour, int, 0);
+MODULE_PARM_DESC(colour, "Initial colour");
+module_param(hue, int, 0);
+MODULE_PARM_DESC(hue, "Initial hue");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast");
+module_param(whiteness, int, 0);
+MODULE_PARM_DESC(whiteness, "Initial whiteness");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(qcm_init);
+module_exit(qcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_DESCRIPTION("QCM USB Camera");
+MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
new file mode 100644
index 0000000..baab9c0
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.h
@@ -0,0 +1,126 @@
+#ifndef quickcam_messenger_h
+#define quickcam_messenger_h
+
+#ifndef CONFIG_INPUT
+/* if we're not using input we dummy out these functions */
+#define qcm_register_input(...)
+#define qcm_unregister_input(...)
+#define qcm_report_buttonstat(...)
+#define qcm_setup_input_int(...) 0
+#define qcm_stop_int_data(...)
+#define qcm_alloc_int_urb(...) 0
+#define qcm_free_int(...)
+#endif
+
+
+#define CHECK_RET(ret, expr) \
+	if ((ret = expr) < 0) return ret
+
+/* Control Registers for the STVV6422 ASIC
+ * - this define is taken from the qc-usb-messenger code
+ */
+#define STV_ISO_ENABLE		0x1440
+#define ISOC_PACKET_SIZE	1023
+
+/* Chip identification number including revision indicator */
+#define CMOS_SENSOR_IDREV	0xE00A
+
+struct rgb {
+	u8 b;
+	u8 g;
+	u8 r;
+	u8 b2;
+	u8 g2;
+	u8 r2;
+};
+
+struct bayL0 {
+#ifdef __BIG_ENDIAN
+	u8 r;
+	u8 g;
+#elif __LITTLE_ENDIAN
+	u8 g;
+	u8 r;
+#else
+#error not byte order defined
+#endif
+};
+
+struct bayL1 {
+#ifdef __BIG_ENDIAN
+	u8 g;
+	u8 b;
+#elif __LITTLE_ENDIAN
+	u8 b;
+	u8 g;
+#else
+#error not byte order defined
+#endif
+};
+
+struct cam_size {
+	u16	width;
+	u16	height;
+	u8	cmd;
+};
+
+static const struct cam_size camera_sizes[] = {
+	{ 160, 120, 0xf },
+	{ 320, 240, 0x2 },
+};
+
+enum frame_sizes {
+	SIZE_160X120	= 0,
+	SIZE_320X240	= 1,
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+struct qcm {
+	u16 colour;
+	u16 hue;
+	u16 brightness;
+	u16 contrast;
+	u16 whiteness;
+
+	u8 size;
+	int height;
+	int width;
+	u8 *scratch;
+	struct urb *button_urb;
+	u8 button_sts;
+	u8 button_sts_buf;
+
+#ifdef CONFIG_INPUT
+	struct input_dev *input;
+	char input_physname[64];
+#endif
+};
+
+struct regval {
+	u16 reg;
+	u8 val;
+};
+/* this table is derived from the
+qc-usb-messenger code */
+static const struct regval regval_table[] = {
+	{ STV_ISO_ENABLE, 0x00 },
+	{ 0x1436, 0x00 }, { 0x1432, 0x03 },
+	{ 0x143a, 0xF9 }, { 0x0509, 0x38 },
+	{ 0x050a, 0x38 }, { 0x050b, 0x38 },
+	{ 0x050c, 0x2A }, { 0x050d, 0x01 },
+	{ 0x1431, 0x00 }, { 0x1433, 0x34 },
+	{ 0x1438, 0x18 }, { 0x1439, 0x00 },
+	{ 0x143b, 0x05 }, { 0x143c, 0x00 },
+	{ 0x143e, 0x01 }, { 0x143d, 0x00 },
+	{ 0x1442, 0xe2 }, { 0x1500, 0xd0 },
+	{ 0x1500, 0xd0 }, { 0x1500, 0x50 },
+	{ 0x1501, 0xaf }, { 0x1502, 0xc2 },
+	{ 0x1503, 0x45 }, { 0x1505, 0x02 },
+	{ 0x150e, 0x8e }, { 0x150f, 0x37 },
+	{ 0x15c0, 0x00 },
+};
+
+static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
+
+#endif /* quickcam_messenger_h */
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h
index 3cbf4fc..49dbee5 100644
--- a/drivers/media/video/usbvideo/usbvideo.h
+++ b/drivers/media/video/usbvideo/usbvideo.h
@@ -18,6 +18,7 @@
 
 #include <linux/config.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 474a29b..19d3c20 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -32,6 +32,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index d330fa9..f4b3d64 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -59,6 +59,7 @@
 #include <asm/io.h>
 #include <asm/div64.h>
 #include <linux/video_decoder.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <media/v4l2-common.h>
 
 #ifdef CONFIG_KMOD
@@ -293,7 +294,10 @@
 #if 1
 	[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
 #endif
-	[_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS"
+	[_IOC_NR(VIDIOC_LOG_STATUS)]       = "VIDIOC_LOG_STATUS",
+	[_IOC_NR(VIDIOC_G_EXT_CTRLS)]      = "VIDIOC_G_EXT_CTRLS",
+	[_IOC_NR(VIDIOC_S_EXT_CTRLS)]      = "VIDIOC_S_EXT_CTRLS",
+	[_IOC_NR(VIDIOC_TRY_EXT_CTRLS)]    = "VIDIOC_TRY_EXT_CTRLS"
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
@@ -331,7 +335,8 @@
 	[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)]  = "VIDIOC_INT_S_AUDIO_ROUTING",
 	[_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)]  = "VIDIOC_INT_G_AUDIO_ROUTING",
 	[_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)]  = "VIDIOC_INT_S_VIDEO_ROUTING",
-	[_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)]  = "VIDIOC_INT_G_VIDEO_ROUTING"
+	[_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)]  = "VIDIOC_INT_G_VIDEO_ROUTING",
+	[_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)]   = "VIDIOC_INT_S_CRYSTAL_FREQ"
 };
 #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
 
@@ -423,7 +428,9 @@
 	case TUNER_SET_TYPE_ADDR:
 	case TUNER_SET_STANDBY:
 	case TDA9887_SET_CONFIG:
+#ifdef __OLD_VIDIOC_
 	case VIDIOC_OVERLAY_OLD:
+#endif
 	case VIDIOC_STREAMOFF:
 	case VIDIOC_G_OUTPUT:
 	case VIDIOC_S_OUTPUT:
@@ -439,7 +446,9 @@
 	case VIDIOC_G_AUDIO:
 	case VIDIOC_S_AUDIO:
 	case VIDIOC_ENUMAUDIO:
+#ifdef __OLD_VIDIOC_
 	case VIDIOC_G_AUDIO_OLD:
+#endif
 	{
 		struct v4l2_audio *p=arg;
 
@@ -450,7 +459,9 @@
 	case VIDIOC_G_AUDOUT:
 	case VIDIOC_S_AUDOUT:
 	case VIDIOC_ENUMAUDOUT:
+#ifdef __OLD_VIDIOC_
 	case VIDIOC_G_AUDOUT_OLD:
+#endif
 	{
 		struct v4l2_audioout *p=arg;
 		printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
@@ -478,9 +489,9 @@
 				prt_names(p->memory,v4l2_memory_names),
 				p->m.userptr);
 		printk ("%s: timecode= %02d:%02d:%02d type=%d, "
-			"flags=0x%08x, frames=%d, userbits=0x%p\n",
+			"flags=0x%08x, frames=%d, userbits=0x%08x\n",
 				s,tc->hours,tc->minutes,tc->seconds,
-				tc->type, tc->flags, tc->frames, tc->userbits);
+				tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
 		break;
 	}
 	case VIDIOC_QUERYCAP:
@@ -495,12 +506,31 @@
 	}
 	case VIDIOC_G_CTRL:
 	case VIDIOC_S_CTRL:
+#ifdef __OLD_VIDIOC_
 	case VIDIOC_S_CTRL_OLD:
+#endif
 	{
 		struct v4l2_control *p=arg;
 		printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
 		break;
 	}
+	case VIDIOC_G_EXT_CTRLS:
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *p = arg;
+		int i;
+
+		printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
+		for (i = 0; i < p->count; i++) {
+			struct v4l2_ext_control *c = &p->controls[i];
+			if (cmd == VIDIOC_G_EXT_CTRLS)
+				printk("%s: id=%d\n", s, c->id);
+			else
+				printk("%s: id=%d, value=%d\n", s, c->id, c->value);
+		}
+		break;
+	}
 	case VIDIOC_G_CROP:
 	case VIDIOC_S_CROP:
 	{
@@ -510,7 +540,9 @@
 		break;
 	}
 	case VIDIOC_CROPCAP:
+#ifdef __OLD_VIDIOC_
 	case VIDIOC_CROPCAP_OLD:
+#endif
 	{
 		struct v4l2_cropcap *p=arg;
 		/*FIXME: Should also show rect structs */
@@ -667,6 +699,12 @@
 		printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
 		break;
 	}
+	case VIDIOC_INT_S_CRYSTAL_FREQ:
+	{
+		struct v4l2_crystal_freq *p=arg;
+		printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
+		break;
+	}
 	case VIDIOC_G_SLICED_VBI_CAP:
 	{
 		struct v4l2_sliced_vbi_cap *p=arg;
@@ -696,7 +734,9 @@
 	}
 	case VIDIOC_G_PARM:
 	case VIDIOC_S_PARM:
+#ifdef __OLD_VIDIOC_
 	case VIDIOC_S_PARM_OLD:
+#endif
 	{
 		struct v4l2_streamparm *p=arg;
 		printk ("%s: type=%d\n", s, p->type);
@@ -915,6 +955,498 @@
 
 /* ----------------------------------------------------------------- */
 
+/* Helper functions for control handling			     */
+
+/* Check for correctness of the ctrl's value based on the data from
+   struct v4l2_queryctrl and the available menu items. Note that
+   menu_items may be NULL, in that case it is ignored. */
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+		const char **menu_items)
+{
+	if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+		return -EINVAL;
+	if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+		return -EBUSY;
+	if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+	    qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+	    qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+		return 0;
+	if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+		return -ERANGE;
+	if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+		if (menu_items[ctrl->value] == NULL ||
+		    menu_items[ctrl->value][0] == '\0')
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* Returns NULL or a character pointer array containing the menu for
+   the given control ID. The pointer array ends with a NULL pointer.
+   An empty string signifies a menu entry that is invalid. This allows
+   drivers to disable certain options if it is not supported. */
+const char **v4l2_ctrl_get_menu(u32 id)
+{
+	static const char *mpeg_audio_sampling_freq[] = {
+		"44.1 kHz",
+		"48 kHz",
+		"32 kHz",
+		NULL
+	};
+	static const char *mpeg_audio_encoding[] = {
+		"Layer I",
+		"Layer II",
+		"Layer III",
+		NULL
+	};
+	static const char *mpeg_audio_l1_bitrate[] = {
+		"32 kbps",
+		"64 kbps",
+		"96 kbps",
+		"128 kbps",
+		"160 kbps",
+		"192 kbps",
+		"224 kbps",
+		"256 kbps",
+		"288 kbps",
+		"320 kbps",
+		"352 kbps",
+		"384 kbps",
+		"416 kbps",
+		"448 kbps",
+		NULL
+	};
+	static const char *mpeg_audio_l2_bitrate[] = {
+		"32 kbps",
+		"48 kbps",
+		"56 kbps",
+		"64 kbps",
+		"80 kbps",
+		"96 kbps",
+		"112 kbps",
+		"128 kbps",
+		"160 kbps",
+		"192 kbps",
+		"224 kbps",
+		"256 kbps",
+		"320 kbps",
+		"384 kbps",
+		NULL
+	};
+	static const char *mpeg_audio_l3_bitrate[] = {
+		"32 kbps",
+		"40 kbps",
+		"48 kbps",
+		"56 kbps",
+		"64 kbps",
+		"80 kbps",
+		"96 kbps",
+		"112 kbps",
+		"128 kbps",
+		"160 kbps",
+		"192 kbps",
+		"224 kbps",
+		"256 kbps",
+		"320 kbps",
+		NULL
+	};
+	static const char *mpeg_audio_mode[] = {
+		"Stereo",
+		"Joint Stereo",
+		"Dual",
+		"Mono",
+		NULL
+	};
+	static const char *mpeg_audio_mode_extension[] = {
+		"Bound 4",
+		"Bound 8",
+		"Bound 12",
+		"Bound 16",
+		NULL
+	};
+	static const char *mpeg_audio_emphasis[] = {
+		"No Emphasis",
+		"50/15 us",
+		"CCITT J17",
+		NULL
+	};
+	static const char *mpeg_audio_crc[] = {
+		"No CRC",
+		"16-bit CRC",
+		NULL
+	};
+	static const char *mpeg_video_encoding[] = {
+		"MPEG-1",
+		"MPEG-2",
+		NULL
+	};
+	static const char *mpeg_video_aspect[] = {
+		"1x1",
+		"4x3",
+		"16x9",
+		"2.21x1",
+		NULL
+	};
+	static const char *mpeg_video_bitrate_mode[] = {
+		"Variable Bitrate",
+		"Constant Bitrate",
+		NULL
+	};
+	static const char *mpeg_stream_type[] = {
+		"MPEG-2 Program Stream",
+		"MPEG-2 Transport Stream",
+		"MPEG-1 System Stream",
+		"MPEG-2 DVD-compatible Stream",
+		"MPEG-1 VCD-compatible Stream",
+		"MPEG-2 SVCD-compatible Stream",
+		NULL
+	};
+	static const char *mpeg_stream_vbi_fmt[] = {
+		"No VBI",
+		"VBI in private packets, IVTV format",
+		NULL
+	};
+
+	switch (id) {
+		case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+			return mpeg_audio_sampling_freq;
+		case V4L2_CID_MPEG_AUDIO_ENCODING:
+			return mpeg_audio_encoding;
+		case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+			return mpeg_audio_l1_bitrate;
+		case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+			return mpeg_audio_l2_bitrate;
+		case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+			return mpeg_audio_l3_bitrate;
+		case V4L2_CID_MPEG_AUDIO_MODE:
+			return mpeg_audio_mode;
+		case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+			return mpeg_audio_mode_extension;
+		case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+			return mpeg_audio_emphasis;
+		case V4L2_CID_MPEG_AUDIO_CRC:
+			return mpeg_audio_crc;
+		case V4L2_CID_MPEG_VIDEO_ENCODING:
+			return mpeg_video_encoding;
+		case V4L2_CID_MPEG_VIDEO_ASPECT:
+			return mpeg_video_aspect;
+		case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+			return mpeg_video_bitrate_mode;
+		case V4L2_CID_MPEG_STREAM_TYPE:
+			return mpeg_stream_type;
+		case V4L2_CID_MPEG_STREAM_VBI_FMT:
+			return mpeg_stream_vbi_fmt;
+		default:
+			return NULL;
+	}
+}
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+	const char *name;
+
+	qctrl->flags = 0;
+	switch (qctrl->id) {
+	/* USER controls */
+	case V4L2_CID_USER_CLASS: 	name = "User Controls"; break;
+	case V4L2_CID_AUDIO_VOLUME: 	name = "Volume"; break;
+	case V4L2_CID_AUDIO_MUTE: 	name = "Mute"; break;
+	case V4L2_CID_AUDIO_BALANCE: 	name = "Balance"; break;
+	case V4L2_CID_AUDIO_BASS: 	name = "Bass"; break;
+	case V4L2_CID_AUDIO_TREBLE: 	name = "Treble"; break;
+	case V4L2_CID_AUDIO_LOUDNESS: 	name = "Loudness"; break;
+	case V4L2_CID_BRIGHTNESS: 	name = "Brightness"; break;
+	case V4L2_CID_CONTRAST: 	name = "Contrast"; break;
+	case V4L2_CID_SATURATION: 	name = "Saturation"; break;
+	case V4L2_CID_HUE: 		name = "Hue"; break;
+
+	/* MPEG controls */
+	case V4L2_CID_MPEG_CLASS: 		name = "MPEG Encoder Controls"; break;
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
+	case V4L2_CID_MPEG_AUDIO_ENCODING: 	name = "Audio Encoding Layer"; break;
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE: 	name = "Audio Layer I Bitrate"; break;
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE: 	name = "Audio Layer II Bitrate"; break;
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE: 	name = "Audio Layer III Bitrate"; break;
+	case V4L2_CID_MPEG_AUDIO_MODE: 		name = "Audio Stereo Mode"; break;
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS: 	name = "Audio Emphasis"; break;
+	case V4L2_CID_MPEG_AUDIO_CRC: 		name = "Audio CRC"; break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING: 	name = "Video Encoding"; break;
+	case V4L2_CID_MPEG_VIDEO_ASPECT: 	name = "Video Aspect"; break;
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES: 	name = "Video B Frames"; break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 	name = "Video GOP Size"; break;
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: 	name = "Video GOP Closure"; break;
+	case V4L2_CID_MPEG_VIDEO_PULLDOWN: 	name = "Video Pulldown"; break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: 	name = "Video Bitrate Mode"; break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE: 	name = "Video Bitrate"; break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: 	name = "Video Peak Bitrate"; break;
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
+	case V4L2_CID_MPEG_STREAM_TYPE: 	name = "Stream Type"; break;
+	case V4L2_CID_MPEG_STREAM_PID_PMT: 	name = "Stream PMT Program ID"; break;
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO: 	name = "Stream Audio Program ID"; break;
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO: 	name = "Stream Video Program ID"; break;
+	case V4L2_CID_MPEG_STREAM_PID_PCR: 	name = "Stream PCR Program ID"; break;
+	case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
+	case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:	name = "Stream VBI Format"; break;
+
+	default:
+		return -EINVAL;
+	}
+	switch (qctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_LOUDNESS:
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+	case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+		qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+		min = 0;
+		max = step = 1;
+		break;
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+	case V4L2_CID_MPEG_AUDIO_MODE:
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+	case V4L2_CID_MPEG_AUDIO_CRC:
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+	case V4L2_CID_MPEG_STREAM_TYPE:
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		qctrl->type = V4L2_CTRL_TYPE_MENU;
+		step = 1;
+		break;
+	case V4L2_CID_USER_CLASS:
+	case V4L2_CID_MPEG_CLASS:
+		qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+		qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+		min = max = step = def = 0;
+		break;
+	default:
+		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+		break;
+	}
+	switch (qctrl->id) {
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+	case V4L2_CID_MPEG_AUDIO_MODE:
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_BRIGHTNESS:
+	case V4L2_CID_CONTRAST:
+	case V4L2_CID_SATURATION:
+	case V4L2_CID_HUE:
+		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+		break;
+	}
+	qctrl->minimum = min;
+	qctrl->maximum = max;
+	qctrl->step = step;
+	qctrl->default_value = def;
+	qctrl->reserved[0] = qctrl->reserved[1] = 0;
+	snprintf(qctrl->name, sizeof(qctrl->name), name);
+	return 0;
+}
+
+/* Fill in a struct v4l2_queryctrl with standard values based on
+   the control ID. */
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
+{
+	switch (qctrl->id) {
+	/* USER controls */
+	case V4L2_CID_USER_CLASS:
+	case V4L2_CID_MPEG_CLASS:
+		return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+	case V4L2_CID_AUDIO_VOLUME:
+		return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_LOUDNESS:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+	case V4L2_CID_CONTRAST:
+	case V4L2_CID_SATURATION:
+		return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
+
+	/* MPEG controls */
+	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+				V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+	case V4L2_CID_MPEG_AUDIO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+				V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L1_BITRATE_32K,
+				V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
+				V4L2_MPEG_AUDIO_L1_BITRATE_256K);
+	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L2_BITRATE_32K,
+				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+				V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_L3_BITRATE_32K,
+				V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
+				V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+	case V4L2_CID_MPEG_AUDIO_MODE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_MODE_STEREO,
+				V4L2_MPEG_AUDIO_MODE_MONO, 1,
+				V4L2_MPEG_AUDIO_MODE_STEREO);
+	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+				V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+				V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+				V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+				V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+	case V4L2_CID_MPEG_AUDIO_CRC:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_AUDIO_CRC_NONE,
+				V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+				V4L2_MPEG_AUDIO_CRC_NONE);
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+				V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+	case V4L2_CID_MPEG_VIDEO_ASPECT:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_ASPECT_1x1,
+				V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+				V4L2_MPEG_VIDEO_ASPECT_4x3);
+	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+		return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
+	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+	case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+				V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+		return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+	case V4L2_CID_MPEG_STREAM_TYPE:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+				V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+	case V4L2_CID_MPEG_STREAM_PID_PMT:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+	case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+	case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+	case V4L2_CID_MPEG_STREAM_PID_PCR:
+		return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+	case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
+		return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+	case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
+		return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+	case V4L2_CID_MPEG_STREAM_VBI_FMT:
+		return v4l2_ctrl_query_fill(qctrl,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE,
+				V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+				V4L2_MPEG_STREAM_VBI_FMT_NONE);
+	default:
+		return -EINVAL;
+	}
+}
+
+/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+   the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
+	       const char **menu_items)
+{
+	int i;
+
+	if (menu_items == NULL ||
+	    (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
+		return -EINVAL;
+	for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+	if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+		return -EINVAL;
+	snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
+	qmenu->reserved = 0;
+	return 0;
+}
+
+/* ctrl_classes points to an array of u32 pointers, the last element is
+   a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+   Each array must be sorted low to high and belong to the same control
+   class. The array of u32 pointer must also be sorted, from low class IDs
+   to high class IDs.
+
+   This function returns the first ID that follows after the given ID.
+   When no more controls are available 0 is returned. */
+u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
+{
+	u32 ctrl_class;
+	const u32 *pctrl;
+
+	/* if no query is desired, then just return the control ID */
+	if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
+		return id;
+	if (ctrl_classes == NULL)
+		return 0;
+	id &= V4L2_CTRL_ID_MASK;
+	ctrl_class = V4L2_CTRL_ID2CLASS(id);
+	id++;	/* select next control */
+	/* find first class that matches (or is greater than) the class of
+	   the ID */
+	while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
+		ctrl_classes++;
+	/* no more classes */
+	if (*ctrl_classes == NULL)
+		return 0;
+	pctrl = *ctrl_classes;
+	/* find first ctrl within the class that is >= ID */
+	while (*pctrl && *pctrl < id) pctrl++;
+	if (*pctrl)
+		return *pctrl;
+	/* we are at the end of the controls of the current class. */
+	/* continue with next class if available */
+	ctrl_classes++;
+	if (*ctrl_classes == NULL)
+		return 0;
+	return **ctrl_classes;
+}
+
+/* ----------------------------------------------------------------- */
+
 EXPORT_SYMBOL(v4l2_video_std_construct);
 
 EXPORT_SYMBOL(v4l2_prio_init);
@@ -929,6 +1461,13 @@
 EXPORT_SYMBOL(v4l_printk_ioctl);
 EXPORT_SYMBOL(v4l_printk_ioctl_arg);
 
+EXPORT_SYMBOL(v4l2_ctrl_next);
+EXPORT_SYMBOL(v4l2_ctrl_check);
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index caf3e7e..7ee8a53 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -135,14 +135,15 @@
 
 int videobuf_dvb_register(struct videobuf_dvb *dvb,
 			  struct module *module,
-			  void *adapter_priv)
+			  void *adapter_priv,
+			  struct device *device)
 {
 	int result;
 
 	mutex_init(&dvb->lock);
 
 	/* register adapter */
-	result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
+	result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
 	if (result < 0) {
 		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
 		       dvb->name, result);
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 5f87dd5..2dfa7f2 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -1,20 +1,31 @@
 /*
- * Video capture interface for Linux
+ * Video capture interface for Linux version 2
  *
- *		A generic video device interface for the LINUX operating system
- *		using a set of device structures/vectors for low level operations.
+ *	A generic video device interface for the LINUX operating system
+ *	using a set of device structures/vectors for low level operations.
  *
- *		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 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.
  *
- * Author:	Alan Cox, <alan@redhat.com>
+ * Authors:	Alan Cox, <alan@redhat.com> (version 1)
+ *              Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
  *
  * Fixes:	20000516  Claudio Matsuoka <claudio@conectiva.com>
  *		- Added procfs support
  */
 
+#define dbgarg(cmd, fmt, arg...) \
+		if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)			\
+			printk (KERN_DEBUG "%s: ",  vfd->name);		\
+			v4l_printk_ioctl(cmd);				\
+			printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
+#define dbgarg2(fmt, arg...) \
+		if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)			\
+			printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -30,7 +41,13 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
+#include <linux/videodev2.h>
+
+#ifdef CONFIG_VIDEO_V4L1
 #include <linux/videodev.h>
+#endif
+#include <media/v4l2-common.h>
 
 #define VIDEO_NUM_DEVICES	256
 #define VIDEO_NAME              "video4linux"
@@ -41,7 +58,8 @@
 
 static ssize_t show_name(struct class_device *cd, char *buf)
 {
-	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+	struct video_device *vfd = container_of(cd, struct video_device,
+								class_dev);
 	return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
 }
 
@@ -62,7 +80,8 @@
 
 static void video_release(struct class_device *cd)
 {
-	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+	struct video_device *vfd = container_of(cd, struct video_device,
+								class_dev);
 
 #if 1
 	/* needed until all drivers are fixed */
@@ -90,7 +109,7 @@
 }
 
 /*
- *	Open a video device.
+ *	Open a video device - FIXME: Obsoleted
  */
 static int video_open(struct inode *inode, struct file *file)
 {
@@ -130,6 +149,7 @@
  * helper function -- handles userspace copying for ioctl arguments
  */
 
+#ifdef __OLD_VIDIOC_
 static unsigned int
 video_fix_command(unsigned int cmd)
 {
@@ -155,7 +175,11 @@
 	}
 	return cmd;
 }
+#endif
 
+/*
+ * Obsolete usercopy function - Should be removed soon
+ */
 int
 video_usercopy(struct inode *inode, struct file *file,
 	       unsigned int cmd, unsigned long arg,
@@ -166,8 +190,1218 @@
 	void    *mbuf = NULL;
 	void	*parg = NULL;
 	int	err  = -EINVAL;
+	int     is_ext_ctrl;
+	size_t  ctrls_size = 0;
+	void __user *user_ptr = NULL;
 
+#ifdef __OLD_VIDIOC_
 	cmd = video_fix_command(cmd);
+#endif
+	is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+		       cmd == VIDIOC_TRY_EXT_CTRLS);
+
+	/*  Copy arguments into temp kernel buffer  */
+	switch (_IOC_DIR(cmd)) {
+	case _IOC_NONE:
+		parg = NULL;
+		break;
+	case _IOC_READ:
+	case _IOC_WRITE:
+	case (_IOC_WRITE | _IOC_READ):
+		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+			parg = sbuf;
+		} else {
+			/* too big to allocate from stack */
+			mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+			if (NULL == mbuf)
+				return -ENOMEM;
+			parg = mbuf;
+		}
+
+		err = -EFAULT;
+		if (_IOC_DIR(cmd) & _IOC_WRITE)
+			if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+				goto out;
+		break;
+	}
+	if (is_ext_ctrl) {
+		struct v4l2_ext_controls *p = parg;
+
+		/* In case of an error, tell the caller that it wasn't
+		   a specific control that caused it. */
+		p->error_idx = p->count;
+		user_ptr = (void __user *)p->controls;
+		if (p->count) {
+			ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+			/* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+			mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+			err = -ENOMEM;
+			if (NULL == mbuf)
+				goto out_ext_ctrl;
+			err = -EFAULT;
+			if (copy_from_user(mbuf, user_ptr, ctrls_size))
+				goto out_ext_ctrl;
+			p->controls = mbuf;
+		}
+	}
+
+	/* call driver */
+	err = func(inode, file, cmd, parg);
+	if (err == -ENOIOCTLCMD)
+		err = -EINVAL;
+	if (is_ext_ctrl) {
+		struct v4l2_ext_controls *p = parg;
+
+		p->controls = (void *)user_ptr;
+		if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+			err = -EFAULT;
+		goto out_ext_ctrl;
+	}
+	if (err < 0)
+		goto out;
+
+out_ext_ctrl:
+	/*  Copy results into user buffer  */
+	switch (_IOC_DIR(cmd))
+	{
+	case _IOC_READ:
+	case (_IOC_WRITE | _IOC_READ):
+		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+			err = -EFAULT;
+		break;
+	}
+
+out:
+	kfree(mbuf);
+	return err;
+}
+
+/*
+ * open/release helper functions -- handle exclusive opens
+ * Should be removed soon
+ */
+int video_exclusive_open(struct inode *inode, struct file *file)
+{
+	struct  video_device *vfl = video_devdata(file);
+	int retval = 0;
+
+	mutex_lock(&vfl->lock);
+	if (vfl->users) {
+		retval = -EBUSY;
+	} else {
+		vfl->users++;
+	}
+	mutex_unlock(&vfl->lock);
+	return retval;
+}
+
+int video_exclusive_release(struct inode *inode, struct file *file)
+{
+	struct  video_device *vfl = video_devdata(file);
+
+	vfl->users--;
+	return 0;
+}
+
+static char *v4l2_memory_names[] = {
+	[V4L2_MEMORY_MMAP]    = "mmap",
+	[V4L2_MEMORY_USERPTR] = "userptr",
+	[V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+
+/* FIXME: Those stuff are replicated also on v4l2-common.c */
+static char *v4l2_type_names_FIXME[] = {
+	[V4L2_BUF_TYPE_VIDEO_CAPTURE]      = "video-cap",
+	[V4L2_BUF_TYPE_VIDEO_OVERLAY]      = "video-over",
+	[V4L2_BUF_TYPE_VIDEO_OUTPUT]       = "video-out",
+	[V4L2_BUF_TYPE_VBI_CAPTURE]        = "vbi-cap",
+	[V4L2_BUF_TYPE_VBI_OUTPUT]         = "vbi-out",
+	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
+	[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
+	[V4L2_BUF_TYPE_PRIVATE]            = "private",
+};
+
+static char *v4l2_field_names_FIXME[] = {
+	[V4L2_FIELD_ANY]        = "any",
+	[V4L2_FIELD_NONE]       = "none",
+	[V4L2_FIELD_TOP]        = "top",
+	[V4L2_FIELD_BOTTOM]     = "bottom",
+	[V4L2_FIELD_INTERLACED] = "interlaced",
+	[V4L2_FIELD_SEQ_TB]     = "seq-tb",
+	[V4L2_FIELD_SEQ_BT]     = "seq-bt",
+	[V4L2_FIELD_ALTERNATE]  = "alternate",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
+static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+					struct v4l2_buffer *p)
+{
+	struct v4l2_timecode *tc=&p->timecode;
+
+	dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+		"bytesused=%d, flags=0x%08d, "
+		"field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+			(p->timestamp.tv_sec/3600),
+			(int)(p->timestamp.tv_sec/60)%60,
+			(int)(p->timestamp.tv_sec%60),
+			p->timestamp.tv_usec,
+			p->index,
+			prt_names(p->type,v4l2_type_names_FIXME),
+			p->bytesused,p->flags,
+			p->field,p->sequence,
+			prt_names(p->memory,v4l2_memory_names),
+			p->m.userptr);
+	dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+		"flags=0x%08d, frames=%d, userbits=0x%08x\n",
+			tc->hours,tc->minutes,tc->seconds,
+			tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
+}
+
+static inline void dbgrect(struct video_device *vfd, char *s,
+							struct v4l2_rect *r)
+{
+	dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+						r->width, r->height);
+};
+
+static inline void v4l_print_pix_fmt (struct video_device *vfd,
+						struct v4l2_pix_format *fmt)
+{
+	dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+		"bytesperline=%d sizeimage=%d, colorspace=%d\n",
+		fmt->width,fmt->height,fmt->pixelformat,
+		prt_names(fmt->field,v4l2_field_names_FIXME),
+		fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
+
+static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (vfd->vidioc_try_fmt_cap)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		if (vfd->vidioc_try_fmt_overlay)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (vfd->vidioc_try_fmt_vbi)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+		if (vfd->vidioc_try_fmt_vbi_output)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+		if (vfd->vidioc_try_fmt_vbi_capture)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		if (vfd->vidioc_try_fmt_video_output)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+		if (vfd->vidioc_try_fmt_vbi_output)
+			return (0);
+		break;
+	case V4L2_BUF_TYPE_PRIVATE:
+		if (vfd->vidioc_try_fmt_type_private)
+			return (0);
+		break;
+	}
+	return (-EINVAL);
+}
+
+static int __video_do_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, void *arg)
+{
+	struct video_device *vfd = video_devdata(file);
+	void                 *fh = file->private_data;
+	int                  ret = -EINVAL;
+
+	if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
+				!(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) {
+		v4l_print_ioctl(vfd->name, cmd);
+	}
+
+	switch(cmd) {
+	/* --- capabilities ------------------------------------------ */
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+		memset(cap, 0, sizeof(*cap));
+
+		if (!vfd->vidioc_querycap)
+			break;
+
+		ret=vfd->vidioc_querycap(file, fh, cap);
+		if (!ret)
+			dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
+					"version=0x%08x, "
+					"capabilities=0x%08x\n",
+					cap->driver,cap->card,cap->bus_info,
+					cap->version,
+					cap->capabilities);
+		break;
+	}
+
+	/* --- priority ------------------------------------------ */
+	case VIDIOC_G_PRIORITY:
+	{
+		enum v4l2_priority *p=arg;
+
+		if (!vfd->vidioc_g_priority)
+			break;
+		ret=vfd->vidioc_g_priority(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "priority is %d\n", *p);
+		break;
+	}
+	case VIDIOC_S_PRIORITY:
+	{
+		enum v4l2_priority *p=arg;
+
+		if (!vfd->vidioc_s_priority)
+			break;
+		dbgarg(cmd, "setting priority to %d\n", *p);
+		ret=vfd->vidioc_s_priority(file, fh, *p);
+		break;
+	}
+
+	/* --- capture ioctls ---------------------------------------- */
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *f = arg;
+		enum v4l2_buf_type type;
+		unsigned int index;
+
+		index = f->index;
+		type  = f->type;
+		memset(f,0,sizeof(*f));
+		f->index = index;
+		f->type  = type;
+
+		switch (type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			if (vfd->vidioc_enum_fmt_cap)
+				ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			if (vfd->vidioc_enum_fmt_overlay)
+				ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_enum_fmt_vbi)
+				ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_enum_fmt_vbi_output)
+				ret=vfd->vidioc_enum_fmt_vbi_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_enum_fmt_vbi_capture)
+				ret=vfd->vidioc_enum_fmt_vbi_capture(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			if (vfd->vidioc_enum_fmt_video_output)
+				ret=vfd->vidioc_enum_fmt_video_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_OUTPUT:
+			if (vfd->vidioc_enum_fmt_vbi_output)
+				ret=vfd->vidioc_enum_fmt_vbi_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_PRIVATE:
+			if (vfd->vidioc_enum_fmt_type_private)
+				ret=vfd->vidioc_enum_fmt_type_private(file,
+								fh, f);
+			break;
+		}
+		if (!ret)
+			dbgarg (cmd, "index=%d, type=%d, flags=%d, "
+					"description=%s,"
+					" pixelformat=0x%8x\n",
+					f->index, f->type, f->flags,
+					f->description,
+					f->pixelformat);
+
+		break;
+	}
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)arg;
+		enum v4l2_buf_type type=f->type;
+
+		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+		f->type=type;
+
+		/* FIXME: Should be one dump per type */
+		dbgarg (cmd, "type=%s\n", prt_names(type,
+					v4l2_type_names_FIXME));
+
+		switch (type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			if (vfd->vidioc_g_fmt_cap)
+				ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+			if (!ret)
+				v4l_print_pix_fmt(vfd,&f->fmt.pix);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			if (vfd->vidioc_g_fmt_overlay)
+				ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_g_fmt_vbi)
+				ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_g_fmt_vbi_output)
+				ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_g_fmt_vbi_capture)
+				ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			if (vfd->vidioc_g_fmt_video_output)
+				ret=vfd->vidioc_g_fmt_video_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_OUTPUT:
+			if (vfd->vidioc_g_fmt_vbi_output)
+				ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_PRIVATE:
+			if (vfd->vidioc_g_fmt_type_private)
+				ret=vfd->vidioc_g_fmt_type_private(file,
+								fh, f);
+			break;
+		}
+
+		break;
+	}
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)arg;
+
+		/* FIXME: Should be one dump per type */
+		dbgarg (cmd, "type=%s\n", prt_names(f->type,
+					v4l2_type_names_FIXME));
+
+		switch (f->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			v4l_print_pix_fmt(vfd,&f->fmt.pix);
+			if (vfd->vidioc_s_fmt_cap)
+				ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			if (vfd->vidioc_s_fmt_overlay)
+				ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_s_fmt_vbi)
+				ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_s_fmt_vbi_output)
+				ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_s_fmt_vbi_capture)
+				ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			if (vfd->vidioc_s_fmt_video_output)
+				ret=vfd->vidioc_s_fmt_video_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_OUTPUT:
+			if (vfd->vidioc_s_fmt_vbi_output)
+				ret=vfd->vidioc_s_fmt_vbi_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_PRIVATE:
+			if (vfd->vidioc_s_fmt_type_private)
+				ret=vfd->vidioc_s_fmt_type_private(file,
+								fh, f);
+			break;
+		}
+		break;
+	}
+	case VIDIOC_TRY_FMT:
+	{
+		struct v4l2_format *f = (struct v4l2_format *)arg;
+
+		/* FIXME: Should be one dump per type */
+		dbgarg (cmd, "type=%s\n", prt_names(f->type,
+						v4l2_type_names_FIXME));
+		switch (f->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			if (vfd->vidioc_try_fmt_cap)
+				ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+			if (!ret)
+				v4l_print_pix_fmt(vfd,&f->fmt.pix);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+			if (vfd->vidioc_try_fmt_overlay)
+				ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_CAPTURE:
+			if (vfd->vidioc_try_fmt_vbi)
+				ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			if (vfd->vidioc_try_fmt_vbi_output)
+				ret=vfd->vidioc_try_fmt_vbi_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+			if (vfd->vidioc_try_fmt_vbi_capture)
+				ret=vfd->vidioc_try_fmt_vbi_capture(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			if (vfd->vidioc_try_fmt_video_output)
+				ret=vfd->vidioc_try_fmt_video_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_VBI_OUTPUT:
+			if (vfd->vidioc_try_fmt_vbi_output)
+				ret=vfd->vidioc_try_fmt_vbi_output(file,
+								fh, f);
+			break;
+		case V4L2_BUF_TYPE_PRIVATE:
+			if (vfd->vidioc_try_fmt_type_private)
+				ret=vfd->vidioc_try_fmt_type_private(file,
+								fh, f);
+			break;
+		}
+
+		break;
+	}
+	/* FIXME: Those buf reqs could be handled here,
+	   with some changes on videobuf to allow its header to be included at
+	   videodev2.h or being merged at videodev2.
+	 */
+	case VIDIOC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *p=arg;
+
+		if (!vfd->vidioc_reqbufs)
+			break;
+		ret = check_fmt (vfd, p->type);
+		if (ret)
+			break;
+
+		ret=vfd->vidioc_reqbufs(file, fh, p);
+		dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
+				p->count,
+				prt_names(p->type,v4l2_type_names_FIXME),
+				prt_names(p->memory,v4l2_memory_names));
+		break;
+	}
+	case VIDIOC_QUERYBUF:
+	{
+		struct v4l2_buffer *p=arg;
+
+		if (!vfd->vidioc_querybuf)
+			break;
+		ret = check_fmt (vfd, p->type);
+		if (ret)
+			break;
+
+		ret=vfd->vidioc_querybuf(file, fh, p);
+		if (!ret)
+			dbgbuf(cmd,vfd,p);
+		break;
+	}
+	case VIDIOC_QBUF:
+	{
+		struct v4l2_buffer *p=arg;
+
+		if (!vfd->vidioc_qbuf)
+			break;
+		ret = check_fmt (vfd, p->type);
+		if (ret)
+			break;
+
+		ret=vfd->vidioc_qbuf(file, fh, p);
+		if (!ret)
+			dbgbuf(cmd,vfd,p);
+		break;
+	}
+	case VIDIOC_DQBUF:
+	{
+		struct v4l2_buffer *p=arg;
+		if (!vfd->vidioc_qbuf)
+			break;
+		ret = check_fmt (vfd, p->type);
+		if (ret)
+			break;
+
+		ret=vfd->vidioc_qbuf(file, fh, p);
+		if (!ret)
+			dbgbuf(cmd,vfd,p);
+		break;
+	}
+	case VIDIOC_OVERLAY:
+	{
+		int *i = arg;
+
+		if (!vfd->vidioc_overlay)
+			break;
+		dbgarg (cmd, "value=%d\n",*i);
+		ret=vfd->vidioc_overlay(file, fh, *i);
+		break;
+	}
+#ifdef HAVE_V4L1
+	/* --- streaming capture ------------------------------------- */
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf *p=arg;
+
+		memset(p,0,sizeof(p));
+
+		if (!vfd->vidiocgmbuf)
+			break;
+		ret=vfd->vidiocgmbuf(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
+						p->size, p->frames,
+						(unsigned long)p->offsets);
+		break;
+	}
+#endif
+	case VIDIOC_G_FBUF:
+	{
+		struct v4l2_framebuffer *p=arg;
+		if (!vfd->vidioc_g_fbuf)
+			break;
+		ret=vfd->vidioc_g_fbuf(file, fh, arg);
+		if (!ret) {
+			dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+					p->capability,p->flags,
+					(unsigned long)p->base);
+			v4l_print_pix_fmt (vfd, &p->fmt);
+		}
+		break;
+	}
+	case VIDIOC_S_FBUF:
+	{
+		struct v4l2_framebuffer *p=arg;
+		if (!vfd->vidioc_s_fbuf)
+			break;
+
+		dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+				p->capability,p->flags,(unsigned long)p->base);
+		v4l_print_pix_fmt (vfd, &p->fmt);
+		ret=vfd->vidioc_s_fbuf(file, fh, arg);
+
+		break;
+	}
+	case VIDIOC_STREAMON:
+	{
+		enum v4l2_buf_type i = *(int *)arg;
+		if (!vfd->vidioc_streamon)
+			break;
+		dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+		ret=vfd->vidioc_streamon(file, fh,i);
+		break;
+	}
+	case VIDIOC_STREAMOFF:
+	{
+		enum v4l2_buf_type i = *(int *)arg;
+
+		if (!vfd->vidioc_streamoff)
+			break;
+		dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+		ret=vfd->vidioc_streamoff(file, fh, i);
+		break;
+	}
+	/* ---------- tv norms ---------- */
+	case VIDIOC_ENUMSTD:
+	{
+		struct v4l2_standard *p = arg;
+		unsigned int index = p->index;
+
+		if (!vfd->tvnormsize) {
+			printk (KERN_WARNING "%s: no TV norms defined!\n",
+						vfd->name);
+			break;
+		}
+
+		if (index<=0 || index >= vfd->tvnormsize) {
+			ret=-EINVAL;
+			break;
+		}
+		v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
+					 vfd->tvnorms[p->index].name);
+		p->index = index;
+
+		dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+				"framelines=%d\n", p->index,
+				(unsigned long long)p->id, p->name,
+				p->frameperiod.numerator,
+				p->frameperiod.denominator,
+				p->framelines);
+
+		ret=0;
+		break;
+	}
+	case VIDIOC_G_STD:
+	{
+		v4l2_std_id *id = arg;
+
+		*id = vfd->current_norm;
+
+		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+		ret=0;
+		break;
+	}
+	case VIDIOC_S_STD:
+	{
+		v4l2_std_id *id = arg;
+		unsigned int i;
+
+		if (!vfd->tvnormsize) {
+			printk (KERN_WARNING "%s: no TV norms defined!\n",
+						vfd->name);
+			break;
+		}
+
+		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+		/* First search for exact match */
+		for (i = 0; i < vfd->tvnormsize; i++)
+			if (*id == vfd->tvnorms[i].id)
+				break;
+		/* Then for a generic video std that contains desired std */
+		if (i == vfd->tvnormsize)
+			for (i = 0; i < vfd->tvnormsize; i++)
+				if (*id & vfd->tvnorms[i].id)
+					break;
+		if (i == vfd->tvnormsize) {
+			break;
+		}
+
+		/* Calls the specific handler */
+		if (vfd->vidioc_s_std)
+			ret=vfd->vidioc_s_std(file, fh, i);
+		else
+			ret=-EINVAL;
+
+		/* Updates standard information */
+		if (!ret)
+			vfd->current_norm=*id;
+
+		break;
+	}
+	case VIDIOC_QUERYSTD:
+	{
+		v4l2_std_id *p=arg;
+
+		if (!vfd->vidioc_querystd)
+			break;
+		ret=vfd->vidioc_querystd(file, fh, arg);
+		if (!ret)
+			dbgarg (cmd, "detected std=%Lu\n",
+						(unsigned long long)*p);
+		break;
+	}
+	/* ------ input switching ---------- */
+	/* FIXME: Inputs can be handled inside videodev2 */
+	case VIDIOC_ENUMINPUT:
+	{
+		struct v4l2_input *p=arg;
+		int i=p->index;
+
+		if (!vfd->vidioc_enum_input)
+			break;
+		memset(p, 0, sizeof(*p));
+		p->index=i;
+
+		ret=vfd->vidioc_enum_input(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "index=%d, name=%s, type=%d, "
+					"audioset=%d, "
+					"tuner=%d, std=%Ld, status=%d\n",
+					p->index,p->name,p->type,p->audioset,
+					p->tuner,
+					(unsigned long long)p->std,
+					p->status);
+		break;
+	}
+	case VIDIOC_G_INPUT:
+	{
+		unsigned int *i = arg;
+
+		if (!vfd->vidioc_g_input)
+			break;
+		ret=vfd->vidioc_g_input(file, fh, i);
+		if (!ret)
+			dbgarg (cmd, "value=%d\n",*i);
+		break;
+	}
+	case VIDIOC_S_INPUT:
+	{
+		unsigned int *i = arg;
+
+		if (!vfd->vidioc_s_input)
+			break;
+		dbgarg (cmd, "value=%d\n",*i);
+		ret=vfd->vidioc_s_input(file, fh, *i);
+		break;
+	}
+
+	/* ------ output switching ---------- */
+	case VIDIOC_G_OUTPUT:
+	{
+		unsigned int *i = arg;
+
+		if (!vfd->vidioc_g_output)
+			break;
+		ret=vfd->vidioc_g_output(file, fh, i);
+		if (!ret)
+			dbgarg (cmd, "value=%d\n",*i);
+		break;
+	}
+	case VIDIOC_S_OUTPUT:
+	{
+		unsigned int *i = arg;
+
+		if (!vfd->vidioc_s_output)
+			break;
+		dbgarg (cmd, "value=%d\n",*i);
+		ret=vfd->vidioc_s_output(file, fh, *i);
+		break;
+	}
+
+	/* --- controls ---------------------------------------------- */
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *p=arg;
+
+		if (!vfd->vidioc_queryctrl)
+			break;
+		ret=vfd->vidioc_queryctrl(file, fh, p);
+
+		if (!ret)
+			dbgarg (cmd, "id=%d, type=%d, name=%s, "
+					"min/max=%d/%d,"
+					" step=%d, default=%d, flags=0x%08x\n",
+					p->id,p->type,p->name,p->minimum,
+					p->maximum,p->step,p->default_value,
+					p->flags);
+		break;
+	}
+	case VIDIOC_G_CTRL:
+	{
+		struct v4l2_control *p = arg;
+
+		if (!vfd->vidioc_g_ctrl)
+			break;
+		dbgarg(cmd, "Enum for index=%d\n", p->id);
+
+		ret=vfd->vidioc_g_ctrl(file, fh, p);
+		if (!ret)
+			dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+		break;
+	}
+	case VIDIOC_S_CTRL:
+	{
+		struct v4l2_control *p = arg;
+
+		if (!vfd->vidioc_s_ctrl)
+			break;
+		dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
+
+		ret=vfd->vidioc_s_ctrl(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *p = arg;
+
+		if (vfd->vidioc_g_ext_ctrls) {
+			dbgarg(cmd, "count=%d\n", p->count);
+
+			ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
+		}
+		break;
+	}
+	case VIDIOC_S_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *p = arg;
+
+		if (vfd->vidioc_s_ext_ctrls) {
+			dbgarg(cmd, "count=%d\n", p->count);
+
+			ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
+		}
+		break;
+	}
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *p = arg;
+
+		if (vfd->vidioc_try_ext_ctrls) {
+			dbgarg(cmd, "count=%d\n", p->count);
+
+			ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
+		}
+		break;
+	}
+	case VIDIOC_QUERYMENU:
+	{
+		struct v4l2_querymenu *p=arg;
+		if (!vfd->vidioc_querymenu)
+			break;
+		ret=vfd->vidioc_querymenu(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "id=%d, index=%d, name=%s\n",
+						p->id,p->index,p->name);
+		break;
+	}
+	/* --- audio ---------------------------------------------- */
+	case VIDIOC_ENUMAUDIO:
+	{
+		struct v4l2_audio *p=arg;
+
+		if (!vfd->vidioc_enumaudio)
+			break;
+		dbgarg(cmd, "Enum for index=%d\n", p->index);
+		ret=vfd->vidioc_enumaudio(file, fh, p);
+		if (!ret)
+			dbgarg2("index=%d, name=%s, capability=%d, "
+					"mode=%d\n",p->index,p->name,
+					p->capability, p->mode);
+		break;
+	}
+	case VIDIOC_G_AUDIO:
+	{
+		struct v4l2_audio *p=arg;
+
+		if (!vfd->vidioc_g_audio)
+			break;
+		dbgarg(cmd, "Get for index=%d\n", p->index);
+		ret=vfd->vidioc_g_audio(file, fh, p);
+		if (!ret)
+			dbgarg2("index=%d, name=%s, capability=%d, "
+					"mode=%d\n",p->index,
+					p->name,p->capability, p->mode);
+		break;
+	}
+	case VIDIOC_S_AUDIO:
+	{
+		struct v4l2_audio *p=arg;
+
+		if (!vfd->vidioc_s_audio)
+			break;
+		dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+					"mode=%d\n", p->index, p->name,
+					p->capability, p->mode);
+		ret=vfd->vidioc_s_audio(file, fh, p);
+		break;
+	}
+	case VIDIOC_ENUMAUDOUT:
+	{
+		struct v4l2_audioout *p=arg;
+
+		if (!vfd->vidioc_enumaudout)
+			break;
+		dbgarg(cmd, "Enum for index=%d\n", p->index);
+		ret=vfd->vidioc_enumaudout(file, fh, p);
+		if (!ret)
+			dbgarg2("index=%d, name=%s, capability=%d, "
+					"mode=%d\n", p->index, p->name,
+					p->capability,p->mode);
+		break;
+	}
+	case VIDIOC_G_AUDOUT:
+	{
+		struct v4l2_audioout *p=arg;
+
+		if (!vfd->vidioc_g_audout)
+			break;
+		dbgarg(cmd, "Enum for index=%d\n", p->index);
+		ret=vfd->vidioc_g_audout(file, fh, p);
+		if (!ret)
+			dbgarg2("index=%d, name=%s, capability=%d, "
+					"mode=%d\n", p->index, p->name,
+					p->capability,p->mode);
+		break;
+	}
+	case VIDIOC_S_AUDOUT:
+	{
+		struct v4l2_audioout *p=arg;
+
+		if (!vfd->vidioc_s_audout)
+			break;
+		dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+					"mode=%d\n", p->index, p->name,
+					p->capability,p->mode);
+
+		ret=vfd->vidioc_s_audout(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_MODULATOR:
+	{
+		struct v4l2_modulator *p=arg;
+		if (!vfd->vidioc_g_modulator)
+			break;
+		ret=vfd->vidioc_g_modulator(file, fh, p);
+		if (!ret)
+			dbgarg(cmd, "index=%d, name=%s, "
+					"capability=%d, rangelow=%d,"
+					" rangehigh=%d, txsubchans=%d\n",
+					p->index, p->name,p->capability,
+					p->rangelow, p->rangehigh,
+					p->txsubchans);
+		break;
+	}
+	case VIDIOC_S_MODULATOR:
+	{
+		struct v4l2_modulator *p=arg;
+		if (!vfd->vidioc_s_modulator)
+			break;
+		dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+				"rangelow=%d, rangehigh=%d, txsubchans=%d\n",
+				p->index, p->name,p->capability,p->rangelow,
+				p->rangehigh,p->txsubchans);
+			ret=vfd->vidioc_s_modulator(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_CROP:
+	{
+		struct v4l2_crop *p=arg;
+		if (!vfd->vidioc_g_crop)
+			break;
+		ret=vfd->vidioc_g_crop(file, fh, p);
+		if (!ret) {
+			dbgarg(cmd, "type=%d\n", p->type);
+			dbgrect(vfd, "", &p->c);
+		}
+		break;
+	}
+	case VIDIOC_S_CROP:
+	{
+		struct v4l2_crop *p=arg;
+		if (!vfd->vidioc_s_crop)
+			break;
+		dbgarg(cmd, "type=%d\n", p->type);
+		dbgrect(vfd, "", &p->c);
+		ret=vfd->vidioc_s_crop(file, fh, p);
+		break;
+	}
+	case VIDIOC_CROPCAP:
+	{
+		struct v4l2_cropcap *p=arg;
+		/*FIXME: Should also show v4l2_fract pixelaspect */
+		if (!vfd->vidioc_cropcap)
+			break;
+		dbgarg(cmd, "type=%d\n", p->type);
+		dbgrect(vfd, "bounds ", &p->bounds);
+		dbgrect(vfd, "defrect ", &p->defrect);
+		ret=vfd->vidioc_cropcap(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_MPEGCOMP:
+	{
+		struct v4l2_mpeg_compression *p=arg;
+
+		/*FIXME: Several fields not shown */
+		if (!vfd->vidioc_g_mpegcomp)
+			break;
+		ret=vfd->vidioc_g_mpegcomp(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
+					" ts_pid_video=%d, ts_pid_pcr=%d, "
+					"ps_size=%d, au_sample_rate=%d, "
+					"au_pesid=%c, vi_frame_rate=%d, "
+					"vi_frames_per_gop=%d, "
+					"vi_bframes_count=%d, vi_pesid=%c\n",
+					p->ts_pid_pmt,p->ts_pid_audio,
+					p->ts_pid_video,p->ts_pid_pcr,
+					p->ps_size, p->au_sample_rate,
+					p->au_pesid, p->vi_frame_rate,
+					p->vi_frames_per_gop,
+					p->vi_bframes_count, p->vi_pesid);
+		break;
+	}
+	case VIDIOC_S_MPEGCOMP:
+	{
+		struct v4l2_mpeg_compression *p=arg;
+		/*FIXME: Several fields not shown */
+		if (!vfd->vidioc_s_mpegcomp)
+			break;
+		dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
+				"ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
+				"au_sample_rate=%d, au_pesid=%c, "
+				"vi_frame_rate=%d, vi_frames_per_gop=%d, "
+				"vi_bframes_count=%d, vi_pesid=%c\n",
+				p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+				p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+				p->au_pesid, p->vi_frame_rate,
+				p->vi_frames_per_gop, p->vi_bframes_count,
+				p->vi_pesid);
+		ret=vfd->vidioc_s_mpegcomp(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_JPEGCOMP:
+	{
+		struct v4l2_jpegcompression *p=arg;
+		if (!vfd->vidioc_g_jpegcomp)
+			break;
+		ret=vfd->vidioc_g_jpegcomp(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "quality=%d, APPn=%d, "
+						"APP_len=%d, COM_len=%d, "
+						"jpeg_markers=%d\n",
+						p->quality,p->APPn,p->APP_len,
+						p->COM_len,p->jpeg_markers);
+		break;
+	}
+	case VIDIOC_S_JPEGCOMP:
+	{
+		struct v4l2_jpegcompression *p=arg;
+		if (!vfd->vidioc_g_jpegcomp)
+			break;
+		dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
+					"COM_len=%d, jpeg_markers=%d\n",
+					p->quality,p->APPn,p->APP_len,
+					p->COM_len,p->jpeg_markers);
+			ret=vfd->vidioc_s_jpegcomp(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_PARM:
+	{
+		struct v4l2_streamparm *p=arg;
+		if (!vfd->vidioc_g_parm)
+			break;
+		ret=vfd->vidioc_g_parm(file, fh, p);
+		dbgarg (cmd, "type=%d\n", p->type);
+		break;
+	}
+	case VIDIOC_S_PARM:
+	{
+		struct v4l2_streamparm *p=arg;
+		if (!vfd->vidioc_s_parm)
+			break;
+		dbgarg (cmd, "type=%d\n", p->type);
+		ret=vfd->vidioc_s_parm(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_TUNER:
+	{
+		struct v4l2_tuner *p=arg;
+		if (!vfd->vidioc_g_tuner)
+			break;
+		ret=vfd->vidioc_g_tuner(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "index=%d, name=%s, type=%d, "
+					"capability=%d, rangelow=%d, "
+					"rangehigh=%d, signal=%d, afc=%d, "
+					"rxsubchans=%d, audmode=%d\n",
+					p->index, p->name, p->type,
+					p->capability, p->rangelow,
+					p->rangehigh, p->rxsubchans,
+					p->audmode, p->signal, p->afc);
+		break;
+	}
+	case VIDIOC_S_TUNER:
+	{
+		struct v4l2_tuner *p=arg;
+		if (!vfd->vidioc_s_tuner)
+			break;
+		dbgarg (cmd, "index=%d, name=%s, type=%d, "
+				"capability=%d, rangelow=%d, rangehigh=%d, "
+				"signal=%d, afc=%d, rxsubchans=%d, "
+				"audmode=%d\n",p->index, p->name, p->type,
+				p->capability, p->rangelow,p->rangehigh,
+				p->rxsubchans, p->audmode, p->signal,
+				p->afc);
+		ret=vfd->vidioc_s_tuner(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_FREQUENCY:
+	{
+		struct v4l2_frequency *p=arg;
+		if (!vfd->vidioc_g_frequency)
+			break;
+		ret=vfd->vidioc_g_frequency(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+						p->tuner,p->type,p->frequency);
+		break;
+	}
+	case VIDIOC_S_FREQUENCY:
+	{
+		struct v4l2_frequency *p=arg;
+		if (!vfd->vidioc_s_frequency)
+			break;
+		dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+				p->tuner,p->type,p->frequency);
+		ret=vfd->vidioc_s_frequency(file, fh, p);
+		break;
+	}
+	case VIDIOC_G_SLICED_VBI_CAP:
+	{
+		struct v4l2_sliced_vbi_cap *p=arg;
+		if (!vfd->vidioc_g_sliced_vbi_cap)
+			break;
+		ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "service_set=%d\n", p->service_set);
+		break;
+	}
+	case VIDIOC_LOG_STATUS:
+	{
+		if (!vfd->vidioc_log_status)
+			break;
+		ret=vfd->vidioc_log_status(file, fh);
+		break;
+	}
+
+	/* --- Others --------------------------------------------- */
+
+	default:
+		ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
+	}
+
+	if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
+		if (ret<0) {
+			printk ("%s: err:\n", vfd->name);
+			v4l_print_ioctl(vfd->name, cmd);
+		}
+	}
+
+	return ret;
+}
+
+int video_ioctl2 (struct inode *inode, struct file *file,
+	       unsigned int cmd, unsigned long arg)
+{
+	char	sbuf[128];
+	void    *mbuf = NULL;
+	void	*parg = NULL;
+	int	err  = -EINVAL;
+	int     is_ext_ctrl;
+	size_t  ctrls_size = 0;
+	void __user *user_ptr = NULL;
+
+#ifdef __OLD_VIDIOC_
+	cmd = video_fix_command(cmd);
+#endif
+	is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+		       cmd == VIDIOC_TRY_EXT_CTRLS);
 
 	/*  Copy arguments into temp kernel buffer  */
 	switch (_IOC_DIR(cmd)) {
@@ -194,13 +1428,43 @@
 		break;
 	}
 
-	/* call driver */
-	err = func(inode, file, cmd, parg);
+	if (is_ext_ctrl) {
+		struct v4l2_ext_controls *p = parg;
+
+		/* In case of an error, tell the caller that it wasn't
+		   a specific control that caused it. */
+		p->error_idx = p->count;
+		user_ptr = (void __user *)p->controls;
+		if (p->count) {
+			ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+			/* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+			mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+			err = -ENOMEM;
+			if (NULL == mbuf)
+				goto out_ext_ctrl;
+			err = -EFAULT;
+			if (copy_from_user(mbuf, user_ptr, ctrls_size))
+				goto out_ext_ctrl;
+			p->controls = mbuf;
+		}
+	}
+
+	/* Handles IOCTL */
+	err = __video_do_ioctl(inode, file, cmd, parg);
 	if (err == -ENOIOCTLCMD)
 		err = -EINVAL;
+	if (is_ext_ctrl) {
+		struct v4l2_ext_controls *p = parg;
+
+		p->controls = (void *)user_ptr;
+		if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+			err = -EFAULT;
+		goto out_ext_ctrl;
+	}
 	if (err < 0)
 		goto out;
 
+out_ext_ctrl:
 	/*  Copy results into user buffer  */
 	switch (_IOC_DIR(cmd))
 	{
@@ -216,31 +1480,6 @@
 	return err;
 }
 
-/*
- * open/release helper functions -- handle exclusive opens
- */
-int video_exclusive_open(struct inode *inode, struct file *file)
-{
-	struct  video_device *vfl = video_devdata(file);
-	int retval = 0;
-
-	mutex_lock(&vfl->lock);
-	if (vfl->users) {
-		retval = -EBUSY;
-	} else {
-		vfl->users++;
-	}
-	mutex_unlock(&vfl->lock);
-	return retval;
-}
-
-int video_exclusive_release(struct inode *inode, struct file *file)
-{
-	struct  video_device *vfl = video_devdata(file);
-
-	vfl->users--;
-	return 0;
-}
 
 static struct file_operations video_fops;
 
@@ -371,7 +1610,9 @@
 	mutex_unlock(&videodev_lock);
 }
 
-
+/*
+ * Video fs operations
+ */
 static struct file_operations video_fops=
 {
 	.owner		= THIS_MODULE,
@@ -387,7 +1628,7 @@
 {
 	int ret;
 
-	printk(KERN_INFO "Linux video capture interface: v1.00\n");
+	printk(KERN_INFO "Linux video capture interface: v2.00\n");
 	if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
 		printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
 		return -EIO;
@@ -418,11 +1659,12 @@
 EXPORT_SYMBOL(video_usercopy);
 EXPORT_SYMBOL(video_exclusive_open);
 EXPORT_SYMBOL(video_exclusive_release);
+EXPORT_SYMBOL(video_ioctl2);
 EXPORT_SYMBOL(video_device_alloc);
 EXPORT_SYMBOL(video_device_release);
 
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
 MODULE_LICENSE("GPL");
 
 
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index a8c1014..268e69f 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -40,7 +40,7 @@
 #include <linux/i2c-algo-sgi.h>
 
 #include <linux/videodev.h>
-#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 779db26..41d23c8 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -48,34 +48,15 @@
 
 #include "font.h"
 
-#ifndef kzalloc
-#define kzalloc(size, flags)                            \
-({                                                      \
-	void *__ret = kmalloc(size, flags);             \
-	if (__ret)                                      \
-		memset(__ret, 0, size);                 \
-	__ret;                                          \
-})
-#endif
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
 #define VIVI_MAJOR_VERSION 0
 #define VIVI_MINOR_VERSION 4
 #define VIVI_RELEASE 0
 #define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
 
-static int video_nr = -1;        /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-
-static int debug = 0;
-module_param(debug, int, 0);
-
-static unsigned int vid_limit = 16;
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+static struct video_device vivi;	/* Video device */
+static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */
 
 /* supported controls */
 static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -129,10 +110,10 @@
 
 static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
 
-#define dprintk(level,fmt, arg...)			     \
-	do { 						     \
-		if (debug >= (level))			     \
-			printk(KERN_DEBUG "vivi: " fmt , ## arg);    \
+#define dprintk(level,fmt, arg...)					\
+	do {								\
+		if (vivi.debug >= (level))				\
+			printk(KERN_DEBUG "vivi: " fmt , ## arg);	\
 	} while (0)
 
 /* ------------------------------------------------------------------
@@ -190,7 +171,7 @@
 
 	/* various device info */
 	unsigned int               resources;
-	struct video_device        video_dev;
+	struct video_device        vfd;
 
 	struct vivi_dmaqueue       vidq;
 
@@ -248,7 +229,8 @@
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
+static void prep_to_addr(struct sg_to_addr to_addr[],
+			 struct videobuf_buffer *vb)
 {
 	int i, pos=0;
 
@@ -259,7 +241,7 @@
 	}
 }
 
-inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
+static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
 {
 	int p1=0,p2=pages-1,p3=pages/2;
 
@@ -280,8 +262,8 @@
 	return (p1);
 }
 
-void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
-					int hmax, int line, char *timestr)
+static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
+		     int hmax, int line, char *timestr)
 {
 	int  w,i,j,pos=inipos,pgpos,oldpg,y;
 	char *p,*s,*basep;
@@ -491,7 +473,7 @@
 		dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
 }
 
-void vivi_sleep(struct vivi_dmaqueue  *dma_q)
+static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
 {
 	int timeout;
 	DECLARE_WAITQUEUE(wait, current);
@@ -526,7 +508,7 @@
 	try_to_freeze();
 }
 
-int vivi_thread(void *data)
+static int vivi_thread(void *data)
 {
 	struct vivi_dmaqueue  *dma_q=data;
 
@@ -542,7 +524,7 @@
 	return 0;
 }
 
-int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
+static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
 {
 	dma_q->frame=0;
 	dma_q->ini_jiffies=jiffies;
@@ -560,7 +542,7 @@
 	return 0;
 }
 
-void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
+static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
 {
 	dprintk(1,"%s\n",__FUNCTION__);
 	/* shutdown control thread */
@@ -666,8 +648,7 @@
 	return 0;
 }
 
-void
-free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
 	dprintk(1,"%s\n",__FUNCTION__);
 
@@ -791,8 +772,8 @@
 	free_buffer(vq,buf);
 }
 
-int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
-	   int direction)
+static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
+		       int direction)
 {
 	int i;
 
@@ -808,15 +789,15 @@
 	return nents;
 }
 
-int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-					int direction)
+static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
+			 int direction)
 {
 	dprintk(1,"%s\n",__FUNCTION__);
 	return 0;
 }
 
-int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-					int direction)
+static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
+			    int direction)
 {
 //	dprintk(1,"%s\n",__FUNCTION__);
 
@@ -840,7 +821,80 @@
 	IOCTL handling
    ------------------------------------------------------------------*/
 
-static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+
+static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+	/* is it free? */
+	down(&dev->lock);
+	if (dev->resources) {
+		/* no, someone else uses it */
+		up(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	dev->resources =1;
+	dprintk(1,"res: get\n");
+	up(&dev->lock);
+	return 1;
+}
+
+static int res_locked(struct vivi_dev *dev)
+{
+	return (dev->resources);
+}
+
+static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+	down(&dev->lock);
+	dev->resources = 0;
+	dprintk(1,"res: put\n");
+	up(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "vivi");
+	strcpy(cap->card, "vivi");
+	cap->version = VIVI_VERSION;
+	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE |
+				V4L2_CAP_STREAMING     |
+				V4L2_CAP_READWRITE;
+	return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index > 0)
+		return -EINVAL;
+
+	strlcpy(f->description,format.name,sizeof(f->description));
+	f->pixelformat = format.fourcc;
+	return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivi_fh  *fh=priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->vb_vidq.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return (0);
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
 			struct v4l2_format *f)
 {
 	struct vivi_fmt *fmt;
@@ -848,7 +902,8 @@
 	unsigned int maxw, maxh;
 
 	if (format.fourcc != f->fmt.pix.pixelformat) {
-		dprintk(1,"Fourcc format invalid.\n");
+		dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+			"only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
 		return -EINVAL;
 	}
 	fmt=&format;
@@ -884,356 +939,196 @@
 	return 0;
 }
 
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+					struct v4l2_format *f)
 {
-	/* is it free? */
-	down(&dev->lock);
-	if (dev->resources) {
-		/* no, someone else uses it */
-		up(&dev->lock);
-		return 0;
-	}
-	/* it's free, grab it */
-	dev->resources =1;
-	dprintk(1,"res: get\n");
-	up(&dev->lock);
-	return 1;
+	struct vivi_fh  *fh=priv;
+	int ret = vidioc_try_fmt_cap(file,fh,f);
+	if (ret < 0)
+		return (ret);
+
+	fh->fmt           = &format;
+	fh->width         = f->fmt.pix.width;
+	fh->height        = f->fmt.pix.height;
+	fh->vb_vidq.field = f->fmt.pix.field;
+	fh->type          = f->type;
+
+	return (0);
 }
 
-static inline int res_locked(struct vivi_dev *dev)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
 {
-	return (dev->resources);
+	struct vivi_fh  *fh=priv;
+
+	return (videobuf_reqbufs(&fh->vb_vidq, p));
 }
 
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	down(&dev->lock);
-	dev->resources = 0;
-	dprintk(1,"res: put\n");
-	up(&dev->lock);
+	struct vivi_fh  *fh=priv;
+
+	return (videobuf_querybuf(&fh->vb_vidq, p));
 }
 
-static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh     = file->private_data;
-	struct vivi_dev *dev    = fh->dev;
-	int ret=0;
+	struct vivi_fh  *fh=priv;
 
-	if (debug) {
-		if (_IOC_DIR(cmd) & _IOC_WRITE)
-			v4l_printk_ioctl_arg("vivi(w)",cmd, arg);
-		else if (!_IOC_DIR(cmd) & _IOC_READ) {
-			v4l_print_ioctl("vivi", cmd);
-		}
-	}
+	return (videobuf_qbuf(&fh->vb_vidq, p));
+}
 
-	switch(cmd) {
-	/* --- capabilities ------------------------------------------ */
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+	struct vivi_fh  *fh=priv;
 
-		memset(cap, 0, sizeof(*cap));
+	return (videobuf_dqbuf(&fh->vb_vidq, p,
+				file->f_flags & O_NONBLOCK));
+}
 
-		strcpy(cap->driver, "vivi");
-		strcpy(cap->card, "vivi");
-		cap->version = VIVI_VERSION;
-		cap->capabilities =
-					V4L2_CAP_VIDEO_CAPTURE |
-					V4L2_CAP_STREAMING     |
-					V4L2_CAP_READWRITE;
-		break;
-	}
-	/* --- capture ioctls ---------------------------------------- */
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *f = arg;
-		enum v4l2_buf_type type;
-		unsigned int index;
-
-		index = f->index;
-		type  = f->type;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-
-		switch (type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			if (index > 0){
-				ret=-EINVAL;
-				break;
-			}
-			memset(f,0,sizeof(*f));
-
-			f->index = index;
-			f->type  = type;
-			strlcpy(f->description,format.name,sizeof(f->description));
-			f->pixelformat = format.fourcc;
-			break;
-		default:
-			ret=-EINVAL;
-		}
-		break;
-	}
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *f = (struct v4l2_format *)arg;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-
-		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
-		f->fmt.pix.width        = fh->width;
-		f->fmt.pix.height       = fh->height;
-		f->fmt.pix.field        = fh->vb_vidq.field;
-		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-		f->fmt.pix.bytesperline =
-			(f->fmt.pix.width * fh->fmt->depth) >> 3;
-		f->fmt.pix.sizeimage =
-			f->fmt.pix.height * f->fmt.pix.bytesperline;
-		break;
-	}
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *f = arg;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			dprintk(1,"Only capture supported.\n");
-			ret=-EINVAL;
-			break;
-		}
-
-		ret = vivi_try_fmt(dev,fh,f);
-		if (ret < 0)
-			break;
-
-		fh->fmt           = &format;
-		fh->width         = f->fmt.pix.width;
-		fh->height        = f->fmt.pix.height;
-		fh->vb_vidq.field = f->fmt.pix.field;
-		fh->type          = f->type;
-
-		break;
-	}
-	case VIDIOC_TRY_FMT:
-	{
-		struct v4l2_format *f = arg;
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-
-		ret=vivi_try_fmt(dev,fh,f);
-		break;
-	}
-	case VIDIOC_REQBUFS:
-		if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-		ret=videobuf_reqbufs(&fh->vb_vidq, arg);
-		break;
-	case VIDIOC_QUERYBUF:
-		if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-		ret=videobuf_querybuf(&fh->vb_vidq, arg);
-		break;
-	case VIDIOC_QBUF:
-		if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-		ret=videobuf_qbuf(&fh->vb_vidq, arg);
-		break;
-	case VIDIOC_DQBUF:
-		if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-		ret=videobuf_dqbuf(&fh->vb_vidq, arg,
-					file->f_flags & O_NONBLOCK);
-		break;
 #ifdef HAVE_V4L1
-	/* --- streaming capture ------------------------------------- */
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *mbuf = arg;
-		struct videobuf_queue *q=&fh->vb_vidq;
-		struct v4l2_requestbuffers req;
-		unsigned int i;
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+	struct vivi_fh  *fh=priv;
+	struct videobuf_queue *q=&fh->vb_vidq;
+	struct v4l2_requestbuffers req;
+	unsigned int i, ret;
 
-		memset(&req,0,sizeof(req));
-		req.type   = q->type;
-		req.count  = 8;
-		req.memory = V4L2_MEMORY_MMAP;
-		ret = videobuf_reqbufs(q,&req);
-		if (ret < 0)
-			break;
-		memset(mbuf,0,sizeof(*mbuf));
-		mbuf->frames = req.count;
-		mbuf->size   = 0;
-		for (i = 0; i < mbuf->frames; i++) {
-			mbuf->offsets[i]  = q->bufs[i]->boff;
-			mbuf->size       += q->bufs[i]->bsize;
-		}
-		break;
+	req.type   = q->type;
+	req.count  = 8;
+	req.memory = V4L2_MEMORY_MMAP;
+	ret = videobuf_reqbufs(q,&req);
+	if (ret < 0)
+		return (ret);
+
+	mbuf->frames = req.count;
+	mbuf->size   = 0;
+	for (i = 0; i < mbuf->frames; i++) {
+		mbuf->offsets[i]  = q->bufs[i]->boff;
+		mbuf->size       += q->bufs[i]->bsize;
 	}
+	return (0);
+}
 #endif
-	case VIDIOC_STREAMON:
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct vivi_fh  *fh=priv;
+	struct vivi_dev *dev    = fh->dev;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	if (!res_get(dev,fh))
+		return -EBUSY;
+	return (videobuf_streamon(&fh->vb_vidq));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct vivi_fh  *fh=priv;
+	struct vivi_dev *dev    = fh->dev;
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	videobuf_streamoff(&fh->vb_vidq);
+	res_free(dev,fh);
+
+	return (0);
+}
+
+static struct v4l2_tvnorm tvnorms[] = {
 	{
-		if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		if (!res_get(dev,fh))
-			return -EBUSY;
-		ret=videobuf_streamon(&fh->vb_vidq);
-		break;
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
 	}
-	case VIDIOC_STREAMOFF:
-	{
-		if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			ret=-EINVAL;
-			break;
-		}
-		ret = videobuf_streamoff(&fh->vb_vidq);
-		if (ret < 0)
-			break;
-		res_free(dev,fh);
-		break;
-	}
-	/* ---------- tv norms ---------- */
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
+};
 
-		if (e->index>0) {
-			ret=-EINVAL;
-			break;
-		}
-		ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M");
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+{
 
-		/* Allows vivi to use different fps from video std */
-		e->frameperiod.numerator = WAKE_NUMERATOR;
-		e->frameperiod.denominator = WAKE_DENOMINATOR;
+	return 0;
+}
 
-		break;
-	}
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *id = arg;
+/* only one input in this sample driver */
+static int vidioc_enum_input (struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	if (inp->index != 0)
+		return -EINVAL;
 
-		*id = V4L2_STD_NTSC_M;
-		break;
-	}
-	case VIDIOC_S_STD:
-	{
-		break;
-	}
-	/* ------ input switching ---------- */
-	case VIDIOC_ENUMINPUT:
-	{ /* only one input in this sample driver */
-		struct v4l2_input *inp = arg;
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	inp->std = V4L2_STD_NTSC_M;
+	strcpy(inp->name,"Camera");
 
-		if (inp->index != 0) {
-			ret=-EINVAL;
-			break;
-		}
-		memset(inp, 0, sizeof(*inp));
+	return (0);
+}
 
-		inp->index = 0;
-		inp->type = V4L2_INPUT_TYPE_CAMERA;
-		inp->std = V4L2_STD_NTSC_M;
-		strcpy(inp->name,"Camera");
-		break;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		unsigned int *i = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
 
-		*i = 0;
-		break;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		unsigned int *i = arg;
+	return (0);
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+	if (i > 0)
+		return -EINVAL;
 
-		if (*i > 0)
-			ret=-EINVAL;
-		break;
-	}
+	return (0);
+}
 
 	/* --- controls ---------------------------------------------- */
-	case VIDIOC_QUERYCTRL:
-	{
-		struct v4l2_queryctrl *qc = arg;
-		int i;
+static int vidioc_queryctrl (struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	int i;
 
-		for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-			if (qc->id && qc->id == vivi_qctrl[i].id) {
-				memcpy(qc, &(vivi_qctrl[i]),
-					sizeof(*qc));
-				break;
-			}
+	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+		if (qc->id && qc->id == vivi_qctrl[i].id) {
+			memcpy(qc, &(vivi_qctrl[i]),
+				sizeof(*qc));
+			return (0);
+		}
 
-		ret=-EINVAL;
-		break;
-	}
-	case VIDIOC_G_CTRL:
-	{
-		struct v4l2_control *ctrl = arg;
-		int i;
-
-		for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-			if (ctrl->id == vivi_qctrl[i].id) {
-				ctrl->value=qctl_regs[i];
-				break;
-			}
-
-		ret=-EINVAL;
-		break;
-	}
-	case VIDIOC_S_CTRL:
-	{
-		struct v4l2_control *ctrl = arg;
-		int i;
-		for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-			if (ctrl->id == vivi_qctrl[i].id) {
-				if (ctrl->value <
-					vivi_qctrl[i].minimum
-					|| ctrl->value >
-					vivi_qctrl[i].maximum) {
-						ret=-ERANGE;
-						break;
-					}
-				qctl_regs[i]=ctrl->value;
-				break;
-			}
-		ret=-EINVAL;
-		break;
-	}
-	default:
-		ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl);
-	}
-
-	if (debug) {
-		if (ret<0) {
-			v4l_print_ioctl("vivi(err)", cmd);
-			dprintk(1,"errcode=%d\n",ret);
-		} else if (_IOC_DIR(cmd) & _IOC_READ)
-			v4l_printk_ioctl_arg("vivi(r)",cmd, arg);
-	}
-
-	return ret;
+	return -EINVAL;
 }
 
-static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int vidioc_g_ctrl (struct file *file, void *priv,
+				struct v4l2_control *ctrl)
 {
-	return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+		if (ctrl->id == vivi_qctrl[i].id) {
+			ctrl->value=qctl_regs[i];
+			return (0);
+		}
+
+	return -EINVAL;
+}
+static int vidioc_s_ctrl (struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+		if (ctrl->id == vivi_qctrl[i].id) {
+			if (ctrl->value <
+				vivi_qctrl[i].minimum
+				|| ctrl->value >
+				vivi_qctrl[i].maximum) {
+					return (-ERANGE);
+				}
+			qctl_regs[i]=ctrl->value;
+			return (0);
+		}
+	return -EINVAL;
 }
 
 /* ------------------------------------------------------------------
@@ -1255,7 +1150,7 @@
 
 	list_for_each(list,&vivi_devlist) {
 		h = list_entry(list, struct vivi_dev, vivi_devlist);
-		if (h->video_dev.minor == minor) {
+		if (h->vfd.minor == minor) {
 			dev  = h;
 			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 		}
@@ -1264,6 +1159,7 @@
 		return -ENODEV;
 
 
+
 	/* If more than one user, mutex should be added */
 	dev->users++;
 
@@ -1279,6 +1175,7 @@
 
 	file->private_data = fh;
 	fh->dev      = dev;
+
 	fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	fh->fmt      = &format;
 	fh->width    = 640;
@@ -1314,7 +1211,7 @@
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-	struct vivi_fh *fh = file->private_data;
+	struct vivi_fh        *fh = file->private_data;
 
 	if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		if (res_locked(fh->dev))
@@ -1328,8 +1225,8 @@
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
-	struct vivi_fh *fh = file->private_data;
-	struct vivi_buffer *buf;
+	struct vivi_fh        *fh = file->private_data;
+	struct vivi_buffer    *buf;
 
 	dprintk(1,"%s\n",__FUNCTION__);
 
@@ -1358,8 +1255,8 @@
 
 static int vivi_release(struct inode *inode, struct file *file)
 {
-	struct vivi_fh  *fh     = file->private_data;
-	struct vivi_dev *dev    = fh->dev;
+	struct vivi_fh         *fh = file->private_data;
+	struct vivi_dev *dev       = fh->dev;
 	struct vivi_dmaqueue *vidq = &dev->vidq;
 
 	int minor = iminor(inode);
@@ -1379,7 +1276,7 @@
 static int
 vivi_mmap(struct file *file, struct vm_area_struct * vma)
 {
-	struct vivi_fh *fh = file->private_data;
+	struct vivi_fh        *fh = file->private_data;
 	int ret;
 
 	dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
@@ -1400,20 +1297,44 @@
 	.release        = vivi_release,
 	.read           = vivi_read,
 	.poll		= vivi_poll,
-	.ioctl          = vivi_ioctl,
+	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
 	.mmap		= vivi_mmap,
 	.llseek         = no_llseek,
 };
 
 static struct video_device vivi = {
-	.name		= "VTM Virtual Video Capture Board",
+	.name		= "vivi",
 	.type		= VID_TYPE_CAPTURE,
 	.hardware	= 0,
 	.fops           = &vivi_fops,
 	.minor		= -1,
 //	.release	= video_device_release,
+
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+	.vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+	.vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+#ifdef HAVE_V4L1
+	.vidiocgmbuf          = vidiocgmbuf,
+#endif
+	.tvnorms              = tvnorms,
+	.tvnormsize           = ARRAY_SIZE(tvnorms),
 };
-/* ------------------------------------------------------------------
+/* -----------------------------------------------------------------
 	Initialization and module stuff
    ------------------------------------------------------------------*/
 
@@ -1457,3 +1378,16 @@
 
 module_init(vivi_init);
 module_exit(vivi_exit);
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_param(video_nr, int, 0);
+
+module_param_named(debug,vivi.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 40b205b..1eca7e6 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -34,6 +34,7 @@
 #define I2C_NAME(x) (x)->name
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/video_decoder.h>
 
 #define I2C_VPX3220        0x86
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 80ef8a1..4bdc886 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -58,6 +58,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/parport.h>
 
 //#define DEBUG				// Undef me for production
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 115833e..a859a69 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,9 +1,9 @@
 config USB_ZC0301
-	tristate "USB ZC0301 Image Processor and Control Chip support"
+	tristate "USB ZC0301[P] Image Processor and Control Chip support"
 	depends on USB && VIDEO_V4L1
 	---help---
-	  Say Y here if you want support for cameras based on the ZC0301
-	  Image Processor and Control Chip.
+	  Say Y here if you want support for cameras based on the ZC0301 or
+	  ZC0301P Image Processors and Control Chips.
 
 	  See <file:Documentation/video4linux/zc0301.txt> for more info.
 
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
index d749199..d9e6d97 100644
--- a/drivers/media/video/zc0301/Makefile
+++ b/drivers/media/video/zc0301/Makefile
@@ -1,3 +1,3 @@
-zc0301-objs     := zc0301_core.o zc0301_pas202bcb.o
+zc0301-objs     := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
 
 obj-$(CONFIG_USB_ZC0301)        += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 0fad397..1b2be2d 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1,5 +1,5 @@
 /***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
+ * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip      *
  *                                                                         *
  * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
@@ -47,13 +47,13 @@
 
 /*****************************************************************************/
 
-#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
+#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
 			      "Image Processor and Control Chip"
 #define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
 #define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.03"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
+#define ZC0301_MODULE_VERSION "1:1.05"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 5)
 
 /*****************************************************************************/
 
@@ -427,10 +427,11 @@
 static int zc0301_start_transfer(struct zc0301_device* cam)
 {
 	struct usb_device *udev = cam->usbdev;
+	struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+						     usb_ifnum_to_if(udev, 0),
+						     ZC0301_ALTERNATE_SETTING);
+	const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
 	struct urb* urb;
-	const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
-					       512, 768, 1023};
-	const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
 	s8 i, j;
 	int err = 0;
 
@@ -1772,11 +1773,9 @@
 	case VIDIOC_G_CTRL:
 		return zc0301_vidioc_g_ctrl(cam, arg);
 
-	case VIDIOC_S_CTRL_OLD:
 	case VIDIOC_S_CTRL:
 		return zc0301_vidioc_s_ctrl(cam, arg);
 
-	case VIDIOC_CROPCAP_OLD:
 	case VIDIOC_CROPCAP:
 		return zc0301_vidioc_cropcap(cam, arg);
 
@@ -1823,7 +1822,6 @@
 	case VIDIOC_G_PARM:
 		return zc0301_vidioc_g_parm(cam, arg);
 
-	case VIDIOC_S_PARM_OLD:
 	case VIDIOC_S_PARM:
 		return zc0301_vidioc_s_parm(cam, arg);
 
@@ -1914,7 +1912,7 @@
 
 	mutex_init(&cam->dev_mutex);
 
-	DBG(2, "ZC0301 Image Processor and Control Chip detected "
+	DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
 	       "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
 
 	for  (i = 0; zc0301_sensor_table[i]; i++) {
@@ -1936,7 +1934,7 @@
 		cam->state |= DEV_MISCONFIGURED;
 	}
 
-	strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+	strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
 	cam->v4ldev->owner = THIS_MODULE;
 	cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
 	cam->v4ldev->hardware = 0;
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index eaadf02..ecfd39a 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -1,10 +1,10 @@
 /***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image     *
  * Processor and Control Chip                                              *
  *                                                                         *
  * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
  *                                                                         *
- * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
  * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
  *                                                                         *
  * This program is free software; you can redistribute it and/or modify    *
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
new file mode 100644
index 0000000..ed8542e
--- /dev/null
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image       *
+ * Processor and Control Chip                                              *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, 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/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pb0330;
+
+
+static int pb0330_init(struct zc0301_device* cam)
+{
+	int err = 0;
+
+	err += zc0301_write_reg(cam, 0x0000, 0x01);
+	err += zc0301_write_reg(cam, 0x0008, 0x03);
+	err += zc0301_write_reg(cam, 0x0010, 0x0A);
+	err += zc0301_write_reg(cam, 0x0002, 0x00);
+	err += zc0301_write_reg(cam, 0x0003, 0x02);
+	err += zc0301_write_reg(cam, 0x0004, 0x80);
+	err += zc0301_write_reg(cam, 0x0005, 0x01);
+	err += zc0301_write_reg(cam, 0x0006, 0xE0);
+	err += zc0301_write_reg(cam, 0x0001, 0x01);
+	err += zc0301_write_reg(cam, 0x0012, 0x05);
+	err += zc0301_write_reg(cam, 0x0012, 0x07);
+	err += zc0301_write_reg(cam, 0x0098, 0x00);
+	err += zc0301_write_reg(cam, 0x009A, 0x00);
+	err += zc0301_write_reg(cam, 0x011A, 0x00);
+	err += zc0301_write_reg(cam, 0x011C, 0x00);
+	err += zc0301_write_reg(cam, 0x0012, 0x05);
+
+	err += zc0301_i2c_write(cam, 0x01, 0x0006);
+	err += zc0301_i2c_write(cam, 0x02, 0x0011);
+	err += zc0301_i2c_write(cam, 0x03, 0x01E7);
+	err += zc0301_i2c_write(cam, 0x04, 0x0287);
+	err += zc0301_i2c_write(cam, 0x06, 0x0003);
+	err += zc0301_i2c_write(cam, 0x07, 0x3002);
+	err += zc0301_i2c_write(cam, 0x20, 0x1100);
+	err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
+	err += zc0301_i2c_write(cam, 0x30, 0x0005);
+	err += zc0301_i2c_write(cam, 0x31, 0x0000);
+	err += zc0301_i2c_write(cam, 0x34, 0x0100);
+	err += zc0301_i2c_write(cam, 0x35, 0x0060);
+	err += zc0301_i2c_write(cam, 0x3D, 0x068F);
+	err += zc0301_i2c_write(cam, 0x40, 0x01E0);
+	err += zc0301_i2c_write(cam, 0x58, 0x0078);
+	err += zc0301_i2c_write(cam, 0x62, 0x0411);
+
+	err += zc0301_write_reg(cam, 0x0087, 0x10);
+	err += zc0301_write_reg(cam, 0x0101, 0x37);
+	err += zc0301_write_reg(cam, 0x0012, 0x05);
+	err += zc0301_write_reg(cam, 0x0100, 0x0D);
+	err += zc0301_write_reg(cam, 0x0189, 0x06);
+	err += zc0301_write_reg(cam, 0x01AD, 0x00);
+	err += zc0301_write_reg(cam, 0x01C5, 0x03);
+	err += zc0301_write_reg(cam, 0x01CB, 0x13);
+	err += zc0301_write_reg(cam, 0x0250, 0x08);
+	err += zc0301_write_reg(cam, 0x0301, 0x08);
+	err += zc0301_write_reg(cam, 0x01A8, 0x60);
+	err += zc0301_write_reg(cam, 0x018D, 0x6C);
+	err += zc0301_write_reg(cam, 0x01AD, 0x09);
+	err += zc0301_write_reg(cam, 0x01AE, 0x15);
+	err += zc0301_write_reg(cam, 0x010A, 0x50);
+	err += zc0301_write_reg(cam, 0x010B, 0xF8);
+	err += zc0301_write_reg(cam, 0x010C, 0xF8);
+	err += zc0301_write_reg(cam, 0x010D, 0xF8);
+	err += zc0301_write_reg(cam, 0x010E, 0x50);
+	err += zc0301_write_reg(cam, 0x010F, 0xF8);
+	err += zc0301_write_reg(cam, 0x0110, 0xF8);
+	err += zc0301_write_reg(cam, 0x0111, 0xF8);
+	err += zc0301_write_reg(cam, 0x0112, 0x50);
+	err += zc0301_write_reg(cam, 0x0008, 0x03);
+	err += zc0301_write_reg(cam, 0x01C6, 0x08);
+	err += zc0301_write_reg(cam, 0x01CB, 0x0F);
+	err += zc0301_write_reg(cam, 0x010A, 0x50);
+	err += zc0301_write_reg(cam, 0x010B, 0xF8);
+	err += zc0301_write_reg(cam, 0x010C, 0xF8);
+	err += zc0301_write_reg(cam, 0x010D, 0xF8);
+	err += zc0301_write_reg(cam, 0x010E, 0x50);
+	err += zc0301_write_reg(cam, 0x010F, 0xF8);
+	err += zc0301_write_reg(cam, 0x0110, 0xF8);
+	err += zc0301_write_reg(cam, 0x0111, 0xF8);
+	err += zc0301_write_reg(cam, 0x0112, 0x50);
+	err += zc0301_write_reg(cam, 0x0180, 0x00);
+	err += zc0301_write_reg(cam, 0x0019, 0x00);
+
+	err += zc0301_i2c_write(cam, 0x05, 0x0066);
+	err += zc0301_i2c_write(cam, 0x09, 0x02B2);
+	err += zc0301_i2c_write(cam, 0x10, 0x0002);
+
+	err += zc0301_write_reg(cam, 0x011D, 0x60);
+	err += zc0301_write_reg(cam, 0x0190, 0x00);
+	err += zc0301_write_reg(cam, 0x0191, 0x07);
+	err += zc0301_write_reg(cam, 0x0192, 0x8C);
+	err += zc0301_write_reg(cam, 0x0195, 0x00);
+	err += zc0301_write_reg(cam, 0x0196, 0x00);
+	err += zc0301_write_reg(cam, 0x0197, 0x8A);
+	err += zc0301_write_reg(cam, 0x018C, 0x10);
+	err += zc0301_write_reg(cam, 0x018F, 0x20);
+	err += zc0301_write_reg(cam, 0x01A9, 0x14);
+	err += zc0301_write_reg(cam, 0x01AA, 0x24);
+	err += zc0301_write_reg(cam, 0x001D, 0xD7);
+	err += zc0301_write_reg(cam, 0x001E, 0xF0);
+	err += zc0301_write_reg(cam, 0x001F, 0xF8);
+	err += zc0301_write_reg(cam, 0x0020, 0xFF);
+	err += zc0301_write_reg(cam, 0x01AD, 0x09);
+	err += zc0301_write_reg(cam, 0x01AE, 0x15);
+	err += zc0301_write_reg(cam, 0x0180, 0x40);
+	err += zc0301_write_reg(cam, 0x0180, 0x42);
+
+	msleep(100);
+
+	return err;
+}
+
+
+static struct zc0301_sensor pb0330 = {
+	.name = "PB-0330",
+	.init = &pb0330_init,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_JPEG,
+		.priv = 8,
+	},
+};
+
+
+int zc0301_probe_pb0330(struct zc0301_device* cam)
+{
+	int r0, err = 0;
+
+	err += zc0301_write_reg(cam, 0x0000, 0x01);
+	err += zc0301_write_reg(cam, 0x0010, 0x0a);
+	err += zc0301_write_reg(cam, 0x0001, 0x01);
+	err += zc0301_write_reg(cam, 0x0012, 0x03);
+	err += zc0301_write_reg(cam, 0x0012, 0x01);
+
+	msleep(10);
+
+	r0 = zc0301_i2c_read(cam, 0x00, 2);
+
+	if (r0 < 0 || err)
+		return -EIO;
+
+	if (r0 != 0x8243)
+		return -ENODEV;
+
+	zc0301_attach_sensor(cam, &pb0330);
+
+	return 0;
+}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 1f95c28..4363a91 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -1,5 +1,5 @@
 /***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and       *
+ * API for image sensors connected to the ZC0301 Image Processor and       *
  * Control Chip                                                            *
  *                                                                         *
  * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
@@ -35,11 +35,13 @@
 /*****************************************************************************/
 
 extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+extern int zc0301_probe_pb0330(struct zc0301_device* cam);
 
 #define ZC0301_SENSOR_TABLE                                                   \
 /* Weak detections must go at the end of the list */                          \
 static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
 	&zc0301_probe_pas202bcb,                                              \
+	&zc0301_probe_pb0330,                                                 \
 	NULL,                                                                 \
 };
 
@@ -58,14 +60,28 @@
 
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
-	{ ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
+	{ ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */            \
 	{ ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
-	{ ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
+	{ ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */            \
+	{ ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), },                         \
 	{ ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
 	{ ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
-	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+	{ ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */            \
+	{ ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */            \
+	{ ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
+	{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
-	{ ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+	{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
+	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
+	{ ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */           \
+	{ ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */           \
 	{ }                                                                   \
 };
 
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 0166f55..ffcda95 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -159,7 +159,7 @@
 #define BUZ_MAX_FRAME     256	/* Must be a power of 2 */
 #define BUZ_MASK_FRAME    255	/* Must be BUZ_MAX_FRAME-1 */
 
-#define BUZ_MAX_INPUT       8
+#define BUZ_MAX_INPUT       16
 
 #if VIDEO_MAX_FRAME <= 32
 #   define   V4L_MAX_FRAME   32
@@ -191,6 +191,9 @@
 	/* Iomega */
 	BUZ,
 
+	/* AverMedia */
+	AVS6EYES,
+
 	/* total number of cards */
 	NUM_CARDS
 };
@@ -379,6 +382,9 @@
 	/* is the /GWS line conected? */
 	u8 gws_not_connected;
 
+	/* avs6eyes mux setting */
+	u8 input_mux;
+
 	void (*init) (struct zoran * zr);
 };
 
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 0a85c9e..958c1e6 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -27,6 +27,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/delay.h>
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -38,6 +40,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/spinlock.h>
 #include <linux/sem.h>
 #include <linux/kmod.h>
@@ -93,6 +96,11 @@
 MODULE_PARM_DESC(default_input,
 		 "Default input (0=Composite, 1=S-Video, 2=Internal)");
 
+static int default_mux = 1;	/* 6 Eyes input selection */
+module_param(default_mux, int, 0);
+MODULE_PARM_DESC(default_mux,
+		 "Default 6 Eyes mux setting (Input selection)");
+
 static int default_norm = 0;	/* 0=PAL, 1=NTSC 2=SECAM */
 module_param(default_norm, int, 0);
 MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
@@ -301,6 +309,30 @@
 	GPIO(zr, 2, 1);		// Set Composite input/output
 }
 
+static void
+avs6eyes_init (struct zoran *zr)
+{
+	// AverMedia 6-Eyes original driver by Christer Weinigel
+
+	// Lifted straight from Christer's old driver and
+	// modified slightly by Martin Samuelsson.
+
+	int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+	GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+	udelay(2);
+
+	GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+	GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+	GPIO(zr, 2, mux & 1);   /* MUX S0 */
+	GPIO(zr, 3, 0); /* /FRAME on */
+	GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+	GPIO(zr, 5, mux & 2);   /* MUX S1 */
+	GPIO(zr, 6, 0); /* ? */
+	GPIO(zr, 7, mux & 4);   /* MUX S2 */
+
+}
+
 static char *
 i2cid_to_modulename (u16 i2c_id)
 {
@@ -391,6 +423,14 @@
 static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
 static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
 
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam  */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
 static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
 	{
 		.type = DC10_old,
@@ -419,6 +459,7 @@
 		.gpcs = { -1, 0 },
 		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
 		.gws_not_connected = 0,
+		.input_mux = 0,
 		.init = &dc10_init,
 	}, {
 		.type = DC10_new,
@@ -445,6 +486,7 @@
 		.gpcs = { -1, 1},
 		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
 		.gws_not_connected = 0,
+		.input_mux = 0,
 		.init = &dc10plus_init,
 	}, {
 		.type = DC10plus,
@@ -474,6 +516,7 @@
 		.gpcs = { -1, 1 },
 		.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
 		.gws_not_connected = 0,
+		.input_mux = 0,
 		.init = &dc10plus_init,
 	}, {
 		.type = DC30,
@@ -502,6 +545,7 @@
 		.gpcs = { -1, 0 },
 		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
 		.gws_not_connected = 0,
+		.input_mux = 0,
 		.init = &dc10_init,
 	}, {
 		.type = DC30plus,
@@ -532,6 +576,7 @@
 		.gpcs = { -1, 0 },
 		.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
 		.gws_not_connected = 0,
+		.input_mux = 0,
 		.init = &dc10_init,
 	}, {
 		.type = LML33,
@@ -558,6 +603,7 @@
 		.gpcs = { 3, 1 },
 		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
 		.gws_not_connected = 1,
+		.input_mux = 0,
 		.init = &lml33_init,
 	}, {
 		.type = LML33R10,
@@ -586,6 +632,7 @@
 		.gpcs = { 3, 1 },
 		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
 		.gws_not_connected = 1,
+		.input_mux = 0,
 		.init = &lml33_init,
 	}, {
 		.type = BUZ,
@@ -614,8 +661,49 @@
 		.gpcs = { 3, 1 },
 		.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
 		.gws_not_connected = 1,
+		.input_mux = 0,
 		.init = &buz_init,
+	}, {
+		.type = AVS6EYES,
+		.name = "6-Eyes",
+		/* AverMedia chose not to brand the 6-Eyes. Thus it
+		   can't be autodetected, and requires card=x. */
+		.vendor_id = -1,
+		.device_id = -1,
+		.i2c_decoder = I2C_DRIVERID_KS0127,
+		.i2c_encoder = I2C_DRIVERID_BT866,
+		.video_codec = CODEC_TYPE_ZR36060,
+
+		.inputs = 10,
+		.input = {
+			{ 0, "Composite 1" },
+			{ 1, "Composite 2" },
+			{ 2, "Composite 3" },
+			{ 4, "Composite 4" },
+			{ 5, "Composite 5" },
+			{ 6, "Composite 6" },
+			{ 8, "S-Video 1" },
+			{ 9, "S-Video 2" },
+			{10, "S-Video 3" },
+			{15, "YCbCr" }
+		},
+		.norms = 2,
+		.tvn = {
+			&f50ccir601_avs6eyes,
+			&f60ccir601_avs6eyes,
+			NULL
+		},
+		.jpeg_int = ZR36057_ISR_GIRQ1,
+		.vsync_int = ZR36057_ISR_GIRQ0,
+		.gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+		.gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+		.gpcs = { 3, 1 },			// Validity unknown /Sam
+		.vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 },  // Validity unknown /Sam
+		.gws_not_connected = 1,
+		.input_mux = 1,
+		.init = &avs6eyes_init,
 	}
+
 };
 
 /*
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index c690b2e..02168d9 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -536,7 +536,7 @@
 		 * All error messages are internal driver checking only! */
 
 		/* video display top and bottom registers */
-		reg = (u32) zr->buffer.base +
+		reg = (long) zr->buffer.base +
 		    zr->overlay_settings.x *
 		    ((zr->overlay_settings.format->depth + 7) / 8) +
 		    zr->overlay_settings.y *
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index b5a576a..9711f62 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -73,6 +73,7 @@
 			     )
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include "videocodec.h"
 
 #include <asm/io.h>
@@ -2047,7 +2048,7 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
 
 		memset(vcap, 0, sizeof(struct video_capability));
-		strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name));
+		strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
 		vcap->type = ZORAN_VID_TYPE;
 
 		vcap->channels = zr->card.inputs;
@@ -2689,8 +2690,8 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
 
 		memset(cap, 0, sizeof(*cap));
-		strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
-		strncpy(cap->driver, "zoran", sizeof(cap->driver));
+		strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+		strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
 		snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
 			 pci_name(zr->pci_dev));
 		cap->version =
@@ -2742,7 +2743,7 @@
 		memset(fmt, 0, sizeof(*fmt));
 		fmt->index = index;
 		fmt->type = type;
-		strncpy(fmt->description, zoran_formats[i].name, 31);
+		strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
 		fmt->pixelformat = zoran_formats[i].fourcc;
 		if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
 			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -3566,16 +3567,16 @@
 
 		switch (ctrl->id) {
 		case V4L2_CID_BRIGHTNESS:
-			strncpy(ctrl->name, "Brightness", 31);
+			strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
 			break;
 		case V4L2_CID_CONTRAST:
-			strncpy(ctrl->name, "Contrast", 31);
+			strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
 			break;
 		case V4L2_CID_SATURATION:
-			strncpy(ctrl->name, "Saturation", 31);
+			strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
 			break;
 		case V4L2_CID_HUE:
-			strncpy(ctrl->name, "Hue", 31);
+			strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
 			break;
 		}
 
@@ -3693,7 +3694,7 @@
 					&caps);
 			if (caps.flags & VIDEO_DECODER_AUTO) {
 				std->id = V4L2_STD_ALL;
-				strncpy(std->name, "Autodetect", 31);
+				strncpy(std->name, "Autodetect", sizeof(std->name)-1);
 				return 0;
 			} else
 				return -EINVAL;
@@ -3701,21 +3702,21 @@
 		switch (std->index) {
 		case 0:
 			std->id = V4L2_STD_PAL;
-			strncpy(std->name, "PAL", 31);
+			strncpy(std->name, "PAL", sizeof(std->name)-1);
 			std->frameperiod.numerator = 1;
 			std->frameperiod.denominator = 25;
 			std->framelines = zr->card.tvn[0]->Ht;
 			break;
 		case 1:
 			std->id = V4L2_STD_NTSC;
-			strncpy(std->name, "NTSC", 31);
+			strncpy(std->name, "NTSC", sizeof(std->name)-1);
 			std->frameperiod.numerator = 1001;
 			std->frameperiod.denominator = 30000;
 			std->framelines = zr->card.tvn[1]->Ht;
 			break;
 		case 2:
 			std->id = V4L2_STD_SECAM;
-			strncpy(std->name, "SECAM", 31);
+			strncpy(std->name, "SECAM", sizeof(std->name)-1);
 			std->frameperiod.numerator = 1;
 			std->frameperiod.denominator = 25;
 			std->framelines = zr->card.tvn[2]->Ht;
@@ -3871,7 +3872,7 @@
 		memset(outp, 0, sizeof(*outp));
 		outp->index = 0;
 		outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
-		strncpy(outp->name, "Autodetect", 31);
+		strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
 
 		return 0;
 	}
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index a00fae9..f4ffe79 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -43,6 +43,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/ctype.h>
+#include <linux/poll.h>
 #include <asm/io.h>
 
 #include "videocodec.h"
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 5ac265d..1344ad7 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -86,14 +86,14 @@
 	  block and "-2" means the penultimate block.
 
 config MTD_REDBOOT_PARTS_UNALLOCATED
-	bool "  Include unallocated flash regions"
+	bool "Include unallocated flash regions"
 	depends on MTD_REDBOOT_PARTS
 	help
 	  If you need to register each unallocated flash region as a MTD
 	  'partition', enable this option.
 
 config MTD_REDBOOT_PARTS_READONLY
-	bool "  Force read-only for RedBoot system images"
+	bool "Force read-only for RedBoot system images"
 	depends on MTD_REDBOOT_PARTS
 	help
 	  If you need to force read-only for 'RedBoot', 'RedBoot Config' and
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 6bdaacc..83d0b2a 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -212,7 +212,7 @@
 	  Support for flash chips on NETtel/SecureEdge/SnapGear boards.
 
 config MTD_ALCHEMY
-	tristate '  AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support'
+	tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support"
 	depends on SOC_AU1X00
 	help
 	  Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 0758cb1..24a0315 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -18,6 +18,7 @@
 #include <linux/ioport.h>
 #include <asm/ebus.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -30,146 +31,140 @@
 #define UFLASH_WINDOW_SIZE	0x200000
 #define UFLASH_BUSWIDTH		1			/* EBus is 8-bit */
 
-MODULE_AUTHOR
-	("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-	("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE
-	("userflash");
-MODULE_LICENSE
-	("GPL");
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
+MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0");
 
 static LIST_HEAD(device_list);
 struct uflash_dev {
-	char *			name;	/* device name */
+	char			*name;	/* device name */
 	struct map_info 	map;	/* mtd map info */
-	struct mtd_info *	mtd;	/* mtd info */
-	struct list_head	list;
+	struct mtd_info		*mtd;	/* mtd info */
 };
 
 
 struct map_info uflash_map_templ = {
-		.name =		"SUNW,???-????",
-		.size =		UFLASH_WINDOW_SIZE,
-		.bankwidth =	UFLASH_BUSWIDTH,
+	.name =		"SUNW,???-????",
+	.size =		UFLASH_WINDOW_SIZE,
+	.bankwidth =	UFLASH_BUSWIDTH,
 };
 
-int uflash_devinit(struct linux_ebus_device* edev)
+int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
 {
-	int iTmp, nregs;
-	struct linux_prom_registers regs[2];
-	struct uflash_dev *pdev;
+	struct uflash_dev *up;
+	struct resource *res;
 
-	iTmp = prom_getproperty(
-		edev->prom_node, "reg", (void *)regs, sizeof(regs));
-	if ((iTmp % sizeof(regs[0])) != 0) {
-		printk("%s: Strange reg property size %d\n",
-			UFLASH_DEVNAME, iTmp);
-		return -ENODEV;
-	}
+	res = &edev->resource[0];
 
-	nregs = iTmp / sizeof(regs[0]);
-
-	if (nregs != 1) {
+	if (edev->num_addrs != 1) {
 		/* Non-CFI userflash device-- once I find one we
 		 * can work on supporting it.
 		 */
 		printk("%s: unsupported device at 0x%lx (%d regs): " \
 			"email ebrower@usa.net\n",
-			UFLASH_DEVNAME, edev->resource[0].start, nregs);
+		       dp->full_name, res->start, edev->num_addrs);
+
 		return -ENODEV;
 	}
 
-	if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) {
-		printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
-		return(-ENOMEM);
-	}
+	up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
+	if (!up)
+		return -ENOMEM;
 
 	/* copy defaults and tweak parameters */
-	memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
-	pdev->map.size = regs[0].reg_size;
+	memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
+	up->map.size = (res->end - res->start) + 1UL;
 
-	iTmp = prom_getproplen(edev->prom_node, "model");
-	pdev->name = kmalloc(iTmp, GFP_KERNEL);
-	prom_getstring(edev->prom_node, "model", pdev->name, iTmp);
-	if(0 != pdev->name && 0 < strlen(pdev->name)) {
-		pdev->map.name = pdev->name;
-	}
-	pdev->map.phys = edev->resource[0].start;
-	pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size);
-	if(0 == pdev->map.virt) {
-		printk("%s: failed to map device\n", __FUNCTION__);
-		kfree(pdev->name);
-		kfree(pdev);
-		return(-1);
+	up->name = of_get_property(dp, "model", NULL);
+	if (up->name && 0 < strlen(up->name))
+		up->map.name = up->name;
+
+	up->map.phys = res->start;
+
+	up->map.virt = ioremap_nocache(res->start, up->map.size);
+	if (!up->map.virt) {
+		printk("%s: Failed to map device.\n", dp->full_name);
+		kfree(up);
+
+		return -EINVAL;
 	}
 
-	simple_map_init(&pdev->map);
+	simple_map_init(&up->map);
 
 	/* MTD registration */
-	pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
-	if(0 == pdev->mtd) {
-		iounmap(pdev->map.virt);
-		kfree(pdev->name);
-		kfree(pdev);
-		return(-ENXIO);
+	up->mtd = do_map_probe("cfi_probe", &up->map);
+	if (!up->mtd) {
+		iounmap(up->map.virt);
+		kfree(up);
+
+		return -ENXIO;
 	}
 
-	list_add(&pdev->list, &device_list);
+	up->mtd->owner = THIS_MODULE;
 
-	pdev->mtd->owner = THIS_MODULE;
+	add_mtd_device(up->mtd);
 
-	add_mtd_device(pdev->mtd);
-	return(0);
+	dev_set_drvdata(&edev->ofdev.dev, up);
+
+	return 0;
 }
 
+static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
+{
+	struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
+	struct device_node *dp = dev->node;
+
+	if (of_find_property(dp, "user", NULL))
+		return -ENODEV;
+
+	return uflash_devinit(edev, dp);
+}
+
+static int __devexit uflash_remove(struct of_device *dev)
+{
+	struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+
+	if (up->mtd) {
+		del_mtd_device(up->mtd);
+		map_destroy(up->mtd);
+	}
+	if (up->map.virt) {
+		iounmap(up->map.virt);
+		up->map.virt = NULL;
+	}
+
+	kfree(up);
+
+	return 0;
+}
+
+static struct of_device_id uflash_match[] = {
+	{
+		.name = UFLASH_OBPNAME,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, uflash_match);
+
+static struct of_platform_driver uflash_driver = {
+	.name		= UFLASH_DEVNAME,
+	.match_table	= uflash_match,
+	.probe		= uflash_probe,
+	.remove		= __devexit_p(uflash_remove),
+};
+
 static int __init uflash_init(void)
 {
-	struct linux_ebus *ebus = NULL;
-	struct linux_ebus_device *edev = NULL;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) {
-				if(0 > prom_getproplen(edev->prom_node, "user")) {
-					DEBUG(2, "%s: ignoring device at 0x%lx\n",
-							UFLASH_DEVNAME, edev->resource[0].start);
-				} else {
-					uflash_devinit(edev);
-				}
-			}
-		}
-	}
-
-	if(list_empty(&device_list)) {
-		printk("%s: unable to locate device\n", UFLASH_DEVNAME);
-		return -ENODEV;
-	}
-	return(0);
+	return of_register_driver(&uflash_driver, &ebus_bus_type);
 }
 
-static void __exit uflash_cleanup(void)
+static void __exit uflash_exit(void)
 {
-	struct list_head *udevlist;
-	struct uflash_dev *udev;
-
-	list_for_each(udevlist, &device_list) {
-		udev = list_entry(udevlist, struct uflash_dev, list);
-		DEBUG(2, "%s: removing device %s\n",
-			UFLASH_DEVNAME, udev->name);
-
-		if(0 != udev->mtd) {
-			del_mtd_device(udev->mtd);
-			map_destroy(udev->mtd);
-		}
-		if(0 != udev->map.virt) {
-			iounmap(udev->map.virt);
-			udev->map.virt = NULL;
-		}
-		kfree(udev->name);
-		kfree(udev);
-	}
+	of_unregister_driver(&uflash_driver);
 }
 
 module_init(uflash_init);
-module_exit(uflash_cleanup);
+module_exit(uflash_exit);
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index bb44509..07136ec 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -508,11 +508,11 @@
  * speak of. We simply pull the packet out of its PIO buffer (which is slow)
  * and queue it for the kernel. Then we reset the card for the next packet.
  *
- * We sometimes get suprise interrupts late both because the SMP IRQ delivery
+ * We sometimes get surprise interrupts late both because the SMP IRQ delivery
  * is message passing and because the card sometimes seems to deliver late. I
  * think if it is part way through a receive and the mode is changed it carries
  * on receiving and sends us an interrupt. We have to band aid all these cases
- * to get a sensible 150kbytes/second performance. Even then you want a small
+ * to get a sensible 150kBytes/second performance. Even then you want a small
  * TCP window.
  */
 
diff --git a/drivers/net/fec.h b/drivers/net/fec.h
index 965c5c4..1d42160 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/fec.h
@@ -14,7 +14,7 @@
 /****************************************************************************/
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x)
+    defined(CONFIG_M520x) || defined(CONFIG_M532x)
 /*
  *	Just figures, Motorola would have to change the offsets for
  *	registers in the same peripheral device on different models
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 844fa74..2a0d538 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1105,7 +1105,7 @@
                 return ret;
 
         /* We get a patch from userspace */
-        IRDA_MESSAGE("%s(): Received firmware %s (%u bytes)\n",
+        IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n",
                      __FUNCTION__, stir421x_fw_name, fw->size);
 
         ret = -EINVAL;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 98fa531..44efd49 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -386,7 +386,7 @@
 	/* Locking notes : this function may be called from irq context with
 	 * spinlock, via irport_write_wakeup(), or from non-interrupt without
 	 * spinlock (from the task timer). Yuck !
-	 * This is ugly, and unsafe is the spinlock is not already aquired.
+	 * This is ugly, and unsafe is the spinlock is not already acquired.
 	 * This will be fixed when irda-task get rewritten.
 	 * Jean II */
 	if (!spin_is_locked(&self->lock)) {
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index cc7ff8f..cb62f2a 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -115,8 +115,12 @@
 	/* Contributed by Jan Frey - IBM A30/A31 */
 	{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, 
 	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
-	{ "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
- 	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
+	/* IBM ThinkPads using PC8738x (T60/X60/Z60) */
+	{ "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
+	/* IBM ThinkPads using PC8394T (T43/R52/?) */
+	{ "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
+	  nsc_ircc_probe_39x, nsc_ircc_init_39x },
 	{ NULL }
 };
 
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index e74bf50..a73d545 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1883,7 +1883,7 @@
     /* Set the Window 1 control, configuration and station addr registers.
        No point in writing the I/O base register ;-> */
     SMC_SELECT_BANK(1);
-    /* Automatically release succesfully transmitted packets,
+    /* Automatically release successfully transmitted packets,
        Accept link errors, counter and Tx error interrupts. */
     outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
 	 ioaddr + CONTROL);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 01cd8ec..d643a09 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2578,8 +2578,7 @@
 
 	list_for_each_entry(pch, &new_channels, list) {
 		if (pch->file.index == unit) {
-			list_del(&pch->list);
-			list_add(&pch->list, &all_channels);
+			list_move(&pch->list, &all_channels);
 			return pch;
 		}
 	}
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index d4c0002..a2fad50 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -55,7 +55,7 @@
 /* sun3/60 addr/irq for the lance chip.  If your sun is different,
    change this. */
 #define LANCE_OBIO 0x120000
-#define LANCE_IRQ IRQ3
+#define LANCE_IRQ IRQ_AUTO_3
 
 /* Debug level:
  *  0 = silent, print only serious errors
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 22e7940..7628c2d 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -60,9 +60,9 @@
 
 static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
 
-static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
+static unsigned int valid_port[] = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
 
-static unsigned int valid_mem[]  __initdata = {
+static unsigned int valid_mem[] = {
 				    0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, 
                                     0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
                                     0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
index 25ea474..533993f 100644
--- a/drivers/net/wireless/bcm43xx/Kconfig
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -2,6 +2,7 @@
 	tristate "Broadcom BCM43xx wireless support"
 	depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
 	select FW_LOADER
+	select HW_RANDOM
 	---help---
 	  This is an experimental driver for the Broadcom 43xx wireless chip,
 	  found in the Apple Airport Extreme and various other devices.
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index d8f917c..17a5682 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -1,6 +1,7 @@
 #ifndef BCM43xx_H_
 #define BCM43xx_H_
 
+#include <linux/hw_random.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
@@ -82,6 +83,7 @@
 #define BCM43xx_MMIO_TSF_1		0x634 /* core rev < 3 only */
 #define BCM43xx_MMIO_TSF_2		0x636 /* core rev < 3 only */
 #define BCM43xx_MMIO_TSF_3		0x638 /* core rev < 3 only */
+#define BCM43xx_MMIO_RNG		0x65A
 #define BCM43xx_MMIO_POWERUP_DELAY	0x6A8
 
 /* SPROM offsets. */
@@ -750,6 +752,10 @@
 	const struct firmware *initvals0;
 	const struct firmware *initvals1;
 
+	/* Random Number Generator. */
+	struct hwrng rng;
+	char rng_name[20 + 1];
+
 	/* Debugging stuff follows. */
 #ifdef CONFIG_BCM43XX_DEBUG
 	struct bcm43xx_dfsentry *dfsentry;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 085d785..27bcf47 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3237,6 +3237,39 @@
 	bcm43xx_clear_keys(bcm);
 }
 
+static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
+{
+	struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
+	unsigned long flags;
+
+	bcm43xx_lock_irqonly(bcm, flags);
+	*data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
+	bcm43xx_unlock_irqonly(bcm, flags);
+
+	return (sizeof(u16));
+}
+
+static void bcm43xx_rng_exit(struct bcm43xx_private *bcm)
+{
+	hwrng_unregister(&bcm->rng);
+}
+
+static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	snprintf(bcm->rng_name, ARRAY_SIZE(bcm->rng_name),
+		 "%s_%s", KBUILD_MODNAME, bcm->net_dev->name);
+	bcm->rng.name = bcm->rng_name;
+	bcm->rng.data_read = bcm43xx_rng_read;
+	bcm->rng.priv = (unsigned long)bcm;
+	err = hwrng_register(&bcm->rng);
+	if (err)
+		printk(KERN_ERR PFX "RNG init failed (%d)\n", err);
+
+	return err;
+}
+
 /* This is the opposite of bcm43xx_init_board() */
 static void bcm43xx_free_board(struct bcm43xx_private *bcm)
 {
@@ -3248,6 +3281,7 @@
 
 	bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
 
+	bcm43xx_rng_exit(bcm);
 	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
 		if (!bcm->core_80211[i].available)
 			continue;
@@ -3325,6 +3359,9 @@
 		bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
 		bcm43xx_mac_enable(bcm);
 	}
+	err = bcm43xx_rng_init(bcm);
+	if (err)
+		goto err_80211_unwind;
 	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
 	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
 	dprintk(KERN_INFO PFX "80211 cores initialized\n");
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 72335c8..94aeb23 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -1485,7 +1485,7 @@
 		 *
 		 * Sending the PREPARE_FOR_POWER_DOWN will restrict the
 		 * hardware from going into standby mode and will transition
-		 * out of D0-standy if it is already in that state.
+		 * out of D0-standby if it is already in that state.
 		 *
 		 * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
 		 * driver upon completion.  Once received, the driver can
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index b2e8e49..43e521e 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -108,10 +108,10 @@
 		return 0;
 
 	/* FIXME: should we process all CPU buffers ? */
-	down(&buffer_sem);
+	mutex_lock(&buffer_mutex);
 	add_event_entry(ESCAPE_CODE);
 	add_event_entry(MODULE_LOADED_CODE);
-	up(&buffer_sem);
+	mutex_unlock(&buffer_mutex);
 #endif
 	return 0;
 }
@@ -501,7 +501,7 @@
 	sync_buffer_state state = sb_buffer_start;
 	unsigned long available;
 
-	down(&buffer_sem);
+	mutex_lock(&buffer_mutex);
  
 	add_cpu_switch(cpu);
 
@@ -550,5 +550,5 @@
 
 	mark_done(cpu);
 
-	up(&buffer_sem);
+	mutex_unlock(&buffer_mutex);
 }
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index b80318f..04d6417 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -24,7 +24,7 @@
 #include "event_buffer.h"
 #include "oprofile_stats.h"
 
-DECLARE_MUTEX(buffer_sem);
+DEFINE_MUTEX(buffer_mutex);
  
 static unsigned long buffer_opened;
 static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
@@ -32,7 +32,7 @@
 static unsigned long buffer_size;
 static unsigned long buffer_watershed;
 static size_t buffer_pos;
-/* atomic_t because wait_event checks it outside of buffer_sem */
+/* atomic_t because wait_event checks it outside of buffer_mutex */
 static atomic_t buffer_ready = ATOMIC_INIT(0);
 
 /* Add an entry to the event buffer. When we
@@ -60,10 +60,10 @@
  */
 void wake_up_buffer_waiter(void)
 {
-	down(&buffer_sem);
+	mutex_lock(&buffer_mutex);
 	atomic_set(&buffer_ready, 1);
 	wake_up(&buffer_wait);
-	up(&buffer_sem);
+	mutex_unlock(&buffer_mutex);
 }
 
  
@@ -162,7 +162,7 @@
 	if (!atomic_read(&buffer_ready))
 		return -EAGAIN;
 
-	down(&buffer_sem);
+	mutex_lock(&buffer_mutex);
 
 	atomic_set(&buffer_ready, 0);
 
@@ -177,7 +177,7 @@
 	buffer_pos = 0;
  
 out:
-	up(&buffer_sem);
+	mutex_unlock(&buffer_mutex);
 	return retval;
 }
  
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 0180236..9241627 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -11,7 +11,7 @@
 #define EVENT_BUFFER_H
 
 #include <linux/types.h> 
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
  
 int alloc_event_buffer(void);
 
@@ -46,6 +46,6 @@
 /* mutex between sync_cpu_buffers() and the
  * file reading code.
  */
-extern struct semaphore buffer_sem;
+extern struct mutex buffer_mutex;
  
 #endif /* EVENT_BUFFER_H */
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index b3f1cd6..e5162a6 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/oprofile.h>
 #include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
 
 #include "oprof.h"
 #include "event_buffer.h"
@@ -25,7 +25,7 @@
 unsigned long oprofile_started;
 unsigned long backtrace_depth;
 static unsigned long is_setup;
-static DECLARE_MUTEX(start_sem);
+static DEFINE_MUTEX(start_mutex);
 
 /* timer
    0 - use performance monitoring hardware if available
@@ -37,7 +37,7 @@
 {
 	int err;
  
-	down(&start_sem);
+	mutex_lock(&start_mutex);
 
 	if ((err = alloc_cpu_buffers()))
 		goto out;
@@ -57,7 +57,7 @@
 		goto out3;
 
 	is_setup = 1;
-	up(&start_sem);
+	mutex_unlock(&start_mutex);
 	return 0;
  
 out3:
@@ -68,7 +68,7 @@
 out1:
 	free_cpu_buffers();
 out:
-	up(&start_sem);
+	mutex_unlock(&start_mutex);
 	return err;
 }
 
@@ -78,7 +78,7 @@
 {
 	int err = -EINVAL;
  
-	down(&start_sem);
+	mutex_lock(&start_mutex);
  
 	if (!is_setup)
 		goto out;
@@ -95,7 +95,7 @@
 
 	oprofile_started = 1;
 out:
-	up(&start_sem); 
+	mutex_unlock(&start_mutex);
 	return err;
 }
 
@@ -103,7 +103,7 @@
 /* echo 0>/dev/oprofile/enable */
 void oprofile_stop(void)
 {
-	down(&start_sem);
+	mutex_lock(&start_mutex);
 	if (!oprofile_started)
 		goto out;
 	oprofile_ops.stop();
@@ -111,20 +111,20 @@
 	/* wake up the daemon to read what remains */
 	wake_up_buffer_waiter();
 out:
-	up(&start_sem);
+	mutex_unlock(&start_mutex);
 }
 
 
 void oprofile_shutdown(void)
 {
-	down(&start_sem);
+	mutex_lock(&start_mutex);
 	sync_stop();
 	if (oprofile_ops.shutdown)
 		oprofile_ops.shutdown();
 	is_setup = 0;
 	free_event_buffer();
 	free_cpu_buffers();
-	up(&start_sem);
+	mutex_unlock(&start_mutex);
 }
 
 
@@ -132,7 +132,7 @@
 {
 	int err = 0;
 
-	down(&start_sem);
+	mutex_lock(&start_mutex);
 
 	if (oprofile_started) {
 		err = -EBUSY;
@@ -147,7 +147,7 @@
 	backtrace_depth = val;
 
 out:
-	up(&start_sem);
+	mutex_unlock(&start_mutex);
 	return err;
 }
 
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 4d8dc27..c7fa28a 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -136,6 +136,18 @@
 	  found on many Sun machines. Note that many of the newer Ultras
 	  actually have pc style hardware instead.
 
+config PARPORT_AX88796
+	tristate "AX88796 Parallel Port"
+	depends on PARPORT
+	select PARPORT_NOT_PC
+	help
+	  Say Y here if you need support for the parallel port hardware on
+	  the AX88796 network controller chip. This code is also available
+	  as a module (say M), called parport_ax88796.
+
+	  The driver is not dependant on the AX88796 network driver, and
+	  should not interfere with the networking functions of the chip.
+
 config PARPORT_1284
 	bool "IEEE 1284 transfer modes"
 	depends on PARPORT
diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile
index a19de35..696b8d4 100644
--- a/drivers/parport/Makefile
+++ b/drivers/parport/Makefile
@@ -17,4 +17,5 @@
 obj-$(CONFIG_PARPORT_ATARI)	+= parport_atari.o
 obj-$(CONFIG_PARPORT_SUNBPP)	+= parport_sunbpp.o
 obj-$(CONFIG_PARPORT_GSC)	+= parport_gsc.o
-obj-$(CONFIG_PARPORT_IP32)	+= parport_ip32.o
+obj-$(CONFIG_PARPORT_AX88796)	+= parport_ax88796.o
+obj-$(CONFIG_PARPORT_IP32)	+= parport_ip32.o
\ No newline at end of file
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index 9ee6732..fd41e28 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -283,7 +283,7 @@
  *
  *	This tries to locate a device on the given parallel port,
  *	multiplexor port and daisy chain address, and returns its
- *	device number or -NXIO if no device with those coordinates
+ *	device number or %-ENXIO if no device with those coordinates
  *	exists.
  **/
 
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
new file mode 100644
index 0000000..4baa719
--- /dev/null
+++ b/drivers/parport/parport_ax88796.c
@@ -0,0 +1,443 @@
+/* linux/drivers/parport/parport_ax88796.c
+ *
+ * (c) 2005,2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define AX_SPR_BUSY		(1<<7)
+#define AX_SPR_ACK		(1<<6)
+#define AX_SPR_PE		(1<<5)
+#define AX_SPR_SLCT		(1<<4)
+#define AX_SPR_ERR		(1<<3)
+
+#define AX_CPR_nDOE		(1<<5)
+#define AX_CPR_SLCTIN		(1<<3)
+#define AX_CPR_nINIT		(1<<2)
+#define AX_CPR_ATFD		(1<<1)
+#define AX_CPR_STRB		(1<<0)
+
+struct ax_drvdata {
+	struct parport		*parport;
+	struct parport_state	 suspend;
+
+	struct device		*dev;
+	struct resource		*io;
+
+	unsigned char		 irq_enabled;
+
+	void __iomem		*base;
+	void __iomem		*spp_data;
+	void __iomem		*spp_spr;
+	void __iomem		*spp_cpr;
+};
+
+static inline struct ax_drvdata *pp_to_drv(struct parport *p)
+{
+	return p->private_data;
+}
+
+static unsigned char
+parport_ax88796_read_data(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	return readb(dd->spp_data);
+}
+
+static void
+parport_ax88796_write_data(struct parport *p, unsigned char data)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	writeb(data, dd->spp_data);
+}
+
+static unsigned char
+parport_ax88796_read_control(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	unsigned int cpr = readb(dd->spp_cpr);
+	unsigned int ret = 0;
+
+	if (!(cpr & AX_CPR_STRB))
+		ret |= PARPORT_CONTROL_STROBE;
+
+	if (!(cpr & AX_CPR_ATFD))
+		ret |= PARPORT_CONTROL_AUTOFD;
+
+	if (cpr & AX_CPR_nINIT)
+		ret |= PARPORT_CONTROL_INIT;
+
+	if (!(cpr & AX_CPR_SLCTIN))
+		ret |= PARPORT_CONTROL_SELECT;
+
+	return ret;
+}
+
+static void
+parport_ax88796_write_control(struct parport *p, unsigned char control)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	unsigned int cpr = readb(dd->spp_cpr);
+
+	cpr &= AX_CPR_nDOE;
+
+	if (!(control & PARPORT_CONTROL_STROBE))
+		cpr |= AX_CPR_STRB;
+
+	if (!(control & PARPORT_CONTROL_AUTOFD))
+		cpr |= AX_CPR_ATFD;
+
+	if (control & PARPORT_CONTROL_INIT)
+		cpr |= AX_CPR_nINIT;
+
+	if (!(control & PARPORT_CONTROL_SELECT))
+		cpr |= AX_CPR_SLCTIN;
+
+	dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr);
+	writeb(cpr, dd->spp_cpr);
+
+	if (parport_ax88796_read_control(p) != control) {
+		dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n",
+			parport_ax88796_read_control(p), control);
+	}
+}
+
+static unsigned char
+parport_ax88796_read_status(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	unsigned int status = readb(dd->spp_spr);
+	unsigned int ret = 0;
+
+	if (status & AX_SPR_BUSY)
+		ret |= PARPORT_STATUS_BUSY;
+
+	if (status & AX_SPR_ACK)
+		ret |= PARPORT_STATUS_ACK;
+
+	if (status & AX_SPR_ERR)
+		ret |= PARPORT_STATUS_ERROR;
+
+	if (status & AX_SPR_SLCT)
+		ret |= PARPORT_STATUS_SELECT;
+
+	if (status & AX_SPR_PE)
+		ret |= PARPORT_STATUS_PAPEROUT;
+
+	return ret;
+}
+
+static unsigned char
+parport_ax88796_frob_control(struct parport *p, unsigned char mask,
+			     unsigned char val)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	unsigned char old = parport_ax88796_read_control(p);
+
+	dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n",
+		mask, val, old);
+
+	parport_ax88796_write_control(p, (old & ~mask) | val);
+	return old;
+}
+
+static void
+parport_ax88796_enable_irq(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (!dd->irq_enabled) {
+		enable_irq(p->irq);
+		dd->irq_enabled = 1;
+	}
+	local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_disable_irq(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (dd->irq_enabled) {
+		disable_irq(p->irq);
+		dd->irq_enabled = 0;
+	}
+	local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_data_forward(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	void __iomem *cpr = dd->spp_cpr;
+
+	writeb((readb(cpr) & ~AX_CPR_nDOE), cpr);
+}
+
+static void
+parport_ax88796_data_reverse(struct parport *p)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+	void __iomem *cpr = dd->spp_cpr;
+
+	writeb(readb(cpr) | AX_CPR_nDOE, cpr);
+}
+
+static void
+parport_ax88796_init_state(struct pardevice *d, struct parport_state *s)
+{
+	struct ax_drvdata *dd = pp_to_drv(d->port);
+
+	memset(s, 0, sizeof(struct parport_state));
+
+	dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s);
+	s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_save_state(struct parport *p, struct parport_state *s)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s);
+	s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
+{
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s);
+	writeb(s->u.ax88796.cpr, dd->spp_cpr);
+}
+
+static irqreturn_t
+parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+        parport_generic_irq(irq, dev_id, regs);
+        return IRQ_HANDLED;
+}
+
+
+static struct parport_operations parport_ax88796_ops = {
+	.write_data	= parport_ax88796_write_data,
+	.read_data	= parport_ax88796_read_data,
+
+	.write_control	= parport_ax88796_write_control,
+	.read_control	= parport_ax88796_read_control,
+	.frob_control	= parport_ax88796_frob_control,
+
+	.read_status	= parport_ax88796_read_status,
+
+	.enable_irq	= parport_ax88796_enable_irq,
+	.disable_irq	= parport_ax88796_disable_irq,
+
+	.data_forward	= parport_ax88796_data_forward,
+	.data_reverse	= parport_ax88796_data_reverse,
+
+	.init_state	= parport_ax88796_init_state,
+	.save_state	= parport_ax88796_save_state,
+	.restore_state	= parport_ax88796_restore_state,
+
+	.epp_write_data	= parport_ieee1284_epp_write_data,
+	.epp_read_data	= parport_ieee1284_epp_read_data,
+	.epp_write_addr	= parport_ieee1284_epp_write_addr,
+	.epp_read_addr	= parport_ieee1284_epp_read_addr,
+
+	.ecp_write_data	= parport_ieee1284_ecp_write_data,
+	.ecp_read_data	= parport_ieee1284_ecp_read_data,
+	.ecp_write_addr	= parport_ieee1284_ecp_write_addr,
+
+	.compat_write_data	= parport_ieee1284_write_compat,
+	.nibble_read_data	= parport_ieee1284_read_nibble,
+	.byte_read_data		= parport_ieee1284_read_byte,
+
+	.owner		= THIS_MODULE,
+};
+
+static int parport_ax88796_probe(struct platform_device *pdev)
+{
+	struct device *_dev = &pdev->dev;
+	struct ax_drvdata *dd;
+	struct parport *pp = NULL;
+	struct resource *res;
+	unsigned long size;
+	int spacing;
+	int irq;
+	int ret;
+
+	dd = kzalloc(sizeof(struct ax_drvdata), GFP_KERNEL);
+	if (dd == NULL) {
+		dev_err(_dev, "no memory for private data\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(_dev, "no MEM specified\n");
+		ret = -ENXIO;
+		goto exit_mem;
+	}
+
+	size = (res->end - res->start) + 1;
+	spacing = size / 3;
+
+	dd->io = request_mem_region(res->start, size, pdev->name);
+	if (dd->io == NULL) {
+		dev_err(_dev, "cannot reserve memory\n");
+		ret = -ENXIO;
+		goto exit_mem;
+	}
+
+	dd->base = ioremap(res->start, size);
+	if (dd->base == NULL) {
+		dev_err(_dev, "cannot ioremap region\n");
+		ret = -ENXIO;
+		goto exit_res;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0)
+		irq = PARPORT_IRQ_NONE;
+
+	pp = parport_register_port((unsigned long)dd->base, irq,
+				   PARPORT_DMA_NONE,
+				   &parport_ax88796_ops);
+
+	if (pp == NULL) {
+		dev_err(_dev, "failed to register parallel port\n");
+		ret = -ENOMEM;
+		goto exit_unmap;
+	}
+
+	pp->private_data = dd;
+	dd->parport = pp;
+	dd->dev = _dev;
+
+	dd->spp_data = dd->base;
+	dd->spp_spr  = dd->base + (spacing * 1);
+	dd->spp_cpr  = dd->base + (spacing * 2);
+
+	/* initialise the port controls */
+	writeb(AX_CPR_STRB, dd->spp_cpr);
+
+	if (irq >= 0) {
+		/* request irq */
+		ret = request_irq(irq, parport_ax88796_interrupt,
+				  SA_TRIGGER_FALLING, pdev->name, pp);
+
+		if (ret < 0)
+			goto exit_port;
+
+		dd->irq_enabled = 1;
+	}
+
+	platform_set_drvdata(pdev, pp);
+
+	dev_info(_dev, "attached parallel port driver\n");
+	parport_announce_port(pp);
+
+	return 0;
+
+ exit_port:
+	parport_remove_port(pp);
+ exit_unmap:
+	iounmap(dd->base);
+ exit_res:
+	release_resource(dd->io);
+	kfree(dd->io);
+ exit_mem:
+	kfree(dd);
+	return ret;
+}
+
+static int parport_ax88796_remove(struct platform_device *pdev)
+{
+	struct parport *p = platform_get_drvdata(pdev);
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	free_irq(p->irq, p);
+	parport_remove_port(p);
+	iounmap(dd->base);
+	release_resource(dd->io);
+	kfree(dd->io);
+	kfree(dd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int parport_ax88796_suspend(struct platform_device *dev,
+				   pm_message_t state)
+{
+	struct parport *p = platform_get_drvdata(dev);
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	parport_ax88796_save_state(p, &dd->suspend);
+	writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr);
+	return 0;
+}
+
+static int parport_ax88796_resume(struct platform_device *dev)
+{
+	struct parport *p = platform_get_drvdata(dev);
+	struct ax_drvdata *dd = pp_to_drv(p);
+
+	parport_ax88796_restore_state(p, &dd->suspend);
+	return 0;
+}
+
+#else
+#define parport_ax88796_suspend NULL
+#define parport_ax88796_resume  NULL
+#endif
+
+static struct platform_driver axdrv = {
+	.driver		= {
+		.name	= "ax88796-pp",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= parport_ax88796_probe,
+	.remove		= parport_ax88796_remove,
+	.suspend	= parport_ax88796_suspend,
+	.resume		= parport_ax88796_resume,
+};
+
+static int __init parport_ax88796_init(void)
+{
+	return platform_driver_register(&axdrv);
+}
+
+static void __exit parport_ax88796_exit(void)
+{
+	platform_driver_unregister(&axdrv);
+}
+
+module_init(parport_ax88796_init)
+module_exit(parport_ax88796_exit)
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 1de52d9..7352104 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -15,7 +15,7 @@
  * 	    Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
- *          David Campbell <campbell@torque.net>
+ *          David Campbell
  *          Andrea Arcangeli
  */
 
diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h
index 662f6c1..fc9c37c 100644
--- a/drivers/parport/parport_gsc.h
+++ b/drivers/parport/parport_gsc.h
@@ -24,7 +24,7 @@
  * 	    Phil Blundell <Philip.Blundell@pobox.com>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
- *          David Campbell <campbell@torque.net>
+ *          David Campbell
  *          Andrea Arcangeli
  */
 
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 48bbf32..7318e4a 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -3,7 +3,7 @@
  * Authors: Phil Blundell <philb@gnu.org>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
- *          David Campbell <campbell@torque.net>
+ *          David Campbell
  *          Andrea Arcangeli
  *
  * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 69a4bbd..7c43c53 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -389,7 +389,7 @@
 	{},
 };
 
-MODULE_DEVICE_TABLE(of, qec_sbus_match);
+MODULE_DEVICE_TABLE(of, bpp_match);
 
 static struct of_platform_driver bpp_sbus_driver = {
 	.name		= "bpp",
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index cbe1718..8610ae8 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -1,6 +1,6 @@
 /* Sysctl interface for parport devices.
  * 
- * Authors: David Campbell <campbell@torque.net>
+ * Authors: David Campbell
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *          Philip Blundell <philb@gnu.org>
  *          Andrea Arcangeli
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index bbbfd79..2cb22c8 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -218,7 +218,7 @@
  *	parport_get_port - increment a port's reference count
  *	@port: the port
  *
- *	This ensure's that a struct parport pointer remains valid
+ *	This ensures that a struct parport pointer remains valid
  *	until the matching parport_put_port() call.
  **/
 
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
index 0eb5fe9..5ed798b3 100644
--- a/drivers/pci/msi-apic.c
+++ b/drivers/pci/msi-apic.c
@@ -4,6 +4,7 @@
 
 #include <linux/pci.h>
 #include <linux/irq.h>
+#include <asm/smp.h>
 
 #include "msi.h"
 
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d408a3c..23d3b17 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -369,7 +369,7 @@
 
 	/*
 	 * Give firmware a chance to be called, such as ACPI _PRx, _PSx
-	 * Firmware method after natice method ?
+	 * Firmware method after native method ?
 	 */
 	if (platform_pci_set_power_state)
 		platform_pci_set_power_state(dev, state);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index bb19c64..0b4adcb 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -60,30 +60,34 @@
 	card_remove(dev);
 }
 
-static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
+static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
 {
-	const struct pnp_card_device_id *id = match_card(drv,card);
-	if (id) {
-		struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
-		if (!clink)
-			return 0;
-		clink->card = card;
-		clink->driver = drv;
-		clink->pm_state = PMSG_ON;
-		if (drv->probe) {
-			if (drv->probe(clink, id)>=0)
-				return 1;
-			else {
-				struct pnp_dev * dev;
-				card_for_each_dev(card, dev) {
-					if (dev->card_link == clink)
-						pnp_release_card_device(dev);
-				}
-				kfree(clink);
-			}
-		} else
-			return 1;
+	const struct pnp_card_device_id *id;
+	struct pnp_card_link *clink;
+	struct pnp_dev *dev;
+
+	if (!drv->probe)
+		return 0;
+	id = match_card(drv,card);
+	if (!id)
+		return 0;
+
+	clink = pnp_alloc(sizeof(*clink));
+	if (!clink)
+		return 0;
+	clink->card = card;
+	clink->driver = drv;
+	clink->pm_state = PMSG_ON;
+
+	if (drv->probe(clink, id) >= 0)
+		return 1;
+
+	/* Recovery */
+	card_for_each_dev(card, dev) {
+		if (dev->card_link == clink)
+			pnp_release_card_device(dev);
 	}
+	kfree(clink);
 	return 0;
 }
 
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 65d090d..bccff40 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -73,6 +73,13 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-dev.
 
+config RTC_INTF_DEV_UIE_EMUL
+	bool "RTC UIE emulation on dev interface"
+	depends on RTC_INTF_DEV
+	help
+	  Provides an emulation for RTC_UIE if the underlaying rtc chip
+	  driver did not provide RTC_UIE ioctls.
+
 comment "RTC drivers"
 	depends on RTC_CLASS
 
@@ -86,6 +93,34 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-x1205.
 
+config RTC_DRV_DS1307
+	tristate "Dallas/Maxim DS1307 and similar I2C RTC chips"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for various compatible RTC
+	  chips (often with battery backup) connected with I2C.  This driver
+	  should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
+	  and probably other chips.  In some cases the RTC must already
+	  have been initialized (by manufacturing or a bootloader).
+
+	  The first seven registers on these chips hold an RTC, and other
+	  registers may add features such as NVRAM, a trickle charger for
+	  the RTC/NVRAM backup power, and alarms.  This driver may not
+	  expose all those available chip features.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1307.
+
+config RTC_DRV_DS1553
+	tristate "Dallas DS1553"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  Dallas DS1553 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1553.
+
 config RTC_DRV_DS1672
 	tristate "Dallas/Maxim DS1672"
 	depends on RTC_CLASS && I2C
@@ -96,6 +131,16 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1672.
 
+config RTC_DRV_DS1742
+	tristate "Dallas DS1742"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  Dallas DS1742 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1742.
+
 config RTC_DRV_PCF8563
 	tristate "Philips PCF8563/Epson RTC8564"
 	depends on RTC_CLASS && I2C
@@ -107,6 +152,16 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-pcf8563.
 
+config RTC_DRV_PCF8583
+	tristate "Philips PCF8583"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Philips PCF8583 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-pcf8583.
+
 config RTC_DRV_RS5C372
 	tristate "Ricoh RS5C372A/B"
 	depends on RTC_CLASS && I2C
@@ -157,6 +212,22 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called rtc-vr41xx.
 
+config RTC_DRV_PL031
+	tristate "ARM AMBA PL031 RTC"
+	depends on RTC_CLASS && ARM_AMBA
+	help
+	  If you say Y here you will get access to ARM AMBA
+	  PrimeCell PL031 UART found on certain ARM SOCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rtc-pl031.
+
+config RTC_DRV_AT91
+	tristate "AT91RM9200"
+	depends on RTC_CLASS && ARCH_AT91RM9200
+	help
+	  Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+
 config RTC_DRV_TEST
 	tristate "Test driver/device"
 	depends on RTC_CLASS
@@ -172,4 +243,24 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-test.
 
+config RTC_DRV_MAX6902
+	tristate "Maxim 6902"
+	depends on RTC_CLASS && SPI
+	help
+	  If you say yes here you will get support for the
+	  Maxim MAX6902 spi RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max6902.
+
+config RTC_DRV_V3020
+	tristate "EM Microelectronic V3020"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you will get support for the
+	  EM Microelectronic v3020 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-v3020.
+
 endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index a9ca0f1..900d210 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -13,10 +13,18 @@
 
 obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
+obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1742)	+= rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o
+obj-$(CONFIG_RTC_DRV_PCF8583)	+= rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
 obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
+obj-$(CONFIG_RTC_DRV_AT91)	+= rtc-at91.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 413c7d5..5396bee 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -69,6 +69,7 @@
 	rtc->id = id;
 	rtc->ops = ops;
 	rtc->owner = owner;
+	rtc->max_user_freq = 64;
 	rtc->class_dev.dev = dev;
 	rtc->class_dev.class = rtc_class;
 	rtc->class_dev.release = rtc_device_release;
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 56e4907..579cd66 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -229,6 +229,9 @@
 	unsigned long flags;
 	struct rtc_device *rtc = to_rtc_device(class_dev);
 
+	if (rtc->ops->irq_set_state == NULL)
+		return -ENXIO;
+
 	spin_lock_irqsave(&rtc->irq_task_lock, flags);
 	if (rtc->irq_task != task)
 		err = -ENXIO;
@@ -243,25 +246,12 @@
 
 int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
 {
-	int err = 0, tmp = 0;
+	int err = 0;
 	unsigned long flags;
 	struct rtc_device *rtc = to_rtc_device(class_dev);
 
-	/* allowed range is 2-8192 */
-	if (freq < 2 || freq > 8192)
-		return -EINVAL;
-/*
-	FIXME: this does not belong here, will move where appropriate
-	at a later stage. It cannot hurt right now, trust me :)
-	if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
-		return -EACCES;
-*/
-	/* check if freq is a power of 2 */
-	while (freq > (1 << tmp))
-		tmp++;
-
-	if (freq != (1 << tmp))
-		return -EINVAL;
+	if (rtc->ops->irq_set_freq == NULL)
+		return -ENXIO;
 
 	spin_lock_irqsave(&rtc->irq_task_lock, flags);
 	if (rtc->irq_task != task)
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c
new file mode 100644
index 0000000..b676f44
--- /dev/null
+++ b/drivers/rtc/rtc-at91.c
@@ -0,0 +1,407 @@
+/*
+ *	Real Time Clock interface for Linux on Atmel AT91RM9200
+ *
+ *	Copyright (C) 2002 Rick Bronson
+ *
+ *	Converted to RTC class model by Andrew Victor
+ *
+ *	Ported to Linux 2.6 by Steven Scholz
+ *	Based on s3c2410-rtc.c Simtec Electronics
+ *
+ *	Based on sa1100-rtc.c by Nils Faerber
+ *	Based on rtc.c by Paul Gortmaker
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+
+#define AT91_RTC_FREQ		1
+#define AT91_RTC_EPOCH		1900UL	/* just like arch/arm/common/rtctime.c */
+
+static DECLARE_COMPLETION(at91_rtc_updated);
+static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
+
+/*
+ * Decode time/date into rtc_time structure
+ */
+static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
+				struct rtc_time *tm)
+{
+	unsigned int time, date;
+
+	/* must read twice in case it changes */
+	do {
+		time = at91_sys_read(timereg);
+		date = at91_sys_read(calreg);
+	} while ((time != at91_sys_read(timereg)) ||
+			(date != at91_sys_read(calreg)));
+
+	tm->tm_sec  = BCD2BIN((time & AT91_RTC_SEC) >> 0);
+	tm->tm_min  = BCD2BIN((time & AT91_RTC_MIN) >> 8);
+	tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);
+
+	/*
+	 * The Calendar Alarm register does not have a field for
+	 * the year - so these will return an invalid value.  When an
+	 * alarm is set, at91_alarm_year wille store the current year.
+	 */
+	tm->tm_year  = BCD2BIN(date & AT91_RTC_CENT) * 100;	/* century */
+	tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8);	/* year */
+
+	tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1;	/* day of the week [0-6], Sunday=0 */
+	tm->tm_mon  = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
+	tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
+}
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+	at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm);
+	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+	tm->tm_year = tm->tm_year - 1900;
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+		tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long cr;
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+		tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	/* Stop Time/Calendar from counting */
+	cr = at91_sys_read(AT91_RTC_CR);
+	at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
+
+	at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
+	wait_for_completion(&at91_rtc_updated);	/* wait for ACKUPD interrupt */
+	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+
+	at91_sys_write(AT91_RTC_TIMR,
+			  BIN2BCD(tm->tm_sec) << 0
+			| BIN2BCD(tm->tm_min) << 8
+			| BIN2BCD(tm->tm_hour) << 16);
+
+	at91_sys_write(AT91_RTC_CALR,
+			  BIN2BCD((tm->tm_year + 1900) / 100)	/* century */
+			| BIN2BCD(tm->tm_year % 100) << 8	/* year */
+			| BIN2BCD(tm->tm_mon + 1) << 16		/* tm_mon starts at zero */
+			| BIN2BCD(tm->tm_wday + 1) << 21	/* day of the week [0-6], Sunday=0 */
+			| BIN2BCD(tm->tm_mday) << 24);
+
+	/* Restart Time/Calendar */
+	cr = at91_sys_read(AT91_RTC_CR);
+	at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
+
+	return 0;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_time *tm = &alrm->time;
+
+	at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
+	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+	tm->tm_year = at91_alarm_year - 1900;
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+		tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	return 0;
+}
+
+/*
+ * Set alarm time and date in RTC
+ */
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_time tm;
+
+	at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
+
+	at91_alarm_year = tm.tm_year;
+
+	tm.tm_hour = alrm->time.tm_hour;
+	tm.tm_min = alrm->time.tm_min;
+	tm.tm_sec = alrm->time.tm_sec;
+
+	at91_sys_write(AT91_RTC_TIMALR,
+		  BIN2BCD(tm.tm_sec) << 0
+		| BIN2BCD(tm.tm_min) << 8
+		| BIN2BCD(tm.tm_hour) << 16
+		| AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
+	at91_sys_write(AT91_RTC_CALALR,
+		  BIN2BCD(tm.tm_mon + 1) << 16		/* tm_mon starts at zero */
+		| BIN2BCD(tm.tm_mday) << 24
+		| AT91_RTC_DATEEN | AT91_RTC_MTHEN);
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+		tm.tm_min, tm.tm_sec);
+
+	return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+			unsigned long arg)
+{
+	int ret = 0;
+
+	pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
+
+	switch (cmd) {
+	case RTC_AIE_OFF:	/* alarm off */
+		at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+		break;
+	case RTC_AIE_ON:	/* alarm on */
+		at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+		break;
+	case RTC_UIE_OFF:	/* update off */
+	case RTC_PIE_OFF:	/* periodic off */
+		at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
+		break;
+	case RTC_UIE_ON:	/* update on */
+	case RTC_PIE_ON:	/* periodic on */
+		at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
+		break;
+	case RTC_IRQP_READ:	/* read periodic alarm frequency */
+		ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
+		break;
+	case RTC_IRQP_SET:	/* set periodic alarm frequency */
+		if (arg != AT91_RTC_FREQ)
+			ret = -EINVAL;
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	unsigned long imr = at91_sys_read(AT91_RTC_IMR);
+
+	seq_printf(seq, "alarm_IRQ\t: %s\n",
+			(imr & AT91_RTC_ALARM) ? "yes" : "no");
+	seq_printf(seq, "update_IRQ\t: %s\n",
+			(imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+	seq_printf(seq, "periodic_IRQ\t: %s\n",
+			(imr & AT91_RTC_SECEV) ? "yes" : "no");
+	seq_printf(seq, "periodic_freq\t: %ld\n",
+			(unsigned long) AT91_RTC_FREQ);
+
+	return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	unsigned int rtsr;
+	unsigned long events = 0;
+
+	rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR);
+	if (rtsr) {		/* this interrupt is shared!  Is it ours? */
+		if (rtsr & AT91_RTC_ALARM)
+			events |= (RTC_AF | RTC_IRQF);
+		if (rtsr & AT91_RTC_SECEV)
+			events |= (RTC_UF | RTC_IRQF);
+		if (rtsr & AT91_RTC_ACKUPD)
+			complete(&at91_rtc_updated);
+
+		at91_sys_write(AT91_RTC_SCCR, rtsr);	/* clear status reg */
+
+		rtc_update_irq(&rtc->class_dev, 1, events);
+
+		pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
+			events >> 8, events & 0x000000FF);
+
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;		/* not handled */
+}
+
+static struct rtc_class_ops at91_rtc_ops = {
+	.ioctl		= at91_rtc_ioctl,
+	.read_time	= at91_rtc_readtime,
+	.set_time	= at91_rtc_settime,
+	.read_alarm	= at91_rtc_readalarm,
+	.set_alarm	= at91_rtc_setalarm,
+	.proc		= at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	int ret;
+
+	at91_sys_write(AT91_RTC_CR, 0);
+	at91_sys_write(AT91_RTC_MR, 0);		/* 24 hour mode */
+
+	/* Disable all interrupts */
+	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+					AT91_RTC_SECEV | AT91_RTC_TIMEV |
+					AT91_RTC_CALEV);
+
+	ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+				SA_SHIRQ, "at91_rtc", pdev);
+	if (ret) {
+		printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
+				AT91_ID_SYS);
+		return ret;
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+				&at91_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		free_irq(AT91_ID_SYS, pdev);
+		return PTR_ERR(rtc);
+	}
+	platform_set_drvdata(pdev, rtc);
+
+	printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+	return 0;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+	/* Disable all interrupts */
+	at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+					AT91_RTC_SECEV | AT91_RTC_TIMEV |
+					AT91_RTC_CALEV);
+	free_irq(AT91_ID_SYS, pdev);
+
+	rtc_device_unregister(rtc);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* AT91RM9200 RTC Power management control */
+
+static struct timespec at91_rtc_delta;
+
+static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_time tm;
+	struct timespec time;
+
+	time.tv_nsec = 0;
+
+	/* calculate time delta for suspend */
+	at91_rtc_readtime(&pdev->dev, &tm);
+	rtc_tm_to_time(&tm, &time.tv_sec);
+	save_time_delta(&at91_rtc_delta, &time);
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_time tm;
+	struct timespec time;
+
+	time.tv_nsec = 0;
+
+	at91_rtc_readtime(&pdev->dev, &tm);
+	rtc_tm_to_time(&tm, &time.tv_sec);
+	restore_time_delta(&at91_rtc_delta, &time);
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume  NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+	.probe		= at91_rtc_probe,
+	.remove		= at91_rtc_remove,
+	.suspend	= at91_rtc_suspend,
+	.resume		= at91_rtc_resume,
+	.driver		= {
+		.name	= "at91_rtc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91_rtc_init(void)
+{
+	return platform_driver_register(&at91_rtc_driver);
+}
+
+static void __exit at91_rtc_exit(void)
+{
+	platform_driver_unregister(&at91_rtc_driver);
+}
+
+module_init(at91_rtc_init);
+module_exit(at91_rtc_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 2011567..61a5825 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -48,6 +48,93 @@
 	return err;
 }
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void rtc_uie_task(void *data)
+{
+	struct rtc_device *rtc = data;
+	struct rtc_time tm;
+	int num = 0;
+	int err;
+
+	err = rtc_read_time(&rtc->class_dev, &tm);
+	spin_lock_irq(&rtc->irq_lock);
+	if (rtc->stop_uie_polling || err) {
+		rtc->uie_task_active = 0;
+	} else if (rtc->oldsecs != tm.tm_sec) {
+		num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
+		rtc->oldsecs = tm.tm_sec;
+		rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
+		rtc->uie_timer_active = 1;
+		rtc->uie_task_active = 0;
+		add_timer(&rtc->uie_timer);
+	} else if (schedule_work(&rtc->uie_task) == 0) {
+		rtc->uie_task_active = 0;
+	}
+	spin_unlock_irq(&rtc->irq_lock);
+	if (num)
+		rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF);
+}
+
+static void rtc_uie_timer(unsigned long data)
+{
+	struct rtc_device *rtc = (struct rtc_device *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtc->irq_lock, flags);
+	rtc->uie_timer_active = 0;
+	rtc->uie_task_active = 1;
+	if ((schedule_work(&rtc->uie_task) == 0))
+		rtc->uie_task_active = 0;
+	spin_unlock_irqrestore(&rtc->irq_lock, flags);
+}
+
+static void clear_uie(struct rtc_device *rtc)
+{
+	spin_lock_irq(&rtc->irq_lock);
+	if (rtc->irq_active) {
+		rtc->stop_uie_polling = 1;
+		if (rtc->uie_timer_active) {
+			spin_unlock_irq(&rtc->irq_lock);
+			del_timer_sync(&rtc->uie_timer);
+			spin_lock_irq(&rtc->irq_lock);
+			rtc->uie_timer_active = 0;
+		}
+		if (rtc->uie_task_active) {
+			spin_unlock_irq(&rtc->irq_lock);
+			flush_scheduled_work();
+			spin_lock_irq(&rtc->irq_lock);
+		}
+		rtc->irq_active = 0;
+	}
+	spin_unlock_irq(&rtc->irq_lock);
+}
+
+static int set_uie(struct rtc_device *rtc)
+{
+	struct rtc_time tm;
+	int err;
+
+	err = rtc_read_time(&rtc->class_dev, &tm);
+	if (err)
+		return err;
+	spin_lock_irq(&rtc->irq_lock);
+	if (!rtc->irq_active) {
+		rtc->irq_active = 1;
+		rtc->stop_uie_polling = 0;
+		rtc->oldsecs = tm.tm_sec;
+		rtc->uie_task_active = 1;
+		if (schedule_work(&rtc->uie_task) == 0)
+			rtc->uie_task_active = 0;
+	}
+	rtc->irq_data = 0;
+	spin_unlock_irq(&rtc->irq_lock);
+	return 0;
+}
+#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
 
 static ssize_t
 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -127,6 +214,28 @@
 	struct rtc_wkalrm alarm;
 	void __user *uarg = (void __user *) arg;
 
+	/* check that the calles has appropriate permissions
+	 * for certain ioctls. doing this check here is useful
+	 * to avoid duplicate code in each driver.
+	 */
+	switch (cmd) {
+	case RTC_EPOCH_SET:
+	case RTC_SET_TIME:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+		break;
+
+	case RTC_IRQP_SET:
+		if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
+			return -EACCES;
+		break;
+
+	case RTC_PIE_ON:
+		if (!capable(CAP_SYS_RESOURCE))
+			return -EACCES;
+		break;
+	}
+
 	/* avoid conflicting IRQ users */
 	if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
 		spin_lock(&rtc->irq_task_lock);
@@ -185,9 +294,6 @@
 		break;
 
 	case RTC_SET_TIME:
-		if (!capable(CAP_SYS_TIME))
-			return -EACCES;
-
 		if (copy_from_user(&tm, uarg, sizeof(tm)))
 			return -EFAULT;
 
@@ -203,10 +309,6 @@
 			err = -EINVAL;
 			break;
 		}
-		if (!capable(CAP_SYS_TIME)) {
-			err = -EACCES;
-			break;
-		}
 		rtc_epoch = arg;
 		err = 0;
 #endif
@@ -232,6 +334,14 @@
 			return -EFAULT;
 		break;
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+	case RTC_UIE_OFF:
+		clear_uie(rtc);
+		return 0;
+
+	case RTC_UIE_ON:
+		return set_uie(rtc);
+#endif
 	default:
 		err = -ENOTTY;
 		break;
@@ -244,6 +354,9 @@
 {
 	struct rtc_device *rtc = to_rtc_device(file->private_data);
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+	clear_uie(rtc);
+#endif
 	if (rtc->ops->release)
 		rtc->ops->release(rtc->class_dev.dev);
 
@@ -284,6 +397,10 @@
 	mutex_init(&rtc->char_lock);
 	spin_lock_init(&rtc->irq_lock);
 	init_waitqueue_head(&rtc->irq_queue);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+	INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc);
+	setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
+#endif
 
 	cdev_init(&rtc->char_dev, &rtc_dev_fops);
 	rtc->char_dev.owner = rtc->owner;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
new file mode 100644
index 0000000..e8afb93
--- /dev/null
+++ b/drivers/rtc/rtc-ds1307.c
@@ -0,0 +1,388 @@
+/*
+ * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips.
+ *
+ *  Copyright (C) 2005 James Chapman (ds1337 core)
+ *  Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+
+
+/* We can't determine type by probing, but if we expect pre-Linux code
+ * to have set the chip up as a clock (turning on the oscillator and
+ * setting the date and time), Linux can ignore the non-clock features.
+ * That's a natural job for a factory or repair bench.
+ *
+ * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
+ * (Much better would be board-specific tables of I2C devices, along with
+ * the platform_data drivers would use to sort such issues out.)
+ */
+enum ds_type {
+	unknown = 0,
+	ds_1307,		/* or ds1338, ... */
+	ds_1337,		/* or ds1339, ... */
+	ds_1340,		/* or st m41t00, ... */
+	// rs5c372 too?  different address...
+};
+
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+
+
+/* RTC registers don't differ much, except for the century flag */
+#define DS1307_REG_SECS		0x00	/* 00-59 */
+#	define DS1307_BIT_CH		0x80
+#define DS1307_REG_MIN		0x01	/* 00-59 */
+#define DS1307_REG_HOUR		0x02	/* 00-23, or 1-12{am,pm} */
+#	define DS1340_BIT_CENTURY_EN	0x80	/* in REG_HOUR */
+#	define DS1340_BIT_CENTURY	0x40	/* in REG_HOUR */
+#define DS1307_REG_WDAY		0x03	/* 01-07 */
+#define DS1307_REG_MDAY		0x04	/* 01-31 */
+#define DS1307_REG_MONTH	0x05	/* 01-12 */
+#	define DS1337_BIT_CENTURY	0x80	/* in REG_MONTH */
+#define DS1307_REG_YEAR		0x06	/* 00-99 */
+
+/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+ * start at 7, and they differ a lot. Only control and status matter for RTC;
+ * be careful using them.
+ */
+#define DS1307_REG_CONTROL	0x07
+#	define DS1307_BIT_OUT		0x80
+#	define DS1307_BIT_SQWE		0x10
+#	define DS1307_BIT_RS1		0x02
+#	define DS1307_BIT_RS0		0x01
+#define DS1337_REG_CONTROL	0x0e
+#	define DS1337_BIT_nEOSC		0x80
+#	define DS1337_BIT_RS2		0x10
+#	define DS1337_BIT_RS1		0x08
+#	define DS1337_BIT_INTCN		0x04
+#	define DS1337_BIT_A2IE		0x02
+#	define DS1337_BIT_A1IE		0x01
+#define DS1337_REG_STATUS	0x0f
+#	define DS1337_BIT_OSF		0x80
+#	define DS1337_BIT_A2I		0x02
+#	define DS1337_BIT_A1I		0x01
+#define DS1339_REG_TRICKLE	0x10
+
+
+
+struct ds1307 {
+	u8			reg_addr;
+	u8			regs[8];
+	enum ds_type		type;
+	struct i2c_msg		msg[2];
+	struct i2c_client	client;
+	struct rtc_device	*rtc;
+};
+
+
+static int ds1307_get_time(struct device *dev, struct rtc_time *t)
+{
+	struct ds1307	*ds1307 = dev_get_drvdata(dev);
+	int		tmp;
+
+	/* read the RTC registers all at once */
+	ds1307->msg[1].flags = I2C_M_RD;
+	ds1307->msg[1].len = 7;
+
+	tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2);
+	if (tmp != 2) {
+		dev_err(dev, "%s error %d\n", "read", tmp);
+		return -EIO;
+	}
+
+	dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+			"read",
+			ds1307->regs[0], ds1307->regs[1],
+			ds1307->regs[2], ds1307->regs[3],
+			ds1307->regs[4], ds1307->regs[5],
+			ds1307->regs[6]);
+
+	t->tm_sec = BCD2BIN(ds1307->regs[DS1307_REG_SECS] & 0x7f);
+	t->tm_min = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+	tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
+	t->tm_hour = BCD2BIN(tmp);
+	t->tm_wday = BCD2BIN(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
+	t->tm_mday = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+	tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
+	t->tm_mon = BCD2BIN(tmp) - 1;
+
+	/* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
+	t->tm_year = BCD2BIN(ds1307->regs[DS1307_REG_YEAR]) + 100;
+
+	dev_dbg(dev, "%s secs=%d, mins=%d, "
+		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+		"read", t->tm_sec, t->tm_min,
+		t->tm_hour, t->tm_mday,
+		t->tm_mon, t->tm_year, t->tm_wday);
+
+	return 0;
+}
+
+static int ds1307_set_time(struct device *dev, struct rtc_time *t)
+{
+	struct ds1307	*ds1307 = dev_get_drvdata(dev);
+	int		result;
+	int		tmp;
+	u8		*buf = ds1307->regs;
+
+	dev_dbg(dev, "%s secs=%d, mins=%d, "
+		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+		"write", dt->tm_sec, dt->tm_min,
+		dt->tm_hour, dt->tm_mday,
+		dt->tm_mon, dt->tm_year, dt->tm_wday);
+
+	*buf++ = 0;		/* first register addr */
+	buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
+	buf[DS1307_REG_MIN] = BIN2BCD(t->tm_min);
+	buf[DS1307_REG_HOUR] = BIN2BCD(t->tm_hour);
+	buf[DS1307_REG_WDAY] = BIN2BCD(t->tm_wday + 1);
+	buf[DS1307_REG_MDAY] = BIN2BCD(t->tm_mday);
+	buf[DS1307_REG_MONTH] = BIN2BCD(t->tm_mon + 1);
+
+	/* assume 20YY not 19YY */
+	tmp = t->tm_year - 100;
+	buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
+
+	if (ds1307->type == ds_1337)
+		buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
+	else if (ds1307->type == ds_1340)
+		buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
+				| DS1340_BIT_CENTURY;
+
+	ds1307->msg[1].flags = 0;
+	ds1307->msg[1].len = 8;
+
+	dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+		"write", buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6]);
+
+	result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1);
+	if (result != 1) {
+		dev_err(dev, "%s error %d\n", "write", tmp);
+		return -EIO;
+	}
+	return 0;
+}
+
+static struct rtc_class_ops ds13xx_rtc_ops = {
+	.read_time	= ds1307_get_time,
+	.set_time	= ds1307_set_time,
+};
+
+static struct i2c_driver ds1307_driver;
+
+static int __devinit
+ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct ds1307		*ds1307;
+	int			err = -ENODEV;
+	struct i2c_client	*client;
+	int			tmp;
+
+	if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &ds1307->client;
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &ds1307_driver;
+	client->flags = 0;
+
+	i2c_set_clientdata(client, ds1307);
+
+	ds1307->msg[0].addr = client->addr;
+	ds1307->msg[0].flags = 0;
+	ds1307->msg[0].len = 1;
+	ds1307->msg[0].buf = &ds1307->reg_addr;
+
+	ds1307->msg[1].addr = client->addr;
+	ds1307->msg[1].flags = I2C_M_RD;
+	ds1307->msg[1].len = sizeof(ds1307->regs);
+	ds1307->msg[1].buf = ds1307->regs;
+
+	/* HACK: "force" implies "needs ds1337-style-oscillator setup" */
+	if (kind >= 0) {
+		ds1307->type = ds_1337;
+
+		ds1307->reg_addr = DS1337_REG_CONTROL;
+		ds1307->msg[1].len = 2;
+
+		tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+		if (tmp != 2) {
+			pr_debug("read error %d\n", tmp);
+			err = -EIO;
+			goto exit_free;
+		}
+
+		ds1307->reg_addr = 0;
+		ds1307->msg[1].len = sizeof(ds1307->regs);
+
+		/* oscillator is off; need to turn it on */
+		if ((ds1307->regs[0] & DS1337_BIT_nEOSC)
+				|| (ds1307->regs[1] & DS1337_BIT_OSF)) {
+			printk(KERN_ERR "no ds1337 oscillator code\n");
+			goto exit_free;
+		}
+	} else
+		ds1307->type = ds_1307;
+
+read_rtc:
+	/* read RTC registers */
+
+	tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+	if (tmp != 2) {
+		pr_debug("read error %d\n", tmp);
+		err = -EIO;
+		goto exit_free;
+	}
+
+	/* minimal sanity checking; some chips (like DS1340) don't
+	 * specify the extra bits as must-be-zero, but there are
+	 * still a few values that are clearly out-of-range.
+	 */
+	tmp = ds1307->regs[DS1307_REG_SECS];
+	if (tmp & DS1307_BIT_CH) {
+		if (ds1307->type && ds1307->type != ds_1307) {
+			pr_debug("not a ds1307?\n");
+			goto exit_free;
+		}
+		ds1307->type = ds_1307;
+
+		/* this partial initialization should work for ds1307,
+		 * ds1338, ds1340, st m41t00, and more.
+		 */
+		dev_warn(&client->dev, "oscillator started; SET TIME!\n");
+		i2c_smbus_write_byte_data(client, 0, 0);
+		goto read_rtc;
+	}
+	tmp = BCD2BIN(tmp & 0x7f);
+	if (tmp > 60)
+		goto exit_free;
+	tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+	if (tmp > 60)
+		goto exit_free;
+
+	tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+	if (tmp == 0 || tmp > 31)
+		goto exit_free;
+
+	tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
+	if (tmp == 0 || tmp > 12)
+		goto exit_free;
+
+	/* force into in 24 hour mode (most chips) or
+	 * disable century bit (ds1340)
+	 */
+	tmp = ds1307->regs[DS1307_REG_HOUR];
+	if (tmp & (1 << 6)) {
+		if (tmp & (1 << 5))
+			tmp = BCD2BIN(tmp & 0x1f) + 12;
+		else
+			tmp = BCD2BIN(tmp);
+		i2c_smbus_write_byte_data(client,
+				DS1307_REG_HOUR,
+				BIN2BCD(tmp));
+	}
+
+	/* FIXME chips like 1337 can generate alarm irqs too; those are
+	 * worth exposing through the API (especially when the irq is
+	 * wakeup-capable).
+	 */
+
+	switch (ds1307->type) {
+	case unknown:
+		strlcpy(client->name, "unknown", I2C_NAME_SIZE);
+		break;
+	case ds_1307:
+		strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
+		break;
+	case ds_1337:
+		strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
+		break;
+	case ds_1340:
+		strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
+		break;
+	}
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(client)))
+		goto exit_free;
+
+	ds1307->rtc = rtc_device_register(client->name, &client->dev,
+				&ds13xx_rtc_ops, THIS_MODULE);
+	if (IS_ERR(ds1307->rtc)) {
+		err = PTR_ERR(ds1307->rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(ds1307);
+exit:
+	return err;
+}
+
+static int __devinit
+ds1307_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+		return 0;
+	return i2c_probe(adapter, &addr_data, ds1307_detect);
+}
+
+static int __devexit ds1307_detach_client(struct i2c_client *client)
+{
+	int		err;
+	struct ds1307	*ds1307 = i2c_get_clientdata(client);
+
+	rtc_device_unregister(ds1307->rtc);
+	if ((err = i2c_detach_client(client)))
+		return err;
+	kfree(ds1307);
+	return 0;
+}
+
+static struct i2c_driver ds1307_driver = {
+	.driver = {
+		.name	= "ds1307",
+		.owner	= THIS_MODULE,
+	},
+	.attach_adapter	= ds1307_attach_adapter,
+	.detach_client	= __devexit_p(ds1307_detach_client),
+};
+
+static int __init ds1307_init(void)
+{
+	return i2c_add_driver(&ds1307_driver);
+}
+module_init(ds1307_init);
+
+static void __exit ds1307_exit(void)
+{
+	i2c_del_driver(&ds1307_driver);
+}
+module_exit(ds1307_exit);
+
+MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
new file mode 100644
index 0000000..ecafbad
--- /dev/null
+++ b/drivers/rtc/rtc-ds1553.c
@@ -0,0 +1,414 @@
+/*
+ * An rtc driver for the Dallas DS1553
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE		0x2000
+#define RTC_OFFSET		0x1ff0
+
+#define RTC_FLAGS		(RTC_OFFSET + 0)
+#define RTC_SECONDS_ALARM	(RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM	(RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM		(RTC_OFFSET + 4)
+#define RTC_DATE_ALARM		(RTC_OFFSET + 5)
+#define RTC_INTERRUPTS		(RTC_OFFSET + 6)
+#define RTC_WATCHDOG		(RTC_OFFSET + 7)
+#define RTC_CONTROL		(RTC_OFFSET + 8)
+#define RTC_CENTURY		(RTC_OFFSET + 8)
+#define RTC_SECONDS		(RTC_OFFSET + 9)
+#define RTC_MINUTES		(RTC_OFFSET + 10)
+#define RTC_HOURS		(RTC_OFFSET + 11)
+#define RTC_DAY			(RTC_OFFSET + 12)
+#define RTC_DATE		(RTC_OFFSET + 13)
+#define RTC_MONTH		(RTC_OFFSET + 14)
+#define RTC_YEAR		(RTC_OFFSET + 15)
+
+#define RTC_CENTURY_MASK	0x3f
+#define RTC_SECONDS_MASK	0x7f
+#define RTC_DAY_MASK		0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE		0x80
+#define RTC_READ		0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP		0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF		0x40
+#define RTC_FLAGS_BLF		0x10
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AE		0x80
+
+struct rtc_plat_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	unsigned long baseaddr;
+	unsigned long last_jiffies;
+	int irq;
+	unsigned int irqen;
+	int alrm_sec;
+	int alrm_min;
+	int alrm_hour;
+	int alrm_mday;
+};
+
+static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u8 century;
+
+	century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+	writeb(RTC_WRITE, pdata->ioaddr + RTC_CONTROL);
+
+	writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+	writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+	writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+	writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+	writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+	writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+	writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+	/* RTC_CENTURY and RTC_CONTROL share same register */
+	writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+	writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+	return 0;
+}
+
+static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned int year, month, day, hour, minute, second, week;
+	unsigned int century;
+
+	/* give enough time to update RTC in case of continuous read */
+	if (pdata->last_jiffies == jiffies)
+		msleep(1);
+	pdata->last_jiffies = jiffies;
+	writeb(RTC_READ, ioaddr + RTC_CONTROL);
+	second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+	minute = readb(ioaddr + RTC_MINUTES);
+	hour = readb(ioaddr + RTC_HOURS);
+	day = readb(ioaddr + RTC_DATE);
+	week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+	month = readb(ioaddr + RTC_MONTH);
+	year = readb(ioaddr + RTC_YEAR);
+	century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+	writeb(0, ioaddr + RTC_CONTROL);
+	tm->tm_sec = BCD2BIN(second);
+	tm->tm_min = BCD2BIN(minute);
+	tm->tm_hour = BCD2BIN(hour);
+	tm->tm_mday = BCD2BIN(day);
+	tm->tm_wday = BCD2BIN(week);
+	tm->tm_mon = BCD2BIN(month) - 1;
+	/* year is 1900 + tm->tm_year */
+	tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "retrieved date/time is not valid.\n");
+		rtc_time_to_tm(0, tm);
+	}
+	return 0;
+}
+
+static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+	writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_mday),
+	       ioaddr + RTC_DATE_ALARM);
+	writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_hour),
+	       ioaddr + RTC_HOURS_ALARM);
+	writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_min),
+	       ioaddr + RTC_MINUTES_ALARM);
+	writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_sec),
+	       ioaddr + RTC_SECONDS_ALARM);
+	writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);
+	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */
+	spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -EINVAL;
+	pdata->alrm_mday = alrm->time.tm_mday;
+	pdata->alrm_hour = alrm->time.tm_hour;
+	pdata->alrm_min = alrm->time.tm_min;
+	pdata->alrm_sec = alrm->time.tm_sec;
+	if (alrm->enabled)
+		pdata->irqen |= RTC_AF;
+	ds1553_rtc_update_alarm(pdata);
+	return 0;
+}
+
+static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -EINVAL;
+	alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+	alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+	alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+	alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+	alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+	return 0;
+}
+
+static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned long events = RTC_IRQF;
+
+	/* read and clear interrupt */
+	if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+		return IRQ_NONE;
+	if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+		events |= RTC_UF;
+	else
+		events |= RTC_AF;
+	rtc_update_irq(&pdata->rtc->class_dev, 1, events);
+	return IRQ_HANDLED;
+}
+
+static void ds1553_rtc_release(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq >= 0) {
+		pdata->irqen = 0;
+		ds1553_rtc_update_alarm(pdata);
+	}
+}
+
+static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -ENOIOCTLCMD;
+	switch (cmd) {
+	case RTC_AIE_OFF:
+		pdata->irqen &= ~RTC_AF;
+		ds1553_rtc_update_alarm(pdata);
+		break;
+	case RTC_AIE_ON:
+		pdata->irqen |= RTC_AF;
+		ds1553_rtc_update_alarm(pdata);
+		break;
+	case RTC_UIE_OFF:
+		pdata->irqen &= ~RTC_UF;
+		ds1553_rtc_update_alarm(pdata);
+		break;
+	case RTC_UIE_ON:
+		pdata->irqen |= RTC_UF;
+		ds1553_rtc_update_alarm(pdata);
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static struct rtc_class_ops ds1553_rtc_ops = {
+	.read_time	= ds1553_rtc_read_time,
+	.set_time	= ds1553_rtc_set_time,
+	.read_alarm	= ds1553_rtc_read_alarm,
+	.set_alarm	= ds1553_rtc_set_alarm,
+	.release	= ds1553_rtc_release,
+	.ioctl		= ds1553_rtc_ioctl,
+};
+
+static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
+				 loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		*buf++ = readb(ioaddr + pos++);
+	return count;
+}
+
+static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf,
+				  loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		writeb(*buf++, ioaddr + pos++);
+	return count;
+}
+
+static struct bin_attribute ds1553_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUGO | S_IWUGO,
+		.owner = THIS_MODULE,
+	},
+	.size = RTC_OFFSET,
+	.read = ds1553_nvram_read,
+	.write = ds1553_nvram_write,
+};
+
+static int __init ds1553_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	struct resource *res;
+	unsigned int cen, sec;
+	struct rtc_plat_data *pdata = NULL;
+	void __iomem *ioaddr = NULL;
+	int ret = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	pdata->irq = -1;
+	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	pdata->baseaddr = res->start;
+	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+	if (!ioaddr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	pdata->ioaddr = ioaddr;
+	pdata->irq = platform_get_irq(pdev, 0);
+
+	/* turn RTC on if it was not on */
+	sec = readb(ioaddr + RTC_SECONDS);
+	if (sec & RTC_STOP) {
+		sec &= RTC_SECONDS_MASK;
+		cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+		writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+		writeb(sec, ioaddr + RTC_SECONDS);
+		writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+	}
+	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF)
+		dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+	if (pdata->irq >= 0) {
+		writeb(0, ioaddr + RTC_INTERRUPTS);
+		if (request_irq(pdata->irq, ds1553_rtc_interrupt, SA_SHIRQ,
+				pdev->name, pdev) < 0) {
+			dev_warn(&pdev->dev, "interrupt not available.\n");
+			pdata->irq = -1;
+		}
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+				  &ds1553_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		ret = PTR_ERR(rtc);
+		goto out;
+	}
+	pdata->rtc = rtc;
+	pdata->last_jiffies = jiffies;
+	platform_set_drvdata(pdev, pdata);
+	sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+	return 0;
+ out:
+	if (pdata->irq >= 0)
+		free_irq(pdata->irq, pdev);
+	if (ioaddr)
+		iounmap(ioaddr);
+	if (pdata->baseaddr)
+		release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return ret;
+}
+
+static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+	rtc_device_unregister(pdata->rtc);
+	if (pdata->irq >= 0) {
+		writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+		free_irq(pdata->irq, pdev);
+	}
+	iounmap(pdata->ioaddr);
+	release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return 0;
+}
+
+static struct platform_driver ds1553_rtc_driver = {
+	.probe		= ds1553_rtc_probe,
+	.remove		= __devexit_p(ds1553_rtc_remove),
+	.driver		= {
+		.name	= "ds1553",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int ds1553_init(void)
+{
+	return platform_driver_register(&ds1553_rtc_driver);
+}
+
+static __exit void ds1553_exit(void)
+{
+	return platform_driver_unregister(&ds1553_rtc_driver);
+}
+
+module_init(ds1553_init);
+module_exit(ds1553_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1553 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
new file mode 100644
index 0000000..8e47e5a
--- /dev/null
+++ b/drivers/rtc/rtc-ds1742.c
@@ -0,0 +1,259 @@
+/*
+ * An rtc driver for the Dallas DS1742
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE		0x800
+#define RTC_OFFSET		0x7f8
+
+#define RTC_CONTROL		(RTC_OFFSET + 0)
+#define RTC_CENTURY		(RTC_OFFSET + 0)
+#define RTC_SECONDS		(RTC_OFFSET + 1)
+#define RTC_MINUTES		(RTC_OFFSET + 2)
+#define RTC_HOURS		(RTC_OFFSET + 3)
+#define RTC_DAY			(RTC_OFFSET + 4)
+#define RTC_DATE		(RTC_OFFSET + 5)
+#define RTC_MONTH		(RTC_OFFSET + 6)
+#define RTC_YEAR		(RTC_OFFSET + 7)
+
+#define RTC_CENTURY_MASK	0x3f
+#define RTC_SECONDS_MASK	0x7f
+#define RTC_DAY_MASK		0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE		0x80
+#define RTC_READ		0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP		0x80
+
+/* Bits in the Day register */
+#define RTC_BATT_FLAG		0x80
+
+struct rtc_plat_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	unsigned long baseaddr;
+	unsigned long last_jiffies;
+};
+
+static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u8 century;
+
+	century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+	writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+
+	writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+	writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+	writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+	writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+	writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+	writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+	writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+	/* RTC_CENTURY and RTC_CONTROL share same register */
+	writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+	writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+	return 0;
+}
+
+static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned int year, month, day, hour, minute, second, week;
+	unsigned int century;
+
+	/* give enough time to update RTC in case of continuous read */
+	if (pdata->last_jiffies == jiffies)
+		msleep(1);
+	pdata->last_jiffies = jiffies;
+	writeb(RTC_READ, ioaddr + RTC_CONTROL);
+	second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+	minute = readb(ioaddr + RTC_MINUTES);
+	hour = readb(ioaddr + RTC_HOURS);
+	day = readb(ioaddr + RTC_DATE);
+	week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+	month = readb(ioaddr + RTC_MONTH);
+	year = readb(ioaddr + RTC_YEAR);
+	century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+	writeb(0, ioaddr + RTC_CONTROL);
+	tm->tm_sec = BCD2BIN(second);
+	tm->tm_min = BCD2BIN(minute);
+	tm->tm_hour = BCD2BIN(hour);
+	tm->tm_mday = BCD2BIN(day);
+	tm->tm_wday = BCD2BIN(week);
+	tm->tm_mon = BCD2BIN(month) - 1;
+	/* year is 1900 + tm->tm_year */
+	tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "retrieved date/time is not valid.\n");
+		rtc_time_to_tm(0, tm);
+	}
+	return 0;
+}
+
+static struct rtc_class_ops ds1742_rtc_ops = {
+	.read_time	= ds1742_rtc_read_time,
+	.set_time	= ds1742_rtc_set_time,
+};
+
+static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
+				 loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		*buf++ = readb(ioaddr + pos++);
+	return count;
+}
+
+static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf,
+				  loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		writeb(*buf++, ioaddr + pos++);
+	return count;
+}
+
+static struct bin_attribute ds1742_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUGO | S_IWUGO,
+		.owner = THIS_MODULE,
+	},
+	.size = RTC_OFFSET,
+	.read = ds1742_nvram_read,
+	.write = ds1742_nvram_write,
+};
+
+static int __init ds1742_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	struct resource *res;
+	unsigned int cen, sec;
+	struct rtc_plat_data *pdata = NULL;
+	void __iomem *ioaddr = NULL;
+	int ret = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	pdata->baseaddr = res->start;
+	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+	if (!ioaddr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	pdata->ioaddr = ioaddr;
+
+	/* turn RTC on if it was not on */
+	sec = readb(ioaddr + RTC_SECONDS);
+	if (sec & RTC_STOP) {
+		sec &= RTC_SECONDS_MASK;
+		cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+		writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+		writeb(sec, ioaddr + RTC_SECONDS);
+		writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+	}
+	if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)
+		dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+				  &ds1742_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		ret = PTR_ERR(rtc);
+		goto out;
+	}
+	pdata->rtc = rtc;
+	pdata->last_jiffies = jiffies;
+	platform_set_drvdata(pdev, pdata);
+	sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+	return 0;
+ out:
+	if (ioaddr)
+		iounmap(ioaddr);
+	if (pdata->baseaddr)
+		release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return ret;
+}
+
+static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+	rtc_device_unregister(pdata->rtc);
+	iounmap(pdata->ioaddr);
+	release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return 0;
+}
+
+static struct platform_driver ds1742_rtc_driver = {
+	.probe		= ds1742_rtc_probe,
+	.remove		= __devexit_p(ds1742_rtc_remove),
+	.driver		= {
+		.name	= "ds1742",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int ds1742_init(void)
+{
+	return platform_driver_register(&ds1742_rtc_driver);
+}
+
+static __exit void ds1742_exit(void)
+{
+	return platform_driver_unregister(&ds1742_rtc_driver);
+}
+
+module_init(ds1742_init);
+module_exit(ds1742_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1742 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index cfedc1d..9812120 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -18,9 +18,19 @@
 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 };
 
+static const unsigned short rtc_ydays[2][13] = {
+	/* Normal years */
+	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+	/* Leap years */
+	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
 #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
 
+/*
+ * The number of days in the month.
+ */
 int rtc_month_days(unsigned int month, unsigned int year)
 {
 	return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
@@ -28,6 +38,15 @@
 EXPORT_SYMBOL(rtc_month_days);
 
 /*
+ * The number of days since January 1. (0 to 365)
+ */
+int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
+{
+	return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+}
+EXPORT_SYMBOL(rtc_year_days);
+
+/*
  * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
  */
 void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
new file mode 100644
index 0000000..2c97395
--- /dev/null
+++ b/drivers/rtc/rtc-max6902.c
@@ -0,0 +1,286 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * 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.
+ *
+ * Driver for MAX6902 spi RTC
+ *
+ * Changelog:
+ *
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ *                - Major rework
+ *   				Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ *                - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+
+#define MAX6902_REG_SECONDS		0x01
+#define MAX6902_REG_MINUTES		0x03
+#define MAX6902_REG_HOURS		0x05
+#define MAX6902_REG_DATE		0x07
+#define MAX6902_REG_MONTH		0x09
+#define MAX6902_REG_DAY			0x0B
+#define MAX6902_REG_YEAR		0x0D
+#define MAX6902_REG_CONTROL		0x0F
+#define MAX6902_REG_CENTURY		0x13
+
+#undef MAX6902_DEBUG
+
+struct max6902 {
+	struct rtc_device *rtc;
+	u8 buf[9]; /* Burst read cmd + 8 registers */
+	u8 tx_buf[2];
+	u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address,
+				unsigned char data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	/* MSB must be '0' to write */
+	buf[0] = address & 0x7f;
+	buf[1] = data;
+
+	spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address,
+				unsigned char *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	if (!data)
+		return -EINVAL;
+
+	/* Build our spi message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));
+	xfer.len = 2;
+	/* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+	xfer.tx_buf = chip->tx_buf;
+	xfer.rx_buf = chip->rx_buf;
+
+	/* Set MSB to indicate read */
+	chip->tx_buf[0] = address | 0x80;
+
+	spi_message_add_tail(&xfer, &message);
+
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0)
+		status = message.status;
+	else
+		return status;
+
+	*data = chip->rx_buf[1];
+
+	return status;
+}
+
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+	unsigned char tmp;
+	int century;
+	int err;
+	struct spi_device *spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+	if (err)
+		return err;
+
+	/* build the message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));
+	xfer.len = 1 + 7;	/* Burst read command + 7 registers */
+	xfer.tx_buf = chip->buf;
+	xfer.rx_buf = chip->buf;
+	chip->buf[0] = 0xbf;	/* Burst read */
+	spi_message_add_tail(&xfer, &message);
+
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0)
+		status = message.status;
+	else
+		return status;
+
+	/* The chip sends data in this order:
+	 * Seconds, Minutes, Hours, Date, Month, Day, Year */
+	dt->tm_sec	= BCD2BIN(chip->buf[1]);
+	dt->tm_min	= BCD2BIN(chip->buf[2]);
+	dt->tm_hour	= BCD2BIN(chip->buf[3]);
+	dt->tm_mday	= BCD2BIN(chip->buf[4]);
+	dt->tm_mon	= BCD2BIN(chip->buf[5] - 1);
+	dt->tm_wday	= BCD2BIN(chip->buf[6]);
+	dt->tm_year = BCD2BIN(chip->buf[7]);
+
+	century = BCD2BIN(tmp) * 100;
+
+	dt->tm_year += century;
+	dt->tm_year -= 1900;
+
+#ifdef MAX6902_DEBUG
+	printk("\n%s : Read RTC values\n",__FUNCTION__);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_year: %i\n",dt->tm_year);
+	printk("tm_mon : %i\n",dt->tm_mon);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+	return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+	dt->tm_year = dt->tm_year+1900;
+
+#ifdef MAX6902_DEBUG
+	printk("\n%s : Setting RTC values\n",__FUNCTION__);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+	printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+	/* Remove write protection */
+	max6902_set_reg(dev, 0xF, 0);
+
+	max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+	max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+	max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+	max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+	max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+	max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+	max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+	max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+	/* Compulab used a delay here. However, the datasheet
+	 * does not mention a delay being required anywhere... */
+	/* delay(2000); */
+
+	/* Write protect */
+	max6902_set_reg(dev, 0xF, 0x80);
+
+	return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+	.read_time	= max6902_read_time,
+	.set_time	= max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+	struct rtc_device *rtc;
+	unsigned char tmp;
+	struct max6902 *chip;
+	int res;
+
+	rtc = rtc_device_register("max6902",
+				&spi->dev, &max6902_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc))
+		return PTR_ERR(rtc);
+
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (!chip) {
+		rtc_device_unregister(rtc);
+		return -ENOMEM;
+	}
+	chip->rtc = rtc;
+	dev_set_drvdata(&spi->dev, chip);
+
+	res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+	if (res) {
+		rtc_device_unregister(rtc);
+		return res;
+	}
+
+	return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+	struct max6902 *chip = platform_get_drvdata(spi);
+	struct rtc_device *rtc = chip->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	kfree(chip);
+
+	return 0;
+}
+
+static struct spi_driver max6902_driver = {
+	.driver = {
+		.name 	= "max6902",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe 	= max6902_probe,
+	.remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+	printk("max6902 spi driver\n");
+	return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+	spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
new file mode 100644
index 0000000..b235a30
--- /dev/null
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -0,0 +1,394 @@
+/*
+ *  drivers/rtc/rtc-pcf8583.c
+ *
+ *  Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ *  Driver for PCF8583 RTC & RAM chip
+ *
+ *  Converted to the generic RTC susbsystem by G. Liakhovetski (2006)
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/bcd.h>
+
+struct rtc_mem {
+	unsigned int	loc;
+	unsigned int	nr;
+	unsigned char	*data;
+};
+
+struct pcf8583 {
+	struct i2c_client client;
+	struct rtc_device *rtc;
+	unsigned char ctrl;
+};
+
+#define CTRL_STOP	0x80
+#define CTRL_HOLD	0x40
+#define CTRL_32KHZ	0x00
+#define CTRL_MASK	0x08
+#define CTRL_ALARMEN	0x04
+#define CTRL_ALARM	0x02
+#define CTRL_TIMER	0x01
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Module parameters */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver pcf8583_driver;
+
+#define get_ctrl(x)    ((struct pcf8583 *)i2c_get_clientdata(x))->ctrl
+#define set_ctrl(x, v) get_ctrl(x) = v
+
+#define CMOS_YEAR	(64 + 128)
+#define CMOS_CHECKSUM	(63)
+
+static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+	unsigned char buf[8], addr[1] = { 1 };
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = addr,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = 6,
+			.buf = buf,
+		}
+	};
+	int ret;
+
+	memset(buf, 0, sizeof(buf));
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret == 2) {
+		dt->tm_year = buf[4] >> 6;
+		dt->tm_wday = buf[5] >> 5;
+
+		buf[4] &= 0x3f;
+		buf[5] &= 0x1f;
+
+		dt->tm_sec = BCD_TO_BIN(buf[1]);
+		dt->tm_min = BCD_TO_BIN(buf[2]);
+		dt->tm_hour = BCD_TO_BIN(buf[3]);
+		dt->tm_mday = BCD_TO_BIN(buf[4]);
+		dt->tm_mon = BCD_TO_BIN(buf[5]);
+	}
+
+	return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
+{
+	unsigned char buf[8];
+	int ret, len = 6;
+
+	buf[0] = 0;
+	buf[1] = get_ctrl(client) | 0x80;
+	buf[2] = 0;
+	buf[3] = BIN_TO_BCD(dt->tm_sec);
+	buf[4] = BIN_TO_BCD(dt->tm_min);
+	buf[5] = BIN_TO_BCD(dt->tm_hour);
+
+	if (datetoo) {
+		len = 8;
+		buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6);
+		buf[7] = BIN_TO_BCD(dt->tm_mon)  | (dt->tm_wday << 5);
+	}
+
+	ret = i2c_master_send(client, (char *)buf, len);
+	if (ret != len)
+		return -EIO;
+
+	buf[1] = get_ctrl(client);
+	ret = i2c_master_send(client, (char *)buf, 2);
+
+	return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+	*ctrl = get_ctrl(client);
+	return 0;
+}
+
+static int pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+	unsigned char buf[2];
+
+	buf[0] = 0;
+	buf[1] = *ctrl;
+	set_ctrl(client, *ctrl);
+
+	return i2c_master_send(client, (char *)buf, 2);
+}
+
+static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+	unsigned char addr[1];
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = addr,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = mem->nr,
+			.buf = mem->data,
+		}
+	};
+
+	if (mem->loc < 8)
+		return -EINVAL;
+
+	addr[0] = mem->loc;
+
+	return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+	unsigned char addr[1];
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = addr,
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_NOSTART,
+			.len = mem->nr,
+			.buf = mem->data,
+		}
+	};
+
+	if (mem->loc < 8)
+		return -EINVAL;
+
+	addr[0] = mem->loc;
+
+	return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	unsigned char ctrl, year[2];
+	struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year };
+	int real_year, year_offset, err;
+
+	/*
+	 * Ensure that the RTC is running.
+	 */
+	pcf8583_get_ctrl(client, &ctrl);
+	if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
+		unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD);
+
+		printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
+		       ctrl, new_ctrl);
+
+		if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
+			return err;
+	}
+
+	if (pcf8583_get_datetime(client, tm) ||
+	    pcf8583_read_mem(client, &mem))
+		return -EIO;
+
+	real_year = year[0];
+
+	/*
+	 * The RTC year holds the LSB two bits of the current
+	 * year, which should reflect the LSB two bits of the
+	 * CMOS copy of the year.  Any difference indicates
+	 * that we have to correct the CMOS version.
+	 */
+	year_offset = tm->tm_year - (real_year & 3);
+	if (year_offset < 0)
+		/*
+		 * RTC year wrapped.  Adjust it appropriately.
+		 */
+		year_offset += 4;
+
+	tm->tm_year = real_year + year_offset + year[1] * 100;
+
+	return 0;
+}
+
+static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	unsigned char year[2], chk;
+	struct rtc_mem cmos_year  = { CMOS_YEAR, sizeof(year), year };
+	struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+	int ret;
+
+	/*
+	 * The RTC's own 2-bit year must reflect the least
+	 * significant two bits of the CMOS year.
+	 */
+
+	ret = pcf8583_set_datetime(client, tm, 1);
+	if (ret)
+		return ret;
+
+	ret = pcf8583_read_mem(client, &cmos_check);
+	if (ret)
+		return ret;
+
+	ret = pcf8583_read_mem(client, &cmos_year);
+	if (ret)
+		return ret;
+
+	chk -= year[1] + year[0];
+
+	year[1] = tm->tm_year / 100;
+	year[0] = tm->tm_year % 100;
+
+	chk += year[1] + year[0];
+
+	ret = pcf8583_write_mem(client, &cmos_year);
+
+	if (ret)
+		return ret;
+
+	ret = pcf8583_write_mem(client, &cmos_check);
+
+	return ret;
+}
+
+static struct rtc_class_ops pcf8583_rtc_ops = {
+	.read_time	= pcf8583_rtc_read_time,
+	.set_time	= pcf8583_rtc_set_time,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind);
+
+static int pcf8583_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, pcf8583_probe);
+}
+
+static int pcf8583_detach(struct i2c_client *client)
+{
+	int err;
+	struct pcf8583 *pcf = i2c_get_clientdata(client);
+	struct rtc_device *rtc = pcf->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(pcf);
+	return 0;
+}
+
+static struct i2c_driver pcf8583_driver = {
+	.driver = {
+		.name	= "pcf8583",
+	},
+	.id		= I2C_DRIVERID_PCF8583,
+	.attach_adapter	= pcf8583_attach,
+	.detach_client	= pcf8583_detach,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct pcf8583 *pcf;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+	unsigned char buf[1], ad[1] = { 0 };
+	int err;
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.len = 1,
+			.buf = ad,
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.len = 1,
+			.buf = buf,
+		}
+	};
+
+	pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
+	if (!pcf)
+		return -ENOMEM;
+
+	client = &pcf->client;
+
+	client->addr		= addr;
+	client->adapter	= adap;
+	client->driver	= &pcf8583_driver;
+
+	strlcpy(client->name, pcf8583_driver.driver.name, I2C_NAME_SIZE);
+
+	if (i2c_transfer(client->adapter, msgs, 2) != 2) {
+		err = -EIO;
+		goto exit_kfree;
+	}
+
+	err = i2c_attach_client(client);
+
+	if (err)
+		goto exit_kfree;
+
+	rtc = rtc_device_register(pcf8583_driver.driver.name, &client->dev,
+				  &pcf8583_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		goto exit_detach;
+	}
+
+	pcf->rtc = rtc;
+	i2c_set_clientdata(client, pcf);
+	set_ctrl(client, buf[0]);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(pcf);
+
+	return err;
+}
+
+static __init int pcf8583_init(void)
+{
+	return i2c_add_driver(&pcf8583_driver);
+}
+
+static __exit void pcf8583_exit(void)
+{
+	i2c_del_driver(&pcf8583_driver);
+}
+
+module_init(pcf8583_init);
+module_exit(pcf8583_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
new file mode 100644
index 0000000..ee53863
--- /dev/null
+++ b/drivers/rtc/rtc-pl031.c
@@ -0,0 +1,233 @@
+/*
+ * drivers/rtc/rtc-pl031.c
+ *
+ * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2006 (c) MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+/*
+ * Register definitions
+ */
+#define	RTC_DR		0x00	/* Data read register */
+#define	RTC_MR		0x04	/* Match register */
+#define	RTC_LR		0x08	/* Data load register */
+#define	RTC_CR		0x0c	/* Control register */
+#define	RTC_IMSC	0x10	/* Interrupt mask and set register */
+#define	RTC_RIS		0x14	/* Raw interrupt status register */
+#define	RTC_MIS		0x18	/* Masked interrupt status register */
+#define	RTC_ICR		0x1c	/* Interrupt clear register */
+
+struct pl031_local {
+	struct rtc_device *rtc;
+	void __iomem *base;
+};
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct rtc_device *rtc = dev_id;
+
+	rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+
+	return IRQ_HANDLED;
+}
+
+static int pl031_open(struct device *dev)
+{
+	/*
+	 * We request IRQ in pl031_probe, so nothing to do here...
+	 */
+	return 0;
+}
+
+static void pl031_release(struct device *dev)
+{
+}
+
+static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+	struct pl031_local *ldata = dev_get_drvdata(dev);
+
+	switch (cmd) {
+	case RTC_AIE_OFF:
+		__raw_writel(1, ldata->base + RTC_MIS);
+		return 0;
+	case RTC_AIE_ON:
+		__raw_writel(0, ldata->base + RTC_MIS);
+		return 0;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static int pl031_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct pl031_local *ldata = dev_get_drvdata(dev);
+
+	rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm);
+
+	return 0;
+}
+
+static int pl031_set_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long time;
+	struct pl031_local *ldata = dev_get_drvdata(dev);
+
+	rtc_tm_to_time(tm, &time);
+	__raw_writel(time, ldata->base + RTC_LR);
+
+	return 0;
+}
+
+static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct pl031_local *ldata = dev_get_drvdata(dev);
+
+	rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time);
+	alarm->pending = __raw_readl(ldata->base + RTC_RIS);
+	alarm->enabled = __raw_readl(ldata->base + RTC_IMSC);
+
+	return 0;
+}
+
+static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct pl031_local *ldata = dev_get_drvdata(dev);
+	unsigned long time;
+
+	rtc_tm_to_time(&alarm->time, &time);
+
+	__raw_writel(time, ldata->base + RTC_MR);
+	__raw_writel(!alarm->enabled, ldata->base + RTC_MIS);
+
+	return 0;
+}
+
+static struct rtc_class_ops pl031_ops = {
+	.open = pl031_open,
+	.release = pl031_release,
+	.ioctl = pl031_ioctl,
+	.read_time = pl031_read_time,
+	.set_time = pl031_set_time,
+	.read_alarm = pl031_read_alarm,
+	.set_alarm = pl031_set_alarm,
+};
+
+static int pl031_remove(struct amba_device *adev)
+{
+	struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
+
+	if (ldata) {
+		dev_set_drvdata(&adev->dev, NULL);
+		free_irq(adev->irq[0], ldata->rtc);
+		rtc_device_unregister(ldata->rtc);
+		iounmap(ldata->base);
+		kfree(ldata);
+	}
+
+	return 0;
+}
+
+static int pl031_probe(struct amba_device *adev, void *id)
+{
+	int ret;
+	struct pl031_local *ldata;
+
+
+	ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+	if (!ldata) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	dev_set_drvdata(&adev->dev, ldata);
+
+	ldata->base = ioremap(adev->res.start,
+			      adev->res.end - adev->res.start + 1);
+	if (!ldata->base) {
+		ret = -ENOMEM;
+		goto out_no_remap;
+	}
+
+	if (request_irq(adev->irq[0], pl031_interrupt, SA_INTERRUPT,
+			"rtc-pl031", ldata->rtc)) {
+		ret = -EIO;
+		goto out_no_irq;
+	}
+
+	ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
+					 THIS_MODULE);
+	if (IS_ERR(ldata->rtc)) {
+		ret = PTR_ERR(ldata->rtc);
+		goto out_no_rtc;
+	}
+
+	return 0;
+
+out_no_rtc:
+	free_irq(adev->irq[0], ldata->rtc);
+out_no_irq:
+	iounmap(ldata->base);
+out_no_remap:
+	dev_set_drvdata(&adev->dev, NULL);
+	kfree(ldata);
+out:
+	return ret;
+}
+
+static struct amba_id pl031_ids[] __initdata = {
+	{
+		 .id = 0x00041031,
+	 	.mask = 0x000fffff, },
+	{0, 0},
+};
+
+static struct amba_driver pl031_driver = {
+	.drv = {
+		.name = "rtc-pl031",
+	},
+	.id_table = pl031_ids,
+	.probe = pl031_probe,
+	.remove = pl031_remove,
+};
+
+static int __init pl031_init(void)
+{
+	return amba_driver_register(&pl031_driver);
+}
+
+static void __exit pl031_exit(void)
+{
+	amba_driver_unregister(&pl031_driver);
+}
+
+module_init(pl031_init);
+module_exit(pl031_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
+MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index a997529..ab486fb 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -229,8 +229,6 @@
 		spin_unlock_irq(&sa1100_rtc_lock);
 		return 0;
 	case RTC_PIE_ON:
-		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
-			return -EACCES;
 		spin_lock_irq(&sa1100_rtc_lock);
 		OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
 		OIER |= OIER_E1;
@@ -242,8 +240,6 @@
 	case RTC_IRQP_SET:
 		if (arg < 1 || arg > TIMER_FREQ)
 			return -EINVAL;
-		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
-			return -EACCES;
 		rtc_freq = arg;
 		return 0;
 	}
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
new file mode 100644
index 0000000..a40f400
--- /dev/null
+++ b/drivers/rtc/rtc-v3020.c
@@ -0,0 +1,264 @@
+/* drivers/rtc/rtc-v3020.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * 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.
+ *
+ * Driver for the V3020 RTC
+ *
+ * Changelog:
+ *
+ *  10-May-2006: Raphael Assenat <raph@8d.com>
+ *				- Converted to platform driver
+ *				- Use the generic rtc class
+ *
+ *  ??-???-2004: Someone at Compulab
+ *  			- Initial driver creation.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/bcd.h>
+#include <linux/rtc-v3020.h>
+
+#include <asm/io.h>
+
+#undef DEBUG
+
+struct v3020 {
+	void __iomem *ioaddress;
+	int leftshift;
+	struct rtc_device *rtc;
+};
+
+static void v3020_set_reg(struct v3020 *chip, unsigned char address,
+			unsigned char data)
+{
+	int i;
+	unsigned char tmp;
+
+	tmp = address;
+	for (i = 0; i < 4; i++) {
+		writel((tmp & 1) << chip->leftshift, chip->ioaddress);
+		tmp >>= 1;
+	}
+
+	/* Commands dont have data */
+	if (!V3020_IS_COMMAND(address)) {
+		for (i = 0; i < 8; i++) {
+			writel((data & 1) << chip->leftshift, chip->ioaddress);
+			data >>= 1;
+		}
+	}
+}
+
+static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
+{
+	unsigned int data=0;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		writel((address & 1) << chip->leftshift, chip->ioaddress);
+		address >>= 1;
+	}
+
+	for (i = 0; i < 8; i++) {
+		data >>= 1;
+		if (readl(chip->ioaddress) & (1 << chip->leftshift))
+			data |= 0x80;
+	}
+
+	return data;
+}
+
+static int v3020_read_time(struct device *dev, struct rtc_time *dt)
+{
+	struct v3020 *chip = dev_get_drvdata(dev);
+	int tmp;
+
+	/* Copy the current time to ram... */
+	v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0);
+
+	/* ...and then read constant values. */
+	tmp = v3020_get_reg(chip, V3020_SECONDS);
+	dt->tm_sec	= BCD2BIN(tmp);
+	tmp = v3020_get_reg(chip, V3020_MINUTES);
+	dt->tm_min	= BCD2BIN(tmp);
+	tmp = v3020_get_reg(chip, V3020_HOURS);
+	dt->tm_hour	= BCD2BIN(tmp);
+	tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
+	dt->tm_mday	= BCD2BIN(tmp);
+	tmp = v3020_get_reg(chip, V3020_MONTH);
+	dt->tm_mon	= BCD2BIN(tmp);
+	tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
+	dt->tm_wday	= BCD2BIN(tmp);
+	tmp = v3020_get_reg(chip, V3020_YEAR);
+	dt->tm_year = BCD2BIN(tmp)+100;
+
+#ifdef DEBUG
+	printk("\n%s : Read RTC values\n",__FUNCTION__);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_year: %i\n",dt->tm_year);
+	printk("tm_mon : %i\n",dt->tm_mon);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+	return 0;
+}
+
+
+static int v3020_set_time(struct device *dev, struct rtc_time *dt)
+{
+	struct v3020 *chip = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+	printk("\n%s : Setting RTC values\n",__FUNCTION__);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+	printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+	/* Write all the values to ram... */
+	v3020_set_reg(chip, V3020_SECONDS, 	BIN2BCD(dt->tm_sec));
+	v3020_set_reg(chip, V3020_MINUTES, 	BIN2BCD(dt->tm_min));
+	v3020_set_reg(chip, V3020_HOURS, 	BIN2BCD(dt->tm_hour));
+	v3020_set_reg(chip, V3020_MONTH_DAY,	BIN2BCD(dt->tm_mday));
+	v3020_set_reg(chip, V3020_MONTH, 	BIN2BCD(dt->tm_mon));
+	v3020_set_reg(chip, V3020_WEEK_DAY, 	BIN2BCD(dt->tm_wday));
+	v3020_set_reg(chip, V3020_YEAR, 	BIN2BCD(dt->tm_year % 100));
+
+	/* ...and set the clock. */
+	v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
+
+	/* Compulab used this delay here. I dont know why,
+	 * the datasheet does not specify a delay. */
+	/*mdelay(5);*/
+
+	return 0;
+}
+
+static struct rtc_class_ops v3020_rtc_ops = {
+	.read_time	= v3020_read_time,
+	.set_time	= v3020_set_time,
+};
+
+static int rtc_probe(struct platform_device *pdev)
+{
+	struct v3020_platform_data *pdata = pdev->dev.platform_data;
+	struct v3020 *chip;
+	struct rtc_device *rtc;
+	int retval = -EBUSY;
+	int i;
+	int temp;
+
+	if (pdev->num_resources != 1)
+		return -EBUSY;
+
+	if (pdev->resource[0].flags != IORESOURCE_MEM)
+		return -EBUSY;
+
+	if (pdev == NULL)
+		return -EBUSY;
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->leftshift = pdata->leftshift;
+	chip->ioaddress = ioremap(pdev->resource[0].start, 1);
+	if (chip->ioaddress == NULL)
+		goto err_chip;
+
+	/* Make sure the v3020 expects a communication cycle
+	 * by reading 8 times */
+	for (i = 0; i < 8; i++)
+		temp = readl(chip->ioaddress);
+
+	/* Test chip by doing a write/read sequence
+	 * to the chip ram */
+	v3020_set_reg(chip, V3020_SECONDS, 0x33);
+	if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
+		retval = -ENODEV;
+		goto err_io;
+	}
+
+	/* Make sure frequency measurment mode, test modes, and lock
+	 * are all disabled */
+	v3020_set_reg(chip, V3020_STATUS_0, 0x0);
+
+	dev_info(&pdev->dev, "Chip available at physical address 0x%p,"
+		"data connected to D%d\n",
+		(void*)pdev->resource[0].start,
+		chip->leftshift);
+
+	platform_set_drvdata(pdev, chip);
+
+	rtc = rtc_device_register("v3020",
+				&pdev->dev, &v3020_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		retval = PTR_ERR(rtc);
+		goto err_io;
+	}
+	chip->rtc = rtc;
+
+	return 0;
+
+err_io:
+	iounmap(chip->ioaddress);
+err_chip:
+	kfree(chip);
+
+	return retval;
+}
+
+static int rtc_remove(struct platform_device *dev)
+{
+	struct v3020 *chip = platform_get_drvdata(dev);
+	struct rtc_device *rtc = chip->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	iounmap(chip->ioaddress);
+	kfree(chip);
+
+	return 0;
+}
+
+static struct platform_driver rtc_device_driver = {
+	.probe	= rtc_probe,
+	.remove = rtc_remove,
+	.driver = {
+		.name	= "v3020",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int v3020_init(void)
+{
+	return platform_driver_register(&rtc_device_driver);
+}
+
+static __exit void v3020_exit(void)
+{
+	platform_driver_unregister(&rtc_device_driver);
+}
+
+module_init(v3020_init);
+module_exit(v3020_exit);
+
+MODULE_DESCRIPTION("V3020 RTC");
+MODULE_AUTHOR("Raphael Assenat");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 277596c..33e0292 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -81,7 +81,6 @@
 
 #define RTC_FREQUENCY		32768
 #define MAX_PERIODIC_RATE	6553
-#define MAX_USER_PERIODIC_RATE	64
 
 static void __iomem *rtc1_base;
 static void __iomem *rtc2_base;
@@ -240,9 +239,6 @@
 		if (arg > MAX_PERIODIC_RATE)
 			return -EINVAL;
 
-		if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0)
-			return -EACCES;
-
 		periodic_frequency = arg;
 
 		count = RTC_FREQUENCY;
@@ -263,10 +259,6 @@
 		/* Doesn't support before 1900 */
 		if (arg < 1900)
 			return -EINVAL;
-
-		if (capable(CAP_SYS_TIME) == 0)
-			return -EACCES;
-
 		epoch = arg;
 		break;
 	default:
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index 56fa691..a4c53c1 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -13,6 +13,7 @@
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/sigp.h>
@@ -66,8 +67,6 @@
 }
 #endif
 
-extern void ctrl_alt_del(void);
-
 /* Handler for quiesce event. Start shutdown procedure. */
 static void
 sclp_quiesce_handler(struct evbuf_header *evbuf)
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index f94419b..2eded55 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1140,10 +1140,9 @@
 		}
 	}
 	/* re-insert all entries from the failed_list into ipm_list */
-	list_for_each_entry_safe(ipm, tmp, &failed_list, list) {
-		list_del_init(&ipm->list);
-		list_add_tail(&ipm->list, &card->ipm_list);
-	}
+	list_for_each_entry_safe(ipm, tmp, &failed_list, list)
+		list_move_tail(&ipm->list, &card->ipm_list);
+
 	spin_unlock_irqrestore(&card->ipm_lock, flags);
 }
 
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 4682c8b..909731b 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -167,7 +167,7 @@
  *		initiates adapter recovery which is done
  *		asynchronously
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 int
@@ -203,7 +203,7 @@
  * purpose:	Wrappper for zfcp_erp_adapter_reopen_internal
  *              used to ensure the correct locking
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 int
@@ -469,7 +469,7 @@
  *		initiates Forced Reopen recovery which is done
  *		asynchronously
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 static int
@@ -509,7 +509,7 @@
  * purpose:	Wrappper for zfcp_erp_port_forced_reopen_internal
  *              used to ensure the correct locking
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 int
@@ -536,7 +536,7 @@
  *		initiates Reopen recovery which is done
  *		asynchronously
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 static int
@@ -605,7 +605,7 @@
  *		initiates Reopen recovery which is done
  *		asynchronously
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 static int
@@ -1805,7 +1805,7 @@
  * purpose:	Wrappper for zfcp_erp_port_reopen_all_internal
  *              used to ensure the correct locking
  *
- * returns:	0	- initiated action succesfully
+ * returns:	0	- initiated action successfully
  *		<0	- failed to initiate action
  */
 int
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index 5bf3dd9..21737b7 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -755,7 +755,7 @@
 
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_name, WD_OBPNAME))
+			if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
 				goto ebus_done;
 		}
 	}
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 5ae684c..31b8a5f 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -71,7 +71,6 @@
 	if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size)
 		size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT));
 
-	vma->vm_flags |= (VM_SHM | VM_LOCKED);
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index cf5b476..d7e4bb4 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -29,8 +29,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  */
 
-#define PROMLIB_INTERNAL
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -39,10 +37,10 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/openpromio.h>
@@ -51,15 +49,20 @@
 #include <asm/pbm.h>
 #endif
 
+MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost  (ecd@skynet.be)");
+MODULE_DESCRIPTION("OPENPROM Configuration Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
 /* Private data kept by the driver for each descriptor. */
 typedef struct openprom_private_data
 {
-	int current_node;	/* Current node for SunOS ioctls. */
-	int lastnode;		/* Last valid node used by BSD ioctls. */
+	struct device_node *current_node; /* Current node for SunOS ioctls. */
+	struct device_node *lastnode; /* Last valid node used by BSD ioctls. */
 } DATA;
 
 /* ID of the PROM node containing all of the EEPROM options. */
-static int options_node = 0;
+static struct device_node *options_node;
 
 /*
  * Copy an openpromio structure into kernel space from user space.
@@ -87,9 +90,8 @@
 	if (bufsize > OPROMMAXPARAM)
 		bufsize = OPROMMAXPARAM;
 
-	if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
+	if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
 		return -ENOMEM;
-	memset(*opp_p, 0, sizeof(int) + bufsize + 1);
 
 	if (copy_from_user(&(*opp_p)->oprom_array,
 			   &info->oprom_array, bufsize)) {
@@ -107,10 +109,9 @@
 	if (!info || !opp_p)
 		return -EFAULT;
 
-	if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
+	if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
 		return -ENOMEM;
 
-	memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1);
 	(*opp_p)->oprom_size = 0;
 
 	n = bufsize = 0;
@@ -140,16 +141,164 @@
 	return 0;
 }
 
+static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
+{
+	void *pval;
+	int len;
+
+	pval = of_get_property(dp, op->oprom_array, &len);
+	if (!pval || len <= 0 || len > bufsize)
+		return copyout(argp, op, sizeof(int));
+
+	memcpy(op->oprom_array, pval, len);
+	op->oprom_array[len] = '\0';
+	op->oprom_size = len;
+
+	return copyout(argp, op, sizeof(int) + bufsize);
+}
+
+static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
+{
+	struct property *prop;
+	int len;
+
+	if (op->oprom_array[0] == '\0') {
+		prop = dp->properties;
+		if (!prop)
+			return copyout(argp, op, sizeof(int));
+		len = strlen(prop->name);
+	} else {
+		prop = of_find_property(dp, op->oprom_array, NULL);
+
+		if (!prop ||
+		    !prop->next ||
+		    (len = strlen(prop->next->name)) + 1 > bufsize)
+			return copyout(argp, op, sizeof(int));
+
+		prop = prop->next;
+	}
+
+	memcpy(op->oprom_array, prop->name, len);
+	op->oprom_array[len] = '\0';
+	op->oprom_size = ++len;
+
+	return copyout(argp, op, sizeof(int) + bufsize);
+}
+
+static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize)
+{
+	char *buf = op->oprom_array + strlen(op->oprom_array) + 1;
+	int len = op->oprom_array + bufsize - buf;
+
+	return of_set_property(options_node, op->oprom_array, buf, len);
+}
+
+static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+	phandle ph;
+
+	BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
+
+	if (bufsize < sizeof(phandle))
+		return -EINVAL;
+
+	ph = *((int *) op->oprom_array);
+	if (ph) {
+		dp = of_find_node_by_phandle(ph);
+		if (!dp)
+			return -EINVAL;
+
+		switch (cmd) {
+		case OPROMNEXT:
+			dp = dp->sibling;
+			break;
+
+		case OPROMCHILD:
+			dp = dp->child;
+			break;
+
+		case OPROMSETCUR:
+		default:
+			break;
+		};
+	} else {
+		/* Sibling of node zero is the root node.  */
+		if (cmd != OPROMNEXT)
+			return -EINVAL;
+
+		dp = of_find_node_by_path("/");
+	}
+
+	ph = 0;
+	if (dp)
+		ph = dp->node;
+
+	data->current_node = dp;
+	*((int *) op->oprom_array) = ph;
+	op->oprom_size = sizeof(phandle);
+
+	return copyout(argp, op, bufsize + sizeof(int));
+}
+
+static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+	int err = -EINVAL;
+
+	if (bufsize >= 2*sizeof(int)) {
+#ifdef CONFIG_PCI
+		struct pci_dev *pdev;
+		struct pcidev_cookie *pcp;
+		pdev = pci_find_slot (((int *) op->oprom_array)[0],
+				      ((int *) op->oprom_array)[1]);
+
+		pcp = pdev->sysdata;
+		if (pcp != NULL) {
+			dp = pcp->prom_node;
+			data->current_node = dp;
+			*((int *)op->oprom_array) = dp->node;
+			op->oprom_size = sizeof(int);
+			err = copyout(argp, op, bufsize + sizeof(int));
+		}
+#endif
+	}
+
+	return err;
+}
+
+static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+	dp = of_find_node_by_path(op->oprom_array);
+	data->current_node = dp;
+	*((int *)op->oprom_array) = dp->node;
+	op->oprom_size = sizeof(int);
+
+	return copyout(argp, op, bufsize + sizeof(int));
+}
+
+static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize)
+{
+	char *buf = saved_command_line;
+	int len = strlen(buf);
+
+	if (len > bufsize)
+		return -EINVAL;
+
+	strcpy(op->oprom_array, buf);
+	op->oprom_size = len;
+
+	return copyout(argp, op, bufsize + sizeof(int));
+}
+
 /*
  *	SunOS and Solaris /dev/openprom ioctl calls.
  */
 static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
-				unsigned int cmd, unsigned long arg, int node)
+				unsigned int cmd, unsigned long arg,
+				struct device_node *dp)
 {
-	DATA *data = (DATA *) file->private_data;
-	char buffer[OPROMMAXPARAM+1], *buf;
+	DATA *data = file->private_data;
 	struct openpromio *opp;
-	int bufsize, len, error = 0;
+	int bufsize, error = 0;
 	static int cnt;
 	void __user *argp = (void __user *)arg;
 
@@ -164,119 +313,35 @@
 	switch (cmd) {
 	case OPROMGETOPT:
 	case OPROMGETPROP:
-		len = prom_getproplen(node, opp->oprom_array);
-
-		if (len <= 0 || len > bufsize) {
-			error = copyout(argp, opp, sizeof(int));
-			break;
-		}
-
-		len = prom_getproperty(node, opp->oprom_array, buffer, bufsize);
-
-		memcpy(opp->oprom_array, buffer, len);
-		opp->oprom_array[len] = '\0';
-		opp->oprom_size = len;
-
-		error = copyout(argp, opp, sizeof(int) + bufsize);
+		error = opromgetprop(argp, dp, opp, bufsize);
 		break;
 
 	case OPROMNXTOPT:
 	case OPROMNXTPROP:
-		buf = prom_nextprop(node, opp->oprom_array, buffer);
-
-		len = strlen(buf);
-		if (len == 0 || len + 1 > bufsize) {
-			error = copyout(argp, opp, sizeof(int));
-			break;
-		}
-
-		memcpy(opp->oprom_array, buf, len);
-		opp->oprom_array[len] = '\0';
-		opp->oprom_size = ++len;
-
-		error = copyout(argp, opp, sizeof(int) + bufsize);
+		error = opromnxtprop(argp, dp, opp, bufsize);
 		break;
 
 	case OPROMSETOPT:
 	case OPROMSETOPT2:
-		buf = opp->oprom_array + strlen(opp->oprom_array) + 1;
-		len = opp->oprom_array + bufsize - buf;
-
-		error = prom_setprop(options_node, opp->oprom_array,
-				     buf, len);
-
-		if (error < 0)
-			error = -EINVAL;
+		error = opromsetopt(dp, opp, bufsize);
 		break;
 
 	case OPROMNEXT:
 	case OPROMCHILD:
 	case OPROMSETCUR:
-		if (bufsize < sizeof(int)) {
-			error = -EINVAL;
-			break;
-		}
-
-		node = *((int *) opp->oprom_array);
-
-		switch (cmd) {
-		case OPROMNEXT: node = __prom_getsibling(node); break;
-		case OPROMCHILD: node = __prom_getchild(node); break;
-		case OPROMSETCUR: break;
-		}
-
-		data->current_node = node;
-		*((int *)opp->oprom_array) = node;
-		opp->oprom_size = sizeof(int);
-
-		error = copyout(argp, opp, bufsize + sizeof(int));
+		error = opromnext(argp, cmd, dp, opp, bufsize, data);
 		break;
 
 	case OPROMPCI2NODE:
-		error = -EINVAL;
-
-		if (bufsize >= 2*sizeof(int)) {
-#ifdef CONFIG_PCI
-			struct pci_dev *pdev;
-			struct pcidev_cookie *pcp;
-			pdev = pci_find_slot (((int *) opp->oprom_array)[0],
-					      ((int *) opp->oprom_array)[1]);
-
-			pcp = pdev->sysdata;
-			if (pcp != NULL) {
-				node = pcp->prom_node->node;
-				data->current_node = node;
-				*((int *)opp->oprom_array) = node;
-				opp->oprom_size = sizeof(int);
-				error = copyout(argp, opp, bufsize + sizeof(int));
-			}
-#endif
-		}
+		error = oprompci2node(argp, dp, opp, bufsize, data);
 		break;
 
 	case OPROMPATH2NODE:
-		node = prom_finddevice(opp->oprom_array);
-		data->current_node = node;
-		*((int *)opp->oprom_array) = node;
-		opp->oprom_size = sizeof(int);
-
-		error = copyout(argp, opp, bufsize + sizeof(int));
+		error = oprompath2node(argp, dp, opp, bufsize, data);
 		break;
 
 	case OPROMGETBOOTARGS:
-		buf = saved_command_line;
-
-		len = strlen(buf);
-
-		if (len > bufsize) {
-			error = -EINVAL;
-			break;
-		}
-
-		strcpy(opp->oprom_array, buf);
-		opp->oprom_size = len;
-
-		error = copyout(argp, opp, bufsize + sizeof(int));
+		error = opromgetbootargs(argp, opp, bufsize);
 		break;
 
 	case OPROMU2P:
@@ -297,25 +362,14 @@
 	return error;
 }
 
-
-/* Return nonzero if a specific node is in the PROM device tree. */
-static int intree(int root, int node)
+static struct device_node *get_node(phandle n, DATA *data)
 {
-	for (; root != 0; root = prom_getsibling(root))
-		if (root == node || intree(prom_getchild(root),node))
-			return 1;
-	return 0;
-}
+	struct device_node *dp = of_find_node_by_phandle(n);
 
-/* Return nonzero if a specific node is "valid". */
-static int goodnode(int n, DATA *data)
-{
-	if (n == data->lastnode || n == prom_root_node || n == options_node)
-		return 1;
-	if (n == 0 || n == -1 || !intree(prom_root_node,n))
-		return 0;
-	data->lastnode = n;
-	return 1;
+	if (dp)
+		data->lastnode = dp;
+
+	return dp;
 }
 
 /* Copy in a whole string from userspace into kernelspace. */
@@ -330,7 +384,7 @@
 	if (!tmp)
 		return -ENOMEM;
 
-	if(copy_from_user(tmp, user, len)) {
+	if (copy_from_user(tmp, user, len)) {
 		kfree(tmp);
 		return -EFAULT;
 	}
@@ -345,162 +399,187 @@
 /*
  *	NetBSD /dev/openprom ioctl calls.
  */
+static int opiocget(void __user *argp, DATA *data)
+{
+	struct opiocdesc op;
+	struct device_node *dp;
+	char *str;
+	void *pval;
+	int err, len;
+
+	if (copy_from_user(&op, argp, sizeof(op)))
+		return -EFAULT;
+
+	dp = get_node(op.op_nodeid, data);
+
+	err = copyin_string(op.op_name, op.op_namelen, &str);
+	if (err)
+		return err;
+
+	pval = of_get_property(dp, str, &len);
+	err = 0;
+	if (!pval || len > op.op_buflen) {
+		err = -EINVAL;
+	} else {
+		op.op_buflen = len;
+		if (copy_to_user(argp, &op, sizeof(op)) ||
+		    copy_to_user(op.op_buf, pval, len))
+			err = -EFAULT;
+	}
+	kfree(str);
+
+	return err;
+}
+
+static int opiocnextprop(void __user *argp, DATA *data)
+{
+	struct opiocdesc op;
+	struct device_node *dp;
+	struct property *prop;
+	char *str;
+	int err, len;
+
+	if (copy_from_user(&op, argp, sizeof(op)))
+		return -EFAULT;
+
+	dp = get_node(op.op_nodeid, data);
+	if (!dp)
+		return -EINVAL;
+
+	err = copyin_string(op.op_name, op.op_namelen, &str);
+	if (err)
+		return err;
+
+	if (str[0] == '\0') {
+		prop = dp->properties;
+	} else {
+		prop = of_find_property(dp, str, NULL);
+		if (prop)
+			prop = prop->next;
+	}
+	kfree(str);
+
+	if (!prop)
+		len = 0;
+	else
+		len = prop->length;
+
+	if (len > op.op_buflen)
+		len = op.op_buflen;
+
+	if (copy_to_user(argp, &op, sizeof(op)))
+		return -EFAULT;
+
+	if (len &&
+	    copy_to_user(op.op_buf, prop->value, len))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int opiocset(void __user *argp, DATA *data)
+{
+	struct opiocdesc op;
+	struct device_node *dp;
+	char *str, *tmp;
+	int err;
+
+	if (copy_from_user(&op, argp, sizeof(op)))
+		return -EFAULT;
+
+	dp = get_node(op.op_nodeid, data);
+	if (!dp)
+		return -EINVAL;
+
+	err = copyin_string(op.op_name, op.op_namelen, &str);
+	if (err)
+		return err;
+
+	err = copyin_string(op.op_buf, op.op_buflen, &tmp);
+	if (err) {
+		kfree(str);
+		return err;
+	}
+
+	err = of_set_property(dp, str, tmp, op.op_buflen);
+
+	kfree(str);
+	kfree(tmp);
+
+	return err;
+}
+
+static int opiocgetnext(unsigned int cmd, void __user *argp)
+{
+	struct device_node *dp;
+	phandle nd;
+
+	BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
+
+	if (copy_from_user(&nd, argp, sizeof(phandle)))
+		return -EFAULT;
+
+	if (nd == 0) {
+		if (cmd != OPIOCGETNEXT)
+			return -EINVAL;
+		dp = of_find_node_by_path("/");
+	} else {
+		dp = of_find_node_by_phandle(nd);
+		nd = 0;
+		if (dp) {
+			if (cmd == OPIOCGETNEXT)
+				dp = dp->sibling;
+			else
+				dp = dp->child;
+		}
+	}
+	if (dp)
+		nd = dp->node;
+	if (copy_to_user(argp, &nd, sizeof(phandle)))
+		return -EFAULT;
+
+	return 0;
+}
+
 static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
 			      unsigned int cmd, unsigned long arg)
 {
 	DATA *data = (DATA *) file->private_data;
 	void __user *argp = (void __user *)arg;
-	struct opiocdesc op;
-	int error, node, len;
-	char *str, *tmp;
-	char buffer[64];
-	static int cnt;
+	int err;
 
 	switch (cmd) {
 	case OPIOCGET:
-		if (copy_from_user(&op, argp, sizeof(op)))
-			return -EFAULT;
-
-		if (!goodnode(op.op_nodeid,data))
-			return -EINVAL;
-
-		error = copyin_string(op.op_name, op.op_namelen, &str);
-		if (error)
-			return error;
-
-		len = prom_getproplen(op.op_nodeid,str);
-
-		if (len > op.op_buflen) {
-			kfree(str);
-			return -ENOMEM;
-		}
-
-		op.op_buflen = len;
-
-		if (len <= 0) {
-			kfree(str);
-			/* Verified by the above copy_from_user */
-			if (__copy_to_user(argp, &op,
-				       sizeof(op)))
-				return -EFAULT;
-			return 0;
-		}
-
-		tmp = kmalloc(len + 1, GFP_KERNEL);
-		if (!tmp) {
-			kfree(str);
-			return -ENOMEM;
-		}
-
-		cnt = prom_getproperty(op.op_nodeid, str, tmp, len);
-		if (cnt <= 0) {
-			error = -EINVAL;
-		} else {
-			tmp[len] = '\0';
-
-			if (__copy_to_user(argp, &op, sizeof(op)) != 0 ||
-			    copy_to_user(op.op_buf, tmp, len) != 0)
-				error = -EFAULT;
-		}
-
-		kfree(tmp);
-		kfree(str);
-
-		return error;
+		err = opiocget(argp, data);
+		break;
 
 	case OPIOCNEXTPROP:
-		if (copy_from_user(&op, argp, sizeof(op)))
-			return -EFAULT;
-
-		if (!goodnode(op.op_nodeid,data))
-			return -EINVAL;
-
-		error = copyin_string(op.op_name, op.op_namelen, &str);
-		if (error)
-			return error;
-
-		tmp = prom_nextprop(op.op_nodeid,str,buffer);
-
-		if (tmp) {
-			len = strlen(tmp);
-			if (len > op.op_buflen)
-				len = op.op_buflen;
-			else
-				op.op_buflen = len;
-		} else {
-			len = op.op_buflen = 0;
-		}
-
-		if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) {
-			kfree(str);
-			return -EFAULT;
-		}
-
-		if (!access_ok(VERIFY_WRITE, op.op_buf, len)) {
-			kfree(str);
-			return -EFAULT;
-		}
-
-		error = __copy_to_user(argp, &op, sizeof(op));
-		if (!error) error = __copy_to_user(op.op_buf, tmp, len);
-
-		kfree(str);
-
-		return error;
+		err = opiocnextprop(argp, data);
+		break;
 
 	case OPIOCSET:
-		if (copy_from_user(&op, argp, sizeof(op)))
-			return -EFAULT;
-
-		if (!goodnode(op.op_nodeid,data))
-			return -EINVAL;
-
-		error = copyin_string(op.op_name, op.op_namelen, &str);
-		if (error)
-			return error;
-
-		error = copyin_string(op.op_buf, op.op_buflen, &tmp);
-		if (error) {
-			kfree(str);
-			return error;
-		}
-
-		len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1);
-
-		if (len != op.op_buflen)
-			return -EINVAL;
-
-		kfree(str);
-		kfree(tmp);
-
-		return 0;
+		err = opiocset(argp, data);
+		break;
 
 	case OPIOCGETOPTNODE:
-		if (copy_to_user(argp, &options_node, sizeof(int)))
+		BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
+
+		if (copy_to_user(argp, &options_node->node, sizeof(phandle)))
 			return -EFAULT;
+
 		return 0;
 
 	case OPIOCGETNEXT:
 	case OPIOCGETCHILD:
-		if (copy_from_user(&node, argp, sizeof(int)))
-			return -EFAULT;
-
-		if (cmd == OPIOCGETNEXT)
-			node = __prom_getsibling(node);
-		else
-			node = __prom_getchild(node);
-
-		if (__copy_to_user(argp, &node, sizeof(int)))
-			return -EFAULT;
-
-		return 0;
+		err = opiocgetnext(cmd, argp);
+		break;
 
 	default:
-		if (cnt++ < 10)
-			printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd);
 		return -EINVAL;
 
-	}
+	};
+
+	return err;
 }
 
 
@@ -511,7 +590,6 @@
 			  unsigned int cmd, unsigned long arg)
 {
 	DATA *data = (DATA *) file->private_data;
-	static int cnt;
 
 	switch (cmd) {
 	case OPROMGETOPT:
@@ -563,10 +641,8 @@
 		return openprom_bsd_ioctl(inode,file,cmd,arg);
 
 	default:
-		if (cnt++ < 10)
-			printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
 		return -EINVAL;
-	}
+	};
 }
 
 static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
@@ -594,9 +670,7 @@
 	case OPROMSETCUR:
 	case OPROMPCI2NODE:
 	case OPROMPATH2NODE:
-		lock_kernel();
 		rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg);
-		lock_kernel();
 		break;
 	}
 
@@ -607,13 +681,13 @@
 {
 	DATA *data;
 
-	data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL);
+	data = kmalloc(sizeof(DATA), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
-	data->current_node = prom_root_node;
-	data->lastnode = prom_root_node;
-	file->private_data = (void *)data;
+	data->current_node = of_find_node_by_path("/");
+	data->lastnode = data->current_node;
+	file->private_data = (void *) data;
 
 	return 0;
 }
@@ -634,24 +708,30 @@
 };
 
 static struct miscdevice openprom_dev = {
-	SUN_OPENPROM_MINOR, "openprom", &openprom_fops
+	.minor		= SUN_OPENPROM_MINOR,
+	.name		= "openprom",
+	.fops		= &openprom_fops,
 };
 
 static int __init openprom_init(void)
 {
-	int error;
+	struct device_node *dp;
+	int err;
 
-	error = misc_register(&openprom_dev);
-	if (error) {
-		printk(KERN_ERR "openprom: unable to get misc minor\n");
-		return error;
+	err = misc_register(&openprom_dev);
+	if (err)
+		return err;
+
+	dp = of_find_node_by_path("/");
+	dp = dp->child;
+	while (dp) {
+		if (!strcmp(dp->name, "options"))
+			break;
+		dp = dp->sibling;
 	}
+	options_node = dp;
 
-	options_node = prom_getchild(prom_root_node);
-	options_node = prom_searchsiblings(options_node,"options");
-
-	if (options_node == 0 || options_node == -1) {
-		printk(KERN_ERR "openprom: unable to find options node\n");
+	if (!options_node) {
 		misc_deregister(&openprom_dev);
 		return -EIO;
 	}
@@ -666,4 +746,3 @@
 
 module_init(openprom_init);
 module_exit(openprom_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c
index d1babff..2a9cc82 100644
--- a/drivers/sbus/char/riowatchdog.c
+++ b/drivers/sbus/char/riowatchdog.c
@@ -211,7 +211,7 @@
 
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_name, "bbc"))
+			if (!strcmp(edev->ofdev.node->name, "bbc"))
 				goto found_bbc;
 		}
 	}
@@ -238,7 +238,7 @@
 
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_name, RIOWD_NAME))
+			if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
 				goto ebus_done;
 		}
 	}
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index dfdd6be..ddcd330 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -623,7 +623,7 @@
 		map_size = sizeof(struct vfc_regs);
 
 	vma->vm_flags |=
-		(VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
+		(VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
 	map_offset = (unsigned int) (long)dev->phys_regs;
 	ret = io_remap_pfn_range(vma, vma->vm_start,
 				  MK_IOSPACE_PFN(dev->which_io,
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 44728ae..c84b02a 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1169,7 +1169,7 @@
 	  you do not have this SCSI card, so say N.
 
 config SCSI_NCR53C8XX_DEFAULT_TAGS
-	int "  default tagged command queue depth"
+	int "default tagged command queue depth"
 	depends on SCSI_ZALON || SCSI_NCR_Q720
 	default "8"
 	---help---
@@ -1195,7 +1195,7 @@
 	  There is no safe option other than using good SCSI devices.
 
 config SCSI_NCR53C8XX_MAX_TAGS
-	int "  maximum number of queued commands"
+	int "maximum number of queued commands"
 	depends on SCSI_ZALON || SCSI_NCR_Q720
 	default "32"
 	---help---
@@ -1212,7 +1212,7 @@
 	  There is no safe option and the default answer is recommended.
 
 config SCSI_NCR53C8XX_SYNC
-	int "  synchronous transfers frequency in MHz"
+	int "synchronous transfers frequency in MHz"
 	depends on SCSI_ZALON || SCSI_NCR_Q720
 	default "20"
 	---help---
@@ -1246,7 +1246,7 @@
 	  terminations and SCSI conformant devices.
 
 config SCSI_NCR53C8XX_PROFILE
-	bool "  enable profiling"
+	bool "enable profiling"
 	depends on SCSI_ZALON || SCSI_NCR_Q720
 	help
 	  This option allows you to enable profiling information gathering.
@@ -1257,7 +1257,7 @@
 	  The normal answer therefore is N.
 
 config SCSI_NCR53C8XX_NO_DISCONNECT
-	bool "  not allow targets to disconnect"
+	bool "not allow targets to disconnect"
 	depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
 	help
 	  This option is only provided for safety if you suspect some SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 84d5463..ebd0cf0 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_SCSI_SAS_ATTRS)	+= scsi_transport_sas.o
 
 obj-$(CONFIG_ISCSI_TCP) 	+= libiscsi.o	iscsi_tcp.o
+obj-$(CONFIG_INFINIBAND_ISER) 	+= libiscsi.o
 obj-$(CONFIG_SCSI_AMIGA7XX)	+= amiga7xx.o	53c7xx.o
 obj-$(CONFIG_A3000_SCSI)	+= a3000.o	wd33c93.o
 obj-$(CONFIG_A2091_SCSI)	+= a2091.o	wd33c93.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index fa57e0b..75f2f7a 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -500,7 +500,7 @@
 /* 
  * Function : int should_disconnect (unsigned char cmd)
  *
- * Purpose : decide weather a command would normally disconnect or 
+ * Purpose : decide whether a command would normally disconnect or 
  *      not, since if it won't disconnect we should go to sleep.
  *
  * Input : cmd - opcode of SCSI command
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 35b0a6e..7cea514 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -104,8 +104,11 @@
 	 * always true on real computers. It also has some slight problems
 	 * with the GART on x86-64. I've btw never tried DMA from PCI space
 	 * on this platform but don't be surprised if its problematic.
+	 * [AK: something is very very wrong when a driver tests this symbol.
+ 	 *  Someone should figure out what the comment writer really meant here and fix
+	 *  the code. Or just remove that bad code. ]
 	 */
-#ifndef CONFIG_GART_IOMMU
+#ifndef CONFIG_IOMMU
 	if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) {
 		init->HostPhysMemPages = 
 			cpu_to_le32(num_physpages << (PAGE_SHIFT-12));
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2a41963..dd9fb3d 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -12374,7 +12374,7 @@
                 ASC_PRINT1(
 "AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
         } else {
-                ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM.");
+                ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
         }
     }
     return (warn_code);
@@ -17316,7 +17316,7 @@
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void
+void __init
 AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 {
     ushort *wbuf;
@@ -17383,7 +17383,7 @@
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void
+void __init
 AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
                        ADVEEP_38C0800_CONFIG *cfg_buf)
 {
@@ -17451,7 +17451,7 @@
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-void
+void __init
 AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
                        ADVEEP_38C1600_CONFIG *cfg_buf)
 {
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 1832452..58b0748 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -3771,7 +3771,7 @@
  * @target: The target for the new device.
  * @lun: The lun for the new device.
  *
- * Return the new device if succesfull or NULL on failure.
+ * Return the new device if successful or NULL on failure.
  **/
 static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
 		u8 target, u8 lun)
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 115f554..497f664 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -760,7 +760,7 @@
 		while (!got_interrupt(host_index))
 			barrier();
 
-		/*if command succesful, break */
+		/*if command successful, break */
 		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
 			return 1;
 	}
@@ -885,7 +885,7 @@
 		while (!got_interrupt(host_index))
 			barrier();
 
-		/*if command succesful, break */
+		/*if command successful, break */
 		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
 			return 1;
 	}
@@ -921,7 +921,7 @@
 			return 2;
 		} else
 			global_command_error_excuse = 0;
-		/*if command succesful, break */
+		/*if command successful, break */
 		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
 			return 1;
 	}
@@ -959,7 +959,7 @@
 			/* did not work, finish */
 			return 1;
 		}
-		/*if command succesful, break */
+		/*if command successful, break */
 		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
 			return 1;
 	}
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index cd2dffd..681bd18 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -3,9 +3,6 @@
  * 
  * (The IMM is the embedded controller in the ZIP Plus drive.)
  * 
- * Current Maintainer: David Campbell (Perth, Western Australia)
- *                     campbell@torque.net
- *
  * My unoffical company acronym list is 21 pages long:
  *      FLA:    Four letter acronym with built in facility for
  *              future expansion to five letters.
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index dc3aebf..ece936a 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -2,7 +2,7 @@
 /*  Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in 
  * the Iomega ZIP Plus drive
  * 
- * (c) 1998     David Campbell     campbell@torque.net
+ * (c) 1998     David Campbell
  *
  * Please note that I live in Perth, Western Australia. GMT+0800
  */
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 5353b28..78f2ff7 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -6438,7 +6438,7 @@
 		/* VPP failure */
 		return (1);
 
-	/* check for succesful flash */
+	/* check for successful flash */
 	if (status & 0x30)
 		/* sequence error */
 		return (1);
@@ -6550,7 +6550,7 @@
 		/* VPP failure */
 		return (1);
 
-	/* check for succesful flash */
+	/* check for successful flash */
 	if (status & 0x30)
 		/* sequence error */
 		return (1);
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index e31fadd..118206d 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -43,9 +43,6 @@
 
 /* #define DEBUG_MAC_ESP */
 
-#define mac_turnon_irq(x)	mac_enable_irq(x)
-#define mac_turnoff_irq(x)	mac_disable_irq(x)
-
 extern void esp_handle(struct NCR_ESP *esp);
 extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
 
@@ -639,13 +636,13 @@
 
 static void dma_ints_off(struct NCR_ESP * esp)
 {
-	mac_turnoff_irq(esp->irq);
+	disable_irq(esp->irq);
 }
 
 
 static void dma_ints_on(struct NCR_ESP * esp)
 {
-	mac_turnon_irq(esp->irq);
+	enable_irq(esp->irq);
 }
 
 /*
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 777f9bc..a942a21 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -65,9 +65,6 @@
 #define RESET_BOOT
 #define DRIVER_SETUP
 
-#define	ENABLE_IRQ()	mac_enable_irq( IRQ_MAC_SCSI ); 
-#define	DISABLE_IRQ()	mac_disable_irq( IRQ_MAC_SCSI );
-
 extern void via_scsi_clear(void);
 
 #ifdef RESET_BOOT
@@ -351,7 +348,7 @@
 	printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
 
 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-	mac_disable_irq(IRQ_MAC_SCSI);
+	disable_irq(IRQ_MAC_SCSI);
 
 	/* get in phase */
 	NCR5380_write( TARGET_COMMAND_REG,
@@ -369,7 +366,7 @@
 		barrier();
 
 	/* switch on SCSI IRQ again */
-	mac_enable_irq(IRQ_MAC_SCSI);
+	enable_irq(IRQ_MAC_SCSI);
 
 	printk(KERN_INFO " done\n" );
 }
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index bec1424..b7caf60 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -714,7 +714,7 @@
  * . Allocate memory required for all the commands
  * . Use internal library of FW routines, build up complete soft state
  */
-static int __init
+static int __devinit
 megaraid_init_mbox(adapter_t *adapter)
 {
 	struct pci_dev		*pdev;
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 6ab0355..b28712d 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -5118,8 +5118,7 @@
 		cp->host_status &= ~HS_SKIPMASK;
 		cp->start.schedule.l_paddr = 
 			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
-		list_del(&cp->link_ccbq);
-		list_add_tail(&cp->link_ccbq, &lp->skip_ccbq);
+		list_move_tail(&cp->link_ccbq, &lp->skip_ccbq);
 		if (cp->queued) {
 			--lp->queuedccbs;
 		}
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 108910f..d58ac5a 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -6,8 +6,6 @@
  * (c) 1995,1996 Grant R. Guenther, grant@torque.net,
  * under the terms of the GNU General Public License.
  * 
- * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
- *                     campbell@torque.net
  */
 
 #include <linux/config.h>
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index f6e1a15..7511df3 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -2,7 +2,7 @@
  * the Iomega ZIP drive
  * 
  * (c) 1996     Grant R. Guenther  grant@torque.net
- *              David Campbell     campbell@torque.net
+ *              David Campbell
  *
  *      All comments to David.
  */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index aef093d..3d4487e 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2258,8 +2258,7 @@
 			}
 
 			/* Remove device from the new list and add it to DB */
-			list_del(&fcport->list);
-			list_add_tail(&fcport->list, &ha->fcports);
+			list_move_tail(&fcport->list, &ha->fcports);
 
 			/* Login and update database */
 			qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 1272dd2..b5218fc 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2818,7 +2818,7 @@
 		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
 		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
 		    undone == 0) {
-			ioctl_result = 0;	/* EOF written succesfully at EOM */
+			ioctl_result = 0;	/* EOF written successfully at EOM */
 			if (fileno >= 0)
 				fileno++;
 			STps->drv_file = fileno;
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index cc990be..2e2c1eb 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -332,11 +332,11 @@
     struct scatterlist *sg = sp->SCp.buffer;
 
     while (sz >= 0) {
-	    sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
+	    sg[sz].dma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
 					   sg[sz].offset, sg[sz].length);
 	    sz--;
     }
-    sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+    sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
 }
 
 static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -350,14 +350,14 @@
     struct scatterlist *sg = (struct scatterlist *)sp->buffer;
                         
     while(sz >= 0) {
-        dvma_unmap((char *)sg[sz].dvma_address);
+        dvma_unmap((char *)sg[sz].dma_address);
         sz--;
     }
 }
 
 static void dma_advance_sg (Scsi_Cmnd *sp)
 {
-    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
 }
 
 static int sun3x_esp_release(struct Scsi_Host *instance)
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index e55f0ee..574955b 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1391,7 +1391,7 @@
  *
  */
 
-static int wd7000_detect(struct scsi_host_template *tpnt)
+static __init int wd7000_detect(struct scsi_host_template *tpnt)
 {
 	short present = 0, biosaddr_ptr, sig_ptr, i, pass;
 	short biosptr[NUM_CONFIGS];
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index b79ed06..739bc84 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -323,8 +323,10 @@
 	{	"USR9180",		0	},
 	/* U.S. Robotics 56K Voice INT PnP*/
 	{	"USR9190",		0	},
-	/* HP Compaq Tablet PC tc1100 Wacom tablet */
+	/* Wacom tablets */
+	{	"WACF004",		0	},
 	{	"WACF005",		0	},
+	{       "WACF006",              0       },
 	/* Rockwell's (PORALiNK) 33600 INT PNP */
 	{	"WCI0003",		0	},
 	/* Unkown PnP modems */
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 8cbbb95..8ad2429 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -60,11 +60,11 @@
 #if defined(CONFIG_HW_FEITH)
 #define	CONSOLE_BAUD_RATE	38400
 #define	DEFAULT_CBAUD		B38400
-#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB)
+#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || defined(CONFIG_M5329EVB)
 #define CONSOLE_BAUD_RATE 	115200
 #define DEFAULT_CBAUD		B115200
 #elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
-      defined(CONFIG_senTec) || defined(CONFIG_SNEHA)
+      defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
 #define	CONSOLE_BAUD_RATE	19200
 #define	DEFAULT_CBAUD		B19200
 #endif
@@ -93,7 +93,7 @@
 #undef SERIAL_DEBUG_FLOW
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
-    defined(CONFIG_M520x)
+    defined(CONFIG_M520x) || defined(CONFIG_M532x)
 #define	IRQBASE	(MCFINT_VECBASE+MCFINT_UART0)
 #else
 #define	IRQBASE	73
@@ -1545,6 +1545,28 @@
 			*feci2c_par |=  MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
 				    | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
 		}
+#elif defined(CONFIG_M532x)
+	volatile unsigned char *uartp;
+	uartp = info->addr;
+	switch (info->line) {
+	case 0:
+		MCF_INTC0_ICR26 = 0x3;
+		MCF_INTC0_CIMR = 26;
+		/* GPIO initialization */
+		MCF_GPIO_PAR_UART |= 0x000F;
+		break;
+	case 1:
+		MCF_INTC0_ICR27 = 0x3;
+		MCF_INTC0_CIMR = 27;
+		/* GPIO initialization */
+		MCF_GPIO_PAR_UART |= 0x0FF0;
+		break;
+	case 2:
+		MCF_INTC0_ICR28 = 0x3;
+		MCF_INTC0_CIMR = 28;
+		/* GPIOs also must be initalized, depends on board */
+		break;
+	}
 #else
 	volatile unsigned char	*icrp, *uartp;
 
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 5578a9d..f6b2948 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -5712,7 +5712,7 @@
 	return 1;
 }
 
-int ixj_set_tone_off(unsigned short arg, IXJ *j)
+static int ixj_set_tone_off(unsigned short arg, IXJ *j)
 {
 	j->tone_off_time = arg;
 	if (ixj_WriteDSPCommand(0x6E05, j))		/* Set Tone Off Period */
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 95f5ad9..bfc9b28 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -569,7 +569,7 @@
 	ignore_mount = 1;
 
 	/* create the devices special file */
-	retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
+	retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
 	if (retval) {
 		err ("Unable to get usbfs mount");
 		goto exit;
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 2fe7fd1..4a22909 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -411,8 +411,7 @@
 	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
 	assert(urb_entry);
 
-	list_del(&urb_entry->list);
-	list_add_tail(&urb_entry->list, &urb_list[epid]);
+	list_move_tail(&urb_entry->list, &urb_list[epid]);
 }
 
 /* Get the next urb in the list. */
diff --git a/drivers/usb/input/fixp-arith.h b/drivers/usb/input/fixp-arith.h
index b44d398..ed3d2da 100644
--- a/drivers/usb/input/fixp-arith.h
+++ b/drivers/usb/input/fixp-arith.h
@@ -2,8 +2,6 @@
 #define _FIXP_ARITH_H
 
 /*
- * $$
- *
  * Simplistic fixed-point arithmetics.
  * Hmm, I'm probably duplicating some code :(
  *
@@ -31,20 +29,20 @@
 
 #include <linux/types.h>
 
-// The type representing fixed-point values
+/* The type representing fixed-point values */
 typedef s16 fixp_t;
 
 #define FRAC_N 8
 #define FRAC_MASK ((1<<FRAC_N)-1)
 
-// Not to be used directly. Use fixp_{cos,sin}
-static const fixp_t cos_table[45] = {
+/* Not to be used directly. Use fixp_{cos,sin} */
+static const fixp_t cos_table[46] = {
 	0x0100,	0x00FF,	0x00FF,	0x00FE,	0x00FD,	0x00FC,	0x00FA,	0x00F8,
 	0x00F6,	0x00F3,	0x00F0,	0x00ED,	0x00E9,	0x00E6,	0x00E2,	0x00DD,
 	0x00D9,	0x00D4,	0x00CF,	0x00C9,	0x00C4,	0x00BE,	0x00B8,	0x00B1,
 	0x00AB,	0x00A4,	0x009D,	0x0096,	0x008F,	0x0087,	0x0080,	0x0078,
 	0x0070,	0x0068,	0x005F,	0x0057,	0x004F,	0x0046,	0x003D,	0x0035,
-	0x002C,	0x0023,	0x001A,	0x0011,	0x0008
+	0x002C,	0x0023,	0x001A,	0x0011,	0x0008, 0x0000
 };
 
 
@@ -68,9 +66,8 @@
 	int quadrant = (degrees / 90) & 3;
 	unsigned int i = degrees % 90;
 
-	if (quadrant == 1 || quadrant == 3) {
-		i = 89 - i;
-	}
+	if (quadrant == 1 || quadrant == 3)
+		i = 90 - i;
 
 	i >>= 1;
 
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
index 702c48c..f04d6d7 100644
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/usb/input/hid-debug.h
@@ -563,7 +563,7 @@
 	[KEY_VOLUMEUP] = "VolumeUp",		[KEY_POWER] = "Power",
 	[KEY_KPEQUAL] = "KPEqual",		[KEY_KPPLUSMINUS] = "KPPlusMinus",
 	[KEY_PAUSE] = "Pause",			[KEY_KPCOMMA] = "KPComma",
-	[KEY_HANGUEL] = "Hanguel",		[KEY_HANJA] = "Hanja",
+	[KEY_HANGUEL] = "Hangeul",		[KEY_HANJA] = "Hanja",
 	[KEY_YEN] = "Yen",			[KEY_LEFTMETA] = "LeftMeta",
 	[KEY_RIGHTMETA] = "RightMeta",		[KEY_COMPOSE] = "Compose",
 	[KEY_STOP] = "Stop",			[KEY_AGAIN] = "Again",
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5b06fa3..56ffc81 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -686,19 +686,16 @@
 		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
 		urb = wrap->urb;
 		usb_kill_urb(urb);
-		list_del(tmp);
-		list_add(tmp, &info->rx_urbs_free);
+		list_move(tmp, &info->rx_urbs_free);
 	}
-	list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
-		list_del(tmp);
-		list_add(tmp, &info->rx_urbs_free);
-	}
+	list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
+		list_move(tmp, &info->rx_urbs_free);
+
 	list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
 		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
 		urb = wrap->urb;
 		usb_kill_urb(urb);
-		list_del(tmp);
-		list_add(tmp, &info->tx_urbs_free);
+		list_move(tmp, &info->tx_urbs_free);
 	}
 	spin_unlock_irqrestore(&info->lock, flags);
 
@@ -1080,8 +1077,7 @@
 		err("%s - Not my urb!", __FUNCTION__);
 		return;
 	}
-	list_del(&wrap->list);
-	list_add(&wrap->list, &info->tx_urbs_free);
+	list_move(&wrap->list, &info->tx_urbs_free);
 	spin_unlock(&info->lock);
 
 	if (urb->status) {
@@ -1371,8 +1367,7 @@
 				wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
 				urb = wrap->urb;
 				usb_kill_urb(urb);
-				list_del(tmp);
-				list_add(tmp, &info->rx_urbs_free);
+				list_move(tmp, &info->rx_urbs_free);
 			}
 			break;
 		}
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 009fb09..5284abe 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -160,10 +160,10 @@
 };
 
 /* Convert between us_data and the corresponding Scsi_Host */
-static struct Scsi_Host inline *us_to_host(struct us_data *us) {
+static inline struct Scsi_Host *us_to_host(struct us_data *us) {
 	return container_of((void *) us, struct Scsi_Host, hostdata);
 }
-static struct us_data inline *host_to_us(struct Scsi_Host *host) {
+static inline struct us_data *host_to_us(struct Scsi_Host *host) {
 	return (struct us_data *) host->hostdata;
 }
 
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5a2840a..17de4c8 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,6 +4,21 @@
 
 menu "Graphics support"
 
+config FIRMWARE_EDID
+       bool "Enable firmware EDID"
+       default y
+       ---help---
+         This enables access to the EDID transferred from the firmware.
+	 On the i386, this is from the Video BIOS. Enable this if DDC/I2C
+	 transfers do not work for your driver and if you are using
+	 nvidiafb, i810fb or savagefb.
+
+	 In general, choosing Y for this option is safe.  If you
+	 experience extremely long delays while booting before you get
+	 something on your display, try setting this to N.  Matrox cards in
+	 combination with certain motherboards and monitors are known to
+	 suffer from this problem.
+
 config FB
 	tristate "Support for frame buffer devices"
 	---help---
@@ -70,21 +85,10 @@
        depends on FB
        default n
 
-config FB_FIRMWARE_EDID
-       bool "Enable firmware EDID"
+config FB_BACKLIGHT
+       bool
        depends on FB
-       default y
-       ---help---
-         This enables access to the EDID transferred from the firmware.
-	 On the i386, this is from the Video BIOS. Enable this if DDC/I2C
-	 transfers do not work for your driver and if you are using
-	 nvidiafb, i810fb or savagefb.
-
-	 In general, choosing Y for this option is safe.  If you
-	 experience extremely long delays while booting before you get
-	 something on your display, try setting this to N.  Matrox cards in
-	 combination with certain motherboards and monitors are known to
-	 suffer from this problem.
+       default n
 
 config FB_MODE_HELPERS
         bool "Enable Video Mode Handling Helpers"
@@ -546,10 +550,14 @@
 	  You will get a boot time penguin logo at no additional cost. Please
 	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
 
-config VIDEO_SELECT
-	bool
-	depends on FB_VESA
-	default y
+config FB_IMAC
+	bool "Intel-based Macintosh Framebuffer Support"
+	depends on (FB = y) && X86
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the frame buffer device driver for the Intel-based Macintosh
 
 config FB_HGA
 	tristate "Hercules mono graphics support"
@@ -573,12 +581,6 @@
 	This will compile the Hercules mono graphics with
 	acceleration functions.
 
-
-config VIDEO_SELECT
-	bool
-	depends on (FB = y) && X86
-	default y
-
 config FB_SGIVW
 	tristate "SGI Visual Workstation framebuffer support"
 	depends on FB && X86_VISWS
@@ -717,6 +719,16 @@
 	  independently validate video mode parameters, you should say Y
 	  here.
 
+config FB_NVIDIA_BACKLIGHT
+	bool "Support for backlight control"
+	depends on FB_NVIDIA && PPC_PMAC
+	select FB_BACKLIGHT
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	default y
+	help
+	  Say Y here if you want to control the backlight of your display.
+
 config FB_RIVA
 	tristate "nVidia Riva support"
 	depends on FB && PCI
@@ -755,6 +767,16 @@
 	  of debugging informations to provide to the maintainer when
 	  something goes wrong.
 
+config FB_RIVA_BACKLIGHT
+	bool "Support for backlight control"
+	depends on FB_RIVA && PPC_PMAC
+	select FB_BACKLIGHT
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	default y
+	help
+	  Say Y here if you want to control the backlight of your display.
+
 config FB_I810
 	tristate "Intel 810/815 support (EXPERIMENTAL)"
 	depends on FB && EXPERIMENTAL && PCI && X86_32
@@ -993,6 +1015,7 @@
 
 	  There is a product page at
 	  http://apps.ati.com/ATIcompare/
+
 config FB_RADEON_I2C
 	bool "DDC/I2C for ATI Radeon support"
 	depends on FB_RADEON
@@ -1000,6 +1023,16 @@
 	help
 	  Say Y here if you want DDC/I2C support for your Radeon board. 
 
+config FB_RADEON_BACKLIGHT
+	bool "Support for backlight control"
+	depends on FB_RADEON && PPC_PMAC
+	select FB_BACKLIGHT
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	default y
+	help
+	  Say Y here if you want to control the backlight of your display.
+
 config FB_RADEON_DEBUG
 	bool "Lots of debug output from Radeon driver"
 	depends on FB_RADEON
@@ -1024,6 +1057,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called aty128fb.
 
+config FB_ATY128_BACKLIGHT
+	bool "Support for backlight control"
+	depends on FB_ATY128 && PPC_PMAC
+	select FB_BACKLIGHT
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	default y
+	help
+	  Say Y here if you want to control the backlight of your display.
+
 config FB_ATY
 	tristate "ATI Mach64 display support" if PCI || ATARI
 	depends on FB && !SPARC32
@@ -1066,6 +1109,16 @@
 	  is at
 	  <http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
 
+config FB_ATY_BACKLIGHT
+	bool "Support for backlight control"
+	depends on FB_ATY && PPC_PMAC
+	select FB_BACKLIGHT
+	select BACKLIGHT_LCD_SUPPORT
+	select BACKLIGHT_CLASS_DEVICE
+	default y
+	help
+	  Say Y here if you want to control the backlight of your display.
+
 config FB_S3TRIO
 	bool "S3 Trio display support"
 	depends on (FB = y) && PPC && BROKEN
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 23de3b2..c335e9b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,15 +4,15 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_VT)		  += console/
-obj-$(CONFIG_LOGO)		  += logo/
-obj-$(CONFIG_SYSFS)		  += backlight/
-
 obj-$(CONFIG_FB)                  += fb.o
 fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
                                      modedb.o fbcvt.o
 fb-objs                           := $(fb-y)
 
+obj-$(CONFIG_VT)		  += console/
+obj-$(CONFIG_LOGO)		  += logo/
+obj-$(CONFIG_SYSFS)		  += backlight/
+
 obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
 obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
 obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
@@ -97,6 +97,7 @@
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
+obj-$(CONFIG_FB_IMAC)             += imacfb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
 
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
index 1852139..a6cc0e9 100644
--- a/drivers/video/aty/Makefile
+++ b/drivers/video/aty/Makefile
@@ -10,5 +10,6 @@
 
 radeonfb-y			:= radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
 radeonfb-$(CONFIG_FB_RADEON_I2C)	+= radeon_i2c.o
+radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT)	+= radeon_backlight.o
 radeonfb-objs			:= $(radeonfb-y)
 
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index f7bbff4..11cf7fc 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -64,6 +64,7 @@
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
+#include <linux/backlight.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_PMAC
@@ -99,7 +100,7 @@
 
 #ifndef CONFIG_PPC_PMAC
 /* default mode */
-static struct fb_var_screeninfo default_var __initdata = {
+static struct fb_var_screeninfo default_var __devinitdata = {
 	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
 	640, 480, 640, 480, 0, 0, 8, 0,
 	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -122,7 +123,7 @@
 
 /* default modedb mode */
 /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode defaultmode __initdata = {
+static struct fb_videomode defaultmode __devinitdata = {
 	.refresh =	60,
 	.xres =		640,
 	.yres =		480,
@@ -334,7 +335,7 @@
 static const struct aty128_meminfo ddr_sgram =
 	{ 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" };
 
-static struct fb_fix_screeninfo aty128fb_fix __initdata = {
+static struct fb_fix_screeninfo aty128fb_fix __devinitdata = {
 	.id		= "ATY Rage128",
 	.type		= FB_TYPE_PACKED_PIXELS,
 	.visual		= FB_VISUAL_PSEUDOCOLOR,
@@ -344,15 +345,15 @@
 	.accel		= FB_ACCEL_ATI_RAGE128,
 };
 
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
 
 #ifdef CONFIG_PPC_PMAC
-static int default_vmode __initdata = VMODE_1024_768_60;
-static int default_cmode __initdata = CMODE_8;
+static int default_vmode __devinitdata = VMODE_1024_768_60;
+static int default_cmode __devinitdata = CMODE_8;
 #endif
 
-static int default_crt_on __initdata = 0;
-static int default_lcd_on __initdata = 1;
+static int default_crt_on __devinitdata = 0;
+static int default_lcd_on __devinitdata = 1;
 
 #ifdef CONFIG_MTRR
 static int mtrr = 1;
@@ -444,9 +445,9 @@
 static int aty128_decode_var(struct fb_var_screeninfo *var,
                              struct aty128fb_par *par);
 #if 0
-static void __init aty128_get_pllinfo(struct aty128fb_par *par,
+static void __devinit aty128_get_pllinfo(struct aty128fb_par *par,
 				      void __iomem *bios);
-static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
+static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
 #endif
 static void aty128_timings(struct aty128fb_par *par);
 static void aty128_init_engine(struct aty128fb_par *par);
@@ -480,16 +481,6 @@
 	.fb_imageblit	= cfb_imageblit,
 };
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int aty128_set_backlight_enable(int on, int level, void* data);
-static int aty128_set_backlight_level(int level, void* data);
-
-static struct backlight_controller aty128_backlight_controller = {
-	aty128_set_backlight_enable,
-	aty128_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
     /*
      * Functions to read from/write to the mmio registers
      *	- endian conversions may possibly be avoided by
@@ -582,7 +573,7 @@
 
 
 /* write to the scratch register to test r/w functionality */
-static int __init register_test(const struct aty128fb_par *par)
+static int __devinit register_test(const struct aty128fb_par *par)
 {
 	u32 val;
 	int flag = 0;
@@ -781,7 +772,7 @@
 
 
 #ifndef __sparc__
-static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
 {
 	u16 dptr;
 	u8 rom_type;
@@ -865,7 +856,7 @@
 	return NULL;
 }
 
-static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
+static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
 {
 	unsigned int bios_hdr;
 	unsigned int bios_pll;
@@ -912,7 +903,7 @@
 #endif /* ndef(__sparc__) */
 
 /* fill in known card constants if pll_block is not available */
-static void __init aty128_timings(struct aty128fb_par *par)
+static void __devinit aty128_timings(struct aty128fb_par *par)
 {
 #ifdef CONFIG_PPC_OF
 	/* instead of a table lookup, assume OF has properly
@@ -1258,19 +1249,35 @@
 static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
 {
 	u32 reg;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+#endif
 
 	if (on) {
 		reg = aty_ld_le32(LVDS_GEN_CNTL);
 		reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
 		reg &= ~LVDS_DISPLAY_DIS;
 		aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef CONFIG_PMAC_BACKLIGHT
-		aty128_set_backlight_enable(get_backlight_enable(),
-					    get_backlight_level(), par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+		mutex_lock(&info->bl_mutex);
+		if (info->bl_dev) {
+			down(&info->bl_dev->sem);
+			info->bl_dev->props->update_status(info->bl_dev);
+			up(&info->bl_dev->sem);
+		}
+		mutex_unlock(&info->bl_mutex);
 #endif	
 	} else {
-#ifdef CONFIG_PMAC_BACKLIGHT
-		aty128_set_backlight_enable(0, 0, par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+		mutex_lock(&info->bl_mutex);
+		if (info->bl_dev) {
+			down(&info->bl_dev->sem);
+			info->bl_dev->props->brightness = 0;
+			info->bl_dev->props->power = FB_BLANK_POWERDOWN;
+			info->bl_dev->props->update_status(info->bl_dev);
+			up(&info->bl_dev->sem);
+		}
+		mutex_unlock(&info->bl_mutex);
 #endif	
 		reg = aty_ld_le32(LVDS_GEN_CNTL);
 		reg |= LVDS_DISPLAY_DIS;
@@ -1638,7 +1645,7 @@
 }
 
 #ifndef MODULE
-static int __init aty128fb_setup(char *options)
+static int __devinit aty128fb_setup(char *options)
 {
 	char *this_opt;
 
@@ -1691,6 +1698,184 @@
 }
 #endif  /*  MODULE  */
 
+/* Backlight */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+#define MAX_LEVEL 0xFF
+
+static struct backlight_properties aty128_bl_data;
+
+static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
+		int level)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	int atylevel;
+
+	/* Get and convert the value */
+	mutex_lock(&info->bl_mutex);
+	atylevel = MAX_LEVEL -
+		(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
+	mutex_unlock(&info->bl_mutex);
+
+	if (atylevel < 0)
+		atylevel = 0;
+	else if (atylevel > MAX_LEVEL)
+		atylevel = MAX_LEVEL;
+
+	return atylevel;
+}
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides greater power saving and the display is useless without
+ * backlight anyway
+ */
+#define BACKLIGHT_LVDS_OFF
+/* That one prevents proper CRT output with LCD off */
+#undef BACKLIGHT_DAC_OFF
+
+static int aty128_bl_update_status(struct backlight_device *bd)
+{
+	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+	int level;
+
+	if (bd->props->power != FB_BLANK_UNBLANK ||
+	    bd->props->fb_blank != FB_BLANK_UNBLANK ||
+	    !par->lcd_on)
+		level = 0;
+	else
+		level = bd->props->brightness;
+
+	reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+	if (level > 0) {
+		reg |= LVDS_DIGION;
+		if (!(reg & LVDS_ON)) {
+			reg &= ~LVDS_BLON;
+			aty_st_le32(LVDS_GEN_CNTL, reg);
+			aty_ld_le32(LVDS_GEN_CNTL);
+			mdelay(10);
+			reg |= LVDS_BLON;
+			aty_st_le32(LVDS_GEN_CNTL, reg);
+		}
+		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+		reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+		reg |= LVDS_ON | LVDS_EN;
+		reg &= ~LVDS_DISPLAY_DIS;
+#endif
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
+#endif
+	} else {
+		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+		reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+		reg |= LVDS_DISPLAY_DIS;
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+		aty_ld_le32(LVDS_GEN_CNTL);
+		udelay(10);
+		reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
+#endif
+		aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
+#endif
+	}
+
+	return 0;
+}
+
+static int aty128_bl_get_brightness(struct backlight_device *bd)
+{
+	return bd->props->brightness;
+}
+
+static struct backlight_properties aty128_bl_data = {
+	.owner		= THIS_MODULE,
+	.get_brightness	= aty128_bl_get_brightness,
+	.update_status	= aty128_bl_update_status,
+	.max_brightness	= (FB_BACKLIGHT_LEVELS - 1),
+};
+
+static void aty128_bl_init(struct aty128fb_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	struct backlight_device *bd;
+	char name[12];
+
+	/* Could be extended to Rage128Pro LVDS output too */
+	if (par->chip_gen != rage_M3)
+		return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!pmac_has_backlight_type("ati"))
+		return;
+#endif
+
+	snprintf(name, sizeof(name), "aty128bl%d", info->node);
+
+	bd = backlight_device_register(name, par, &aty128_bl_data);
+	if (IS_ERR(bd)) {
+		info->bl_dev = NULL;
+		printk("aty128: Backlight registration failed\n");
+		goto error;
+	}
+
+	mutex_lock(&info->bl_mutex);
+	info->bl_dev = bd;
+	fb_bl_default_curve(info, 0,
+		 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+		219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+	mutex_unlock(&info->bl_mutex);
+
+	up(&bd->sem);
+	bd->props->brightness = aty128_bl_data.max_brightness;
+	bd->props->power = FB_BLANK_UNBLANK;
+	bd->props->update_status(bd);
+	down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+	if (!pmac_backlight)
+		pmac_backlight = bd;
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+	printk("aty128: Backlight initialized (%s)\n", name);
+
+	return;
+
+error:
+	return;
+}
+
+static void aty128_bl_exit(struct aty128fb_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+#endif
+
+	mutex_lock(&info->bl_mutex);
+	if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+		if (pmac_backlight == info->bl_dev)
+			pmac_backlight = NULL;
+#endif
+
+		backlight_device_unregister(info->bl_dev);
+		info->bl_dev = NULL;
+
+		printk("aty128: Backlight unloaded\n");
+	}
+	mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#endif /* CONFIG_FB_ATY128_BACKLIGHT */
 
 /*
  *  Initialisation
@@ -1708,7 +1893,7 @@
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct fb_info *info = pci_get_drvdata(pdev);
 	struct aty128fb_par *par = info->par;
@@ -1835,17 +2020,15 @@
 	if (register_framebuffer(info) < 0)
 		return 0;
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-	/* Could be extended to Rage128Pro LVDS output too */
-	if (par->chip_gen == rage_M3)
-		register_backlight_controller(&aty128_backlight_controller, par, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 	par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
 	par->pdev = pdev;
 	par->asleep = 0;
 	par->lock_blank = 0;
-	
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+	aty128_bl_init(par);
+#endif
+
 	printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
 	       info->node, info->fix.id, video_card);
 
@@ -1854,7 +2037,7 @@
 
 #ifdef CONFIG_PCI
 /* register a card    ++ajoshi */
-static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	unsigned long fb_addr, reg_addr;
 	struct aty128fb_par *par;
@@ -1981,6 +2164,10 @@
 
 	par = info->par;
 
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+	aty128_bl_exit(par);
+#endif
+
 	unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
 	if (par->mtrr.vram_valid)
@@ -2011,10 +2198,14 @@
 	if (par->lock_blank || par->asleep)
 		return 0;
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac) && blank)
-		set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+	if (machine_is(powermac) && blank) {
+		down(&fb->bl_dev->sem);
+		fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
+		fb->bl_dev->props->update_status(fb->bl_dev);
+		up(&fb->bl_dev->sem);
+	}
+#endif
 
 	if (blank & FB_BLANK_VSYNC_SUSPEND)
 		state |= 2;
@@ -2029,10 +2220,14 @@
 		aty128_set_crt_enable(par, par->crt_on && !blank);
 		aty128_set_lcd_enable(par, par->lcd_on && !blank);
 	}
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac) && !blank)
-		set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+	if (machine_is(powermac) && !blank) {
+		down(&fb->bl_dev->sem);
+		fb->bl_dev->props->power = FB_BLANK_UNBLANK;
+		fb->bl_dev->props->update_status(fb->bl_dev);
+		up(&fb->bl_dev->sem);
+	}
+#endif
 	return 0;
 }
 
@@ -2138,73 +2333,6 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_conv[] = {
-	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
-	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides greater power saving and the display is useless without
- * backlight anyway
- */
-#define BACKLIGHT_LVDS_OFF
-/* That one prevents proper CRT output with LCD off */
-#undef BACKLIGHT_DAC_OFF
-
-static int aty128_set_backlight_enable(int on, int level, void *data)
-{
-	struct aty128fb_par *par = data;
-	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
-
-	if (!par->lcd_on)
-		on = 0;
-	reg |= LVDS_BL_MOD_EN | LVDS_BLON;
-	if (on && level > BACKLIGHT_OFF) {
-		reg |= LVDS_DIGION;
-		if (!(reg & LVDS_ON)) {
-			reg &= ~LVDS_BLON;
-			aty_st_le32(LVDS_GEN_CNTL, reg);
-			(void)aty_ld_le32(LVDS_GEN_CNTL);
-			mdelay(10);
-			reg |= LVDS_BLON;
-			aty_st_le32(LVDS_GEN_CNTL, reg);
-		}
-		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
-		reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
-		reg |= LVDS_ON | LVDS_EN;
-		reg &= ~LVDS_DISPLAY_DIS;
-#endif
-		aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
-		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
-#endif		
-	} else {
-		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
-		reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
-		reg |= LVDS_DISPLAY_DIS;
-		aty_st_le32(LVDS_GEN_CNTL, reg);
-		(void)aty_ld_le32(LVDS_GEN_CNTL);
-		udelay(10);
-		reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
-#endif		
-		aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
-		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
-#endif		
-	}
-
-	return 0;
-}
-
-static int aty128_set_backlight_level(int level, void* data)
-{
-	return aty128_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 #if 0
     /*
      *  Accelerated functions
@@ -2428,7 +2556,7 @@
 }
 
 
-static int __init aty128fb_init(void)
+static int __devinit aty128fb_init(void)
 {
 #ifndef MODULE
 	char *option = NULL;
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index e9b7a64..43d2cb5 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -151,6 +151,7 @@
 	int lock_blank;
 	unsigned long res_start;
 	unsigned long res_size;
+	struct pci_dev *pdev;
 #ifdef __sparc__
 	struct pci_mmap_map *mmap_map;
 	u8 mmaped;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index c054bb2..22e7206 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -66,6 +66,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/backlight.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -315,12 +316,12 @@
 static int pll;
 static int mclk;
 static int xclk;
-static int comp_sync __initdata = -1;
+static int comp_sync __devinitdata = -1;
 static char *mode;
 
 #ifdef CONFIG_PPC
-static int default_vmode __initdata = VMODE_CHOOSE;
-static int default_cmode __initdata = CMODE_CHOOSE;
+static int default_vmode __devinitdata = VMODE_CHOOSE;
+static int default_cmode __devinitdata = CMODE_CHOOSE;
 
 module_param_named(vmode, default_vmode, int, 0);
 MODULE_PARM_DESC(vmode, "int: video mode for mac");
@@ -329,10 +330,10 @@
 #endif
 
 #ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+static unsigned int mach64_count __devinitdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __devinitdata = { 0, };
+static unsigned long phys_size[FB_MAX] __devinitdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
 #endif
 
 /* top -> down is an evolution of mach64 chipset, any corrections? */
@@ -582,7 +583,7 @@
  *  Apple monitor sense
  */
 
-static int __init read_aty_sense(const struct atyfb_par *par)
+static int __devinit read_aty_sense(const struct atyfb_par *par)
 {
 	int sense, i;
 
@@ -1280,6 +1281,14 @@
 
 	par->accel_flags = var->accel_flags; /* hack */
 
+	if (var->accel_flags) {
+		info->fbops->fb_sync = atyfb_sync;
+		info->flags &= ~FBINFO_HWACCEL_DISABLED;
+	} else {
+		info->fbops->fb_sync = NULL;
+		info->flags |= FBINFO_HWACCEL_DISABLED;
+	}
+
 	if (par->blitter_may_be_busy)
 		wait_for_idle(par);
 
@@ -2115,47 +2124,144 @@
 
 #endif /*  defined(CONFIG_PM) && defined(CONFIG_PCI) */
 
-#ifdef CONFIG_PMAC_BACKLIGHT
+/* Backlight */
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+#define MAX_LEVEL 0xFF
 
-    /*
-     *   LCD backlight control
-     */
+static struct backlight_properties aty_bl_data;
 
-static int backlight_conv[] = {
-	0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
-	0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
-};
-
-static int aty_set_backlight_enable(int on, int level, void *data)
+static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
 {
-	struct fb_info *info = (struct fb_info *) data;
-	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	int atylevel;
+
+	/* Get and convert the value */
+	mutex_lock(&info->bl_mutex);
+	atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+	mutex_unlock(&info->bl_mutex);
+
+	if (atylevel < 0)
+		atylevel = 0;
+	else if (atylevel > MAX_LEVEL)
+		atylevel = MAX_LEVEL;
+
+	return atylevel;
+}
+
+static int aty_bl_update_status(struct backlight_device *bd)
+{
+	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
 	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
+	int level;
+
+	if (bd->props->power != FB_BLANK_UNBLANK ||
+	    bd->props->fb_blank != FB_BLANK_UNBLANK)
+		level = 0;
+	else
+		level = bd->props->brightness;
 
 	reg |= (BLMOD_EN | BIASMOD_EN);
-	if (on && level > BACKLIGHT_OFF) {
+	if (level > 0) {
 		reg &= ~BIAS_MOD_LEVEL_MASK;
-		reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+		reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
 	} else {
 		reg &= ~BIAS_MOD_LEVEL_MASK;
-		reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+		reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
 	}
 	aty_st_lcd(LCD_MISC_CNTL, reg, par);
+
 	return 0;
 }
 
-static int aty_set_backlight_level(int level, void *data)
+static int aty_bl_get_brightness(struct backlight_device *bd)
 {
-	return aty_set_backlight_enable(1, level, data);
+	return bd->props->brightness;
 }
 
-static struct backlight_controller aty_backlight_controller = {
-	aty_set_backlight_enable,
-	aty_set_backlight_level
+static struct backlight_properties aty_bl_data = {
+	.owner	  = THIS_MODULE,
+	.get_brightness = aty_bl_get_brightness,
+	.update_status	= aty_bl_update_status,
+	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
-#endif /* CONFIG_PMAC_BACKLIGHT */
 
-static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
+static void aty_bl_init(struct atyfb_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	struct backlight_device *bd;
+	char name[12];
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!pmac_has_backlight_type("ati"))
+		return;
+#endif
+
+	snprintf(name, sizeof(name), "atybl%d", info->node);
+
+	bd = backlight_device_register(name, par, &aty_bl_data);
+	if (IS_ERR(bd)) {
+		info->bl_dev = NULL;
+		printk("aty: Backlight registration failed\n");
+		goto error;
+	}
+
+	mutex_lock(&info->bl_mutex);
+	info->bl_dev = bd;
+	fb_bl_default_curve(info, 0,
+		0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
+		0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
+	mutex_unlock(&info->bl_mutex);
+
+	up(&bd->sem);
+	bd->props->brightness = aty_bl_data.max_brightness;
+	bd->props->power = FB_BLANK_UNBLANK;
+	bd->props->update_status(bd);
+	down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+	if (!pmac_backlight)
+		pmac_backlight = bd;
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+	printk("aty: Backlight initialized (%s)\n", name);
+
+	return;
+
+error:
+	return;
+}
+
+static void aty_bl_exit(struct atyfb_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+#endif
+
+	mutex_lock(&info->bl_mutex);
+	if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+		if (pmac_backlight == info->bl_dev)
+			pmac_backlight = NULL;
+#endif
+
+		backlight_device_unregister(info->bl_dev);
+
+		printk("aty: Backlight unloaded\n");
+	}
+	mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+
+#endif /* CONFIG_FB_ATY_BACKLIGHT */
+
+static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
 {
 	const int ragepro_tbl[] = {
 		44, 50, 55, 66, 75, 80, 100
@@ -2215,7 +2321,7 @@
 }
 #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
 
-static int __init aty_init(struct fb_info *info, const char *name)
+static int __devinit aty_init(struct fb_info *info, const char *name)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	const char *ramname = NULL, *xtal;
@@ -2296,12 +2402,15 @@
 			break;
 		}
 		switch (clk_type) {
+#ifdef CONFIG_ATARI
 		case CLK_ATI18818_1:
 			par->pll_ops = &aty_pll_ati18818_1;
 			break;
+#else
 		case CLK_IBMRGB514:
 			par->pll_ops = &aty_pll_ibm514;
 			break;
+#endif
 #if 0 /* dead code */
 		case CLK_STG1703:
 			par->pll_ops = &aty_pll_stg1703;
@@ -2506,16 +2615,24 @@
 
 	info->fbops = &atyfb_ops;
 	info->pseudo_palette = pseudo_palette;
-	info->flags = FBINFO_FLAG_DEFAULT;
+	info->flags = FBINFO_DEFAULT           |
+	              FBINFO_HWACCEL_IMAGEBLIT |
+	              FBINFO_HWACCEL_FILLRECT  |
+	              FBINFO_HWACCEL_COPYAREA  |
+	              FBINFO_HWACCEL_YPAN;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 	if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
 		/* these bits let the 101 powerbook wake up from sleep -- paulus */
 		aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
 			   | (USE_F32KHZ | TRISTATE_MEM_EN), par);
-	} else if (M64_HAS(MOBIL_BUS))
-		register_backlight_controller(&aty_backlight_controller, info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+	} else
+#endif
+	if (M64_HAS(MOBIL_BUS)) {
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+		aty_bl_init (par);
+#endif
+	}
 
 	memset(&var, 0, sizeof(var));
 #ifdef CONFIG_PPC
@@ -2631,7 +2748,7 @@
 }
 
 #ifdef CONFIG_ATARI
-static int __init store_video_par(char *video_str, unsigned char m64_num)
+static int __devinit store_video_par(char *video_str, unsigned char m64_num)
 {
 	char *p;
 	unsigned long vmembase, size, guiregbase;
@@ -2674,8 +2791,16 @@
 		return 0;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
-		set_backlight_enable(0);
+	if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
+		mutex_lock(&info->bl_mutex);
+		if (info->bl_dev) {
+			down(&info->bl_dev->sem);
+			info->bl_dev->props->power = FB_BLANK_POWERDOWN;
+			info->bl_dev->props->update_status(info->bl_dev);
+			up(&info->bl_dev->sem);
+		}
+		mutex_unlock(&info->bl_mutex);
+	}
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
 	if (par->lcd_table && blank > FB_BLANK_NORMAL &&
 	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2706,8 +2831,16 @@
 	aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
-		set_backlight_enable(1);
+	if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
+		mutex_lock(&info->bl_mutex);
+		if (info->bl_dev) {
+			down(&info->bl_dev->sem);
+			info->bl_dev->props->power = FB_BLANK_UNBLANK;
+			info->bl_dev->props->update_status(info->bl_dev);
+			up(&info->bl_dev->sem);
+		}
+		mutex_unlock(&info->bl_mutex);
+	}
 #elif defined(CONFIG_FB_ATY_GENERIC_LCD)
 	if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
 	    (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -3440,6 +3573,7 @@
 	par->res_start = res_start;
 	par->res_size = res_size;
 	par->irq = pdev->irq;
+	par->pdev = pdev;
 
 	/* Setup "info" structure */
 #ifdef __sparc__
@@ -3571,6 +3705,11 @@
 	aty_set_crtc(par, &saved_crtc);
 	par->pll_ops->set_pll(info, &saved_pll);
 
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+	if (M64_HAS(MOBIL_BUS))
+		aty_bl_exit(par);
+#endif
+
 	unregister_framebuffer(info);
 
 #ifdef CONFIG_MTRR
@@ -3640,7 +3779,7 @@
 #endif /* CONFIG_PCI */
 
 #ifndef MODULE
-static int __init atyfb_setup(char *options)
+static int __devinit atyfb_setup(char *options)
 {
 	char *this_opt;
 
@@ -3712,7 +3851,7 @@
 }
 #endif  /*  MODULE  */
 
-static int __init atyfb_init(void)
+static int __devinit atyfb_init(void)
 {
 #ifndef MODULE
     char *option = NULL;
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index c98f4a4..1490e5e 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -200,8 +200,6 @@
 	if (!area->width || !area->height)
 		return;
 	if (!par->accel_flags) {
-		if (par->blitter_may_be_busy)
-			wait_for_idle(par);
 		cfb_copyarea(info, area);
 		return;
 	}
@@ -248,8 +246,6 @@
 	if (!rect->width || !rect->height)
 		return;
 	if (!par->accel_flags) {
-		if (par->blitter_may_be_busy)
-			wait_for_idle(par);
 		cfb_fillrect(info, rect);
 		return;
 	}
@@ -288,14 +284,10 @@
 		return;
 	if (!par->accel_flags ||
 	    (image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
-		if (par->blitter_may_be_busy)
-			wait_for_idle(par);
-
 		cfb_imageblit(info, image);
 		return;
 	}
 
-	wait_for_idle(par);
 	pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
 	host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
 
@@ -425,8 +417,6 @@
 		}
 	}
 
-	wait_for_idle(par);
-
 	/* restore pix_width */
 	wait_for_fifo(1, par);
 	aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
index ad8b749..2a7f381 100644
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -66,11 +66,6 @@
 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
 };
 
-static const u8 cursor_mask_lookup[16] = {
-	0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
-	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
-};
-
 static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -130,13 +125,13 @@
 		fg_idx = cursor->image.fg_color;
 		bg_idx = cursor->image.bg_color;
 
-		fg = (info->cmap.red[fg_idx] << 24) |
-		     (info->cmap.green[fg_idx] << 16) |
-		     (info->cmap.blue[fg_idx] << 8) | 15;
+		fg = ((info->cmap.red[fg_idx] & 0xff) << 24) |
+		     ((info->cmap.green[fg_idx] & 0xff) << 16) |
+		     ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff;
 
-		bg = (info->cmap.red[bg_idx] << 24) |
-		     (info->cmap.green[bg_idx] << 16) |
-		     (info->cmap.blue[bg_idx] << 8);
+		bg = ((info->cmap.red[bg_idx] & 0xff) << 24) |
+		     ((info->cmap.green[bg_idx] & 0xff) << 16) |
+		     ((info->cmap.blue[bg_idx] & 0xff) << 8);
 
 		wait_for_fifo(2, par);
 		aty_st_le32(CUR_CLR0, bg, par);
@@ -166,19 +161,17 @@
 			switch (cursor->rop) {
 			case ROP_XOR:
 			    // Upper 4 bits of mask data
-			    fb_writeb(cursor_mask_lookup[m >> 4 ] |
-				cursor_bits_lookup[(b ^ m) >> 4], dst++);
+			    fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++);
 			    // Lower 4 bits of mask
-			    fb_writeb(cursor_mask_lookup[m & 0x0f ] |
-				cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+			    fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f],
+				      dst++);
 			    break;
 			case ROP_COPY:
 			    // Upper 4 bits of mask data
-			    fb_writeb(cursor_mask_lookup[m >> 4 ] |
-				cursor_bits_lookup[(b & m) >> 4], dst++);
+			    fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++);
 			    // Lower 4 bits of mask
-			    fb_writeb(cursor_mask_lookup[m & 0x0f ] |
-				cursor_bits_lookup[(b & m) & 0x0f], dst++);
+			    fb_writeb(cursor_bits_lookup[(b & m) & 0x0f],
+				      dst++);
 			    break;
 			}
 		}
@@ -194,7 +187,7 @@
 	return 0;
 }
 
-int __init aty_init_cursor(struct fb_info *info)
+int __devinit aty_init_cursor(struct fb_info *info)
 {
 	unsigned long addr;
 
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
new file mode 100644
index 0000000..7de66b8
--- /dev/null
+++ b/drivers/video/aty/radeon_backlight.c
@@ -0,0 +1,247 @@
+/*
+ * Backlight code for ATI Radeon based graphic cards
+ *
+ * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
+ * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * 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 "radeonfb.h"
+#include <linux/backlight.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#define MAX_RADEON_LEVEL 0xFF
+
+static struct backlight_properties radeon_bl_data;
+
+struct radeon_bl_privdata {
+	struct radeonfb_info *rinfo;
+	uint8_t negative;
+};
+
+static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
+		int level)
+{
+	struct fb_info *info = pdata->rinfo->info;
+	int rlevel;
+
+	mutex_lock(&info->bl_mutex);
+
+	/* Get and convert the value */
+	rlevel = pdata->rinfo->info->bl_curve[level] *
+		 FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
+
+	mutex_unlock(&info->bl_mutex);
+
+	if (pdata->negative)
+		rlevel = MAX_RADEON_LEVEL - rlevel;
+
+	if (rlevel < 0)
+		rlevel = 0;
+	else if (rlevel > MAX_RADEON_LEVEL)
+		rlevel = MAX_RADEON_LEVEL;
+
+	return rlevel;
+}
+
+static int radeon_bl_update_status(struct backlight_device *bd)
+{
+	struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+	struct radeonfb_info *rinfo = pdata->rinfo;
+	u32 lvds_gen_cntl, tmpPixclksCntl;
+	int level;
+
+	if (rinfo->mon1_type != MT_LCD)
+		return 0;
+
+	/* We turn off the LCD completely instead of just dimming the
+	 * backlight. This provides some greater power saving and the display
+	 * is useless without backlight anyway.
+	 */
+        if (bd->props->power != FB_BLANK_UNBLANK ||
+	    bd->props->fb_blank != FB_BLANK_UNBLANK)
+		level = 0;
+	else
+		level = bd->props->brightness;
+
+	del_timer_sync(&rinfo->lvds_timer);
+	radeon_engine_idle();
+
+	lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+	if (level > 0) {
+		lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+		if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
+			lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+			lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
+			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+			lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+			lvds_gen_cntl |=
+				(radeon_bl_get_level_brightness(pdata, level) <<
+				 LVDS_BL_MOD_LEVEL_SHIFT);
+			lvds_gen_cntl |= LVDS_ON;
+			lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
+			rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+			mod_timer(&rinfo->lvds_timer,
+				  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+		} else {
+			lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+			lvds_gen_cntl |=
+				(radeon_bl_get_level_brightness(pdata, level) <<
+				 LVDS_BL_MOD_LEVEL_SHIFT);
+			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		}
+		rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+		rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
+			& LVDS_STATE_MASK;
+	} else {
+		/* Asic bug, when turning off LVDS_ON, we have to make sure
+		   RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+		*/
+		tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+		if (rinfo->is_mobility || rinfo->is_IGP)
+			OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+		lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
+		lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
+				  LVDS_BL_MOD_LEVEL_SHIFT);
+		lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		udelay(100);
+		lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
+		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+		lvds_gen_cntl &= ~(LVDS_DIGON);
+		rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+		mod_timer(&rinfo->lvds_timer,
+			  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+		if (rinfo->is_mobility || rinfo->is_IGP)
+			OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
+	}
+	rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+	rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+	return 0;
+}
+
+static int radeon_bl_get_brightness(struct backlight_device *bd)
+{
+	return bd->props->brightness;
+}
+
+static struct backlight_properties radeon_bl_data = {
+	.owner		= THIS_MODULE,
+	.get_brightness = radeon_bl_get_brightness,
+	.update_status	= radeon_bl_update_status,
+	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void radeonfb_bl_init(struct radeonfb_info *rinfo)
+{
+	struct backlight_device *bd;
+	struct radeon_bl_privdata *pdata;
+	char name[12];
+
+	if (rinfo->mon1_type != MT_LCD)
+		return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!pmac_has_backlight_type("ati") &&
+	    !pmac_has_backlight_type("mnca"))
+		return;
+#endif
+
+	pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
+	if (!pdata) {
+		printk("radeonfb: Memory allocation failed\n");
+		goto error;
+	}
+
+	snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
+
+	bd = backlight_device_register(name, pdata, &radeon_bl_data);
+	if (IS_ERR(bd)) {
+		rinfo->info->bl_dev = NULL;
+		printk("radeonfb: Backlight registration failed\n");
+		goto error;
+	}
+
+	pdata->rinfo = rinfo;
+
+	/* Pardon me for that hack... maybe some day we can figure out in what
+	 * direction backlight should work on a given panel?
+	 */
+	pdata->negative =
+		(rinfo->family != CHIP_FAMILY_RV200 &&
+		 rinfo->family != CHIP_FAMILY_RV250 &&
+		 rinfo->family != CHIP_FAMILY_RV280 &&
+		 rinfo->family != CHIP_FAMILY_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	pdata->negative = pdata->negative ||
+		machine_is_compatible("PowerBook4,3") ||
+		machine_is_compatible("PowerBook6,3") ||
+		machine_is_compatible("PowerBook6,5");
+#endif
+
+	mutex_lock(&rinfo->info->bl_mutex);
+	rinfo->info->bl_dev = bd;
+	fb_bl_default_curve(rinfo->info, 0,
+		 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
+		217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
+	mutex_unlock(&rinfo->info->bl_mutex);
+
+	up(&bd->sem);
+	bd->props->brightness = radeon_bl_data.max_brightness;
+	bd->props->power = FB_BLANK_UNBLANK;
+	bd->props->update_status(bd);
+	down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+	if (!pmac_backlight)
+		pmac_backlight = bd;
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+	printk("radeonfb: Backlight initialized (%s)\n", name);
+
+	return;
+
+error:
+	kfree(pdata);
+	return;
+}
+
+void radeonfb_bl_exit(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+#endif
+
+	mutex_lock(&rinfo->info->bl_mutex);
+	if (rinfo->info->bl_dev) {
+		struct radeon_bl_privdata *pdata;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+		if (pmac_backlight == rinfo->info->bl_dev)
+			pmac_backlight = NULL;
+#endif
+
+		pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
+		backlight_device_unregister(rinfo->info->bl_dev);
+		kfree(pdata);
+		rinfo->info->bl_dev = NULL;
+
+		printk("radeonfb: Backlight unloaded\n");
+	}
+	mutex_unlock(&rinfo->info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 387a18a..68b1564 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -78,10 +78,6 @@
 #include <asm/pci-bridge.h>
 #include "../macmodes.h"
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
 #ifdef CONFIG_BOOTX_TEXT
 #include <asm/btext.h>
 #endif
@@ -277,20 +273,6 @@
  * prototypes
  */
 
-
-#ifdef CONFIG_PPC_OF
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int radeon_set_backlight_enable(int on, int level, void *data);
-static int radeon_set_backlight_level(int level, void *data);
-static struct backlight_controller radeon_backlight_controller = {
-	radeon_set_backlight_enable,
-	radeon_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#endif /* CONFIG_PPC_OF */
-
 static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
 {
 	if (!rinfo->bios_seg)
@@ -1913,116 +1895,6 @@
         return 0;
 }
 
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-/* TODO: Dbl check these tables, we don't go up to full ON backlight
- * in these, possibly because we noticed MacOS doesn't, but I'd prefer
- * having some more official numbers from ATI
- */
-static int backlight_conv_m6[] = {
-	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
-	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-static int backlight_conv_m7[] = {
-	0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
-	0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
-};
-
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
-static int radeon_set_backlight_enable(int on, int level, void *data)
-{
-	struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
-	u32 lvds_gen_cntl, tmpPixclksCntl;
-	int* conv_table;
-
-	if (rinfo->mon1_type != MT_LCD)
-		return 0;
-
-	/* Pardon me for that hack... maybe some day we can figure
-	 * out in what direction backlight should work on a given
-	 * panel ?
-	 */
-	if ((rinfo->family == CHIP_FAMILY_RV200 ||
-	     rinfo->family == CHIP_FAMILY_RV250 ||
-	     rinfo->family == CHIP_FAMILY_RV280 ||
-	     rinfo->family == CHIP_FAMILY_RV350) &&
-	    !machine_is_compatible("PowerBook4,3") &&
-	    !machine_is_compatible("PowerBook6,3") &&
-	    !machine_is_compatible("PowerBook6,5"))
-		conv_table = backlight_conv_m7;
-	else
-		conv_table = backlight_conv_m6;
-
-	del_timer_sync(&rinfo->lvds_timer);
-	radeon_engine_idle();
-
-	lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
-	if (on && (level > BACKLIGHT_OFF)) {
-		lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
-		if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
-			lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
-			lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
-			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-			lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
-			lvds_gen_cntl |= (conv_table[level] <<
-					  LVDS_BL_MOD_LEVEL_SHIFT);
-			lvds_gen_cntl |= LVDS_ON;
-			lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
-			rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
-			mod_timer(&rinfo->lvds_timer,
-				  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
-		} else {
-			lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
-			lvds_gen_cntl |= (conv_table[level] <<
-					  LVDS_BL_MOD_LEVEL_SHIFT);
-			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-		}
-		rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
-		rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
-			& LVDS_STATE_MASK;
-	} else {
-		/* Asic bug, when turning off LVDS_ON, we have to make sure
-		   RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
-		*/
-		tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
-		if (rinfo->is_mobility || rinfo->is_IGP)
-			OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
-		lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
-		lvds_gen_cntl |= (conv_table[0] <<
-				  LVDS_BL_MOD_LEVEL_SHIFT);
-		lvds_gen_cntl |= LVDS_DISPLAY_DIS;
-		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-		udelay(100);
-		lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
-		OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-		lvds_gen_cntl &= ~(LVDS_DIGON);
-		rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
-		mod_timer(&rinfo->lvds_timer,
-			  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
-		if (rinfo->is_mobility || rinfo->is_IGP)
-			OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
-	}
-	rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
-	rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
-
-	return 0;
-}
-
-
-static int radeon_set_backlight_level(int level, void *data)
-{
-	return radeon_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
 /*
  * This reconfigure the card's internal memory map. In theory, we'd like
  * to setup the card's memory at the same address as it's PCI bus address,
@@ -2477,14 +2349,7 @@
 						 MTRR_TYPE_WRCOMB, 1);
 #endif
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (rinfo->mon1_type == MT_LCD) {
-		register_backlight_controller(&radeon_backlight_controller,
-					      rinfo, "ati");
-		register_backlight_controller(&radeon_backlight_controller,
-					      rinfo, "mnca");
-	}
-#endif
+	radeonfb_bl_init(rinfo);
 
 	printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
 
@@ -2514,7 +2379,6 @@
 err_release_fb:
         framebuffer_release(info);
 err_disable:
-	pci_disable_device(pdev);
 err_out:
 	return ret;
 }
@@ -2528,7 +2392,8 @@
  
         if (!rinfo)
                 return;
- 
+
+	radeonfb_bl_exit(rinfo);
 	radeonfb_pm_exit(rinfo);
 
 	if (rinfo->mon1_EDID)
@@ -2570,7 +2435,6 @@
 #endif        
 	fb_dealloc_cmap(&info->cmap);
         framebuffer_release(info);
-	pci_disable_device(pdev);
 }
 
 
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 217e00a..1645943 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -625,4 +625,13 @@
 extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
 			       int reg_only);
 
+/* Backlight functions */
+#ifdef CONFIG_FB_RADEON_BACKLIGHT
+extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
+extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
+#else
+static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
+static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
+#endif
+
 #endif /* __RADEONFB_H__ */
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 789450b..d63c3f4 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -7,6 +7,8 @@
  *  	Karl Lessard <klessard@sunrisetelecom.com>
  *  	<c.pellegrin@exadron.com>
  *
+ * PM support added by Rodolfo Giometti <giometti@linux.it>
+ *
  * Copyright 2002 MontaVista Software
  * Author: MontaVista Software, Inc.
  *		ppopov@mvista.com or source@mvista.com
@@ -602,17 +604,52 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static u32 sys_clksrc;
+static struct au1100fb_regs fbregs;
+
 int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
 {
-	/* TODO */
+	struct au1100fb_device *fbdev = dev_get_drvdata(dev);
+
+	if (!fbdev)
+		return 0;
+
+	/* Save the clock source state */
+	sys_clksrc = au_readl(SYS_CLKSRC);
+
+	/* Blank the LCD */
+	au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
+
+	/* Stop LCD clocking */
+	au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC);
+
+	memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));
+
 	return 0;
 }
 
 int au1100fb_drv_resume(struct device *dev)
 {
-	/* TODO */
+	struct au1100fb_device *fbdev = dev_get_drvdata(dev);
+
+	if (!fbdev)
+		return 0;
+
+	memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));
+
+	/* Restart LCD clocking */
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	/* Unblank the LCD */
+	au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);
+
 	return 0;
 }
+#else
+#define au1100fb_drv_suspend NULL
+#define au1100fb_drv_resume NULL
+#endif
 
 static struct device_driver au1100fb_driver = {
 	.name		= "au1100-lcd",
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index b895eaa..022f9d3 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -10,7 +10,7 @@
 
 config BACKLIGHT_CLASS_DEVICE
         tristate "Lowlevel Backlight controls"
-	depends on BACKLIGHT_LCD_SUPPORT
+	depends on BACKLIGHT_LCD_SUPPORT && FB
 	default m
 	help
 	  This framework adds support for low-level control of the LCD
@@ -26,7 +26,7 @@
 
 config LCD_CLASS_DEVICE
         tristate "Lowlevel LCD controls"
-	depends on BACKLIGHT_LCD_SUPPORT
+	depends on BACKLIGHT_LCD_SUPPORT && FB
 	default m
 	help
 	  This framework adds support for low-level control of LCD.
@@ -50,6 +50,14 @@
 	  If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
 	  backlight driver.
 
+config BACKLIGHT_LOCOMO
+	tristate "Sharp LOCOMO LCD/Backlight Driver"
+	depends on BACKLIGHT_DEVICE && SHARP_LOCOMO
+	default y
+	help
+	  If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
+	  enable the LCD/backlight driver.
+
 config BACKLIGHT_HP680
 	tristate "HP Jornada 680 Backlight Driver"
 	depends on BACKLIGHT_DEVICE && SH_HP6XX
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 744210c..65e5553 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -4,4 +4,4 @@
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
-obj-$(CONFIG_SHARP_LOCOMO)	+= locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LOCOMO)	+= locomolcd.o
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 60831bb..bd879b7 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -17,6 +17,8 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
 
 #include <asm/hardware/locomo.h>
 #include <asm/irq.h>
@@ -25,7 +27,10 @@
 
 #include "../../../arch/arm/mach-sa1100/generic.h"
 
+static struct backlight_device *locomolcd_bl_device;
 static struct locomo_dev *locomolcd_dev;
+static unsigned long locomolcd_flags;
+#define LOCOMOLCD_SUSPENDED     0x01
 
 static void locomolcd_on(int comadj)
 {
@@ -89,12 +94,10 @@
 	}
 
 	/* read comadj */
-	if (comadj == -1) {
-		if (machine_is_poodle())
-			comadj = 118;
-		if (machine_is_collie())
-			comadj = 128;
-	}
+	if (comadj == -1 && machine_is_collie())
+		comadj = 128;
+	if (comadj == -1 && machine_is_poodle())
+		comadj = 118;
 
 	if (on)
 		locomolcd_on(comadj);
@@ -105,26 +108,100 @@
 }
 EXPORT_SYMBOL(locomolcd_power);
 
-static int poodle_lcd_probe(struct locomo_dev *dev)
+
+static int current_intensity;
+
+static int locomolcd_set_intensity(struct backlight_device *bd)
+{
+	int intensity = bd->props->brightness;
+
+	if (bd->props->power != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
+		intensity = 0;
+
+	switch (intensity) {
+	/* AC and non-AC are handled differently, but produce same results in sharp code? */
+	case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break;
+	case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break;
+	case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break;
+	case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break;
+	case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break;
+
+	default:
+		return -ENODEV;
+	}
+	current_intensity = intensity;
+	return 0;
+}
+
+static int locomolcd_get_intensity(struct backlight_device *bd)
+{
+	return current_intensity;
+}
+
+static struct backlight_properties locomobl_data = {
+	.owner		= THIS_MODULE,
+	.get_brightness = locomolcd_get_intensity,
+	.update_status  = locomolcd_set_intensity,
+	.max_brightness = 4,
+};
+
+#ifdef CONFIG_PM
+static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state)
+{
+	locomolcd_flags |= LOCOMOLCD_SUSPENDED;
+	locomolcd_set_intensity(locomolcd_bl_device);
+	return 0;
+}
+
+static int locomolcd_resume(struct locomo_dev *dev)
+{
+	locomolcd_flags &= ~LOCOMOLCD_SUSPENDED;
+	locomolcd_set_intensity(locomolcd_bl_device);
+	return 0;
+}
+#else
+#define locomolcd_suspend	NULL
+#define locomolcd_resume	NULL
+#endif
+
+static int locomolcd_probe(struct locomo_dev *dev)
 {
 	unsigned long flags;
 
 	local_irq_save(flags);
 	locomolcd_dev = dev;
 
+	locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0);
+
 	/* the poodle_lcd_power function is called for the first time
 	 * from fs_initcall, which is before locomo is activated.
 	 * We need to recall poodle_lcd_power here*/
-#ifdef CONFIG_MACH_POODLE
-	locomolcd_power(1);
-#endif
+	if (machine_is_poodle())
+		locomolcd_power(1);
+
 	local_irq_restore(flags);
+
+	locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data);
+
+	if (IS_ERR (locomolcd_bl_device))
+		return PTR_ERR (locomolcd_bl_device);
+
+	/* Set up frontlight so that screen is readable */
+	locomobl_data.brightness = 2;
+	locomolcd_set_intensity(locomolcd_bl_device);
+
 	return 0;
 }
 
-static int poodle_lcd_remove(struct locomo_dev *dev)
+static int locomolcd_remove(struct locomo_dev *dev)
 {
 	unsigned long flags;
+
+	backlight_device_unregister(locomolcd_bl_device);
 	local_irq_save(flags);
 	locomolcd_dev = NULL;
 	local_irq_restore(flags);
@@ -136,19 +213,33 @@
 		.name = "locomo-backlight",
 	},
 	.devid	= LOCOMO_DEVID_BACKLIGHT,
-	.probe	= poodle_lcd_probe,
-	.remove	= poodle_lcd_remove,
+	.probe	= locomolcd_probe,
+	.remove	= locomolcd_remove,
+	.suspend = locomolcd_suspend,
+	.resume = locomolcd_resume,
 };
 
-static int __init poodle_lcd_init(void)
+
+static int __init locomolcd_init(void)
 {
 	int ret = locomo_driver_register(&poodle_lcd_driver);
-	if (ret) return ret;
+	if (ret)
+		return ret;
 
 #ifdef CONFIG_SA1100_COLLIE
 	sa1100fb_lcd_power = locomolcd_power;
 #endif
 	return 0;
 }
-device_initcall(poodle_lcd_init);
 
+static void __exit locomolcd_exit(void)
+{
+	locomo_driver_unregister(&poodle_lcd_driver);
+}
+
+module_init(locomolcd_init);
+module_exit(locomolcd_exit);
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>");
+MODULE_DESCRIPTION("Collie LCD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 8ba6152..ad8a89b 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -230,6 +230,7 @@
 		tab = cfb_tab16;
 		break;
 	case 32:
+	default:
 		tab = cfb_tab32;
 		break;
 	}
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 72ff6bf..d76bbfac 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -148,9 +148,24 @@
 static int chipsfb_blank(int blank, struct fb_info *info)
 {
 #ifdef CONFIG_PMAC_BACKLIGHT
-	// used to disable backlight only for blank > 1, but it seems
-	// useful at blank = 1 too (saves battery, extends backlight life)
-	set_backlight_enable(!blank);
+	mutex_lock(&pmac_backlight_mutex);
+
+	if (pmac_backlight) {
+		down(&pmac_backlight->sem);
+
+		/* used to disable backlight only for blank > 1, but it seems
+		 * useful at blank = 1 too (saves battery, extends backlight
+		 * life)
+	 	 */
+		if (blank)
+			pmac_backlight->props->power = FB_BLANK_POWERDOWN;
+		else
+			pmac_backlight->props->power = FB_BLANK_UNBLANK;
+		pmac_backlight->props->update_status(pmac_backlight);
+		up(&pmac_backlight->sem);
+	}
+
+	mutex_unlock(&pmac_backlight_mutex);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
 	return 1;	/* get fb_blank to set the colormap to all black */
@@ -401,7 +416,14 @@
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 	/* turn on the backlight */
-	set_backlight_enable(1);
+	mutex_lock(&pmac_backlight_mutex);
+	if (pmac_backlight) {
+		down(&pmac_backlight->sem);
+		pmac_backlight->props->power = FB_BLANK_UNBLANK;
+		pmac_backlight->props->update_status(pmac_backlight);
+		up(&pmac_backlight->sem);
+	}
+	mutex_unlock(&pmac_backlight_mutex);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
 #ifdef CONFIG_PPC
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 1103010..dda240e 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -2227,7 +2227,6 @@
 		release_region(0x3C0, 32);
 	pci_release_regions(pdev);
 	framebuffer_release(cinfo->info);
-	pci_disable_device(pdev);
 }
 #endif /* CONFIG_PCI */
 
@@ -2458,7 +2457,6 @@
 err_release_fb:
 	framebuffer_release(info);
 err_disable:
-	pci_disable_device(pdev);
 err_out:
 	return ret;
 }
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 47ba1a7..5dc4083 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -125,6 +125,8 @@
 static int first_fb_vc;
 static int last_fb_vc = MAX_NR_CONSOLES - 1;
 static int fbcon_is_default = 1; 
+static int fbcon_has_exited;
+
 /* font data */
 static char fontname[40];
 
@@ -140,7 +142,6 @@
 
 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
 
-static void fbcon_free_font(struct display *);
 static int fbcon_set_origin(struct vc_data *);
 
 #define CURSOR_DRAW_DELAY		(1)
@@ -194,6 +195,9 @@
 			      int line, int count, int dy);
 static void fbcon_modechanged(struct fb_info *info);
 static void fbcon_set_all_vcs(struct fb_info *info);
+static void fbcon_start(void);
+static void fbcon_exit(void);
+static struct class_device *fbcon_class_device;
 
 #ifdef CONFIG_MAC
 /*
@@ -252,7 +256,7 @@
 	if (!ops || ops->currcon < 0 || rotate > 3)
 		return;
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		vc = vc_cons[i].d;
 		if (!vc || vc->vc_mode != KD_TEXT ||
 		    registered_fb[con2fb_map[i]] != info)
@@ -389,15 +393,18 @@
 	int c;
 	int mode;
 
-	if (ops->currcon != -1)
+	acquire_console_sem();
+	if (ops && ops->currcon != -1)
 		vc = vc_cons[ops->currcon].d;
 
 	if (!vc || !CON_IS_VISIBLE(vc) ||
 	    fbcon_is_inactive(vc, info) ||
  	    registered_fb[con2fb_map[vc->vc_num]] != info ||
-	    vc_cons[ops->currcon].d->vc_deccm != 1)
+	    vc_cons[ops->currcon].d->vc_deccm != 1) {
+		release_console_sem();
 		return;
-	acquire_console_sem();
+	}
+
 	p = &fb_display[vc->vc_num];
 	c = scr_readw((u16 *) vc->vc_pos);
 	mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
@@ -528,7 +535,7 @@
 {
 	int i, retval = 0;
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		if (con2fb_map[i] == idx)
 			retval = 1;
 	}
@@ -539,7 +546,7 @@
 {
 	int i, retval = 0;
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		if (con2fb_map[i] != -1)
 			retval = 1;
 	}
@@ -561,6 +568,7 @@
 
 	err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
 				fbcon_is_default);
+
 	if (err) {
 		for (i = first_fb_vc; i <= last_fb_vc; i++) {
 			con2fb_map[i] = -1;
@@ -795,8 +803,8 @@
 	if (oldidx == newidx)
 		return 0;
 
-	if (!info)
- 		err =  -EINVAL;
+	if (!info || fbcon_has_exited)
+		return -EINVAL;
 
  	if (!err && !search_for_mapped_con()) {
 		info_idx = newidx;
@@ -832,6 +840,9 @@
  		con2fb_init_display(vc, info, unit, show_logo);
 	}
 
+	if (!search_fb_in_map(info_idx))
+		info_idx = newidx;
+
 	release_console_sem();
  	return err;
 }
@@ -1034,6 +1045,7 @@
 #endif				/* CONFIG_MAC */
 
 	fbcon_add_cursor_timer(info);
+	fbcon_has_exited = 0;
 	return display_desc;
 }
 
@@ -1061,17 +1073,36 @@
 
 	/* If we are not the first console on this
 	   fb, copy the font from that console */
-	t = &fb_display[svc->vc_num];
-	if (!vc->vc_font.data) {
-		vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
-		vc->vc_font.width = (*default_mode)->vc_font.width;
-		vc->vc_font.height = (*default_mode)->vc_font.height;
-		p->userfont = t->userfont;
-		if (p->userfont)
-			REFCOUNT(p->fontdata)++;
+	t = &fb_display[fg_console];
+	if (!p->fontdata) {
+		if (t->fontdata) {
+			struct vc_data *fvc = vc_cons[fg_console].d;
+
+			vc->vc_font.data = (void *)(p->fontdata =
+						    fvc->vc_font.data);
+			vc->vc_font.width = fvc->vc_font.width;
+			vc->vc_font.height = fvc->vc_font.height;
+			p->userfont = t->userfont;
+
+			if (p->userfont)
+				REFCOUNT(p->fontdata)++;
+		} else {
+			const struct font_desc *font = NULL;
+
+			if (!fontname[0] || !(font = find_font(fontname)))
+				font = get_default_font(info->var.xres,
+							info->var.yres);
+			vc->vc_font.width = font->width;
+			vc->vc_font.height = font->height;
+			vc->vc_font.data = (void *)(p->fontdata = font->data);
+			vc->vc_font.charcount = 256; /* FIXME  Need to
+							support more fonts */
+		}
 	}
+
 	if (p->userfont)
 		charcnt = FNTCHARCNT(p->fontdata);
+
 	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) {
@@ -1145,13 +1176,47 @@
 	ops->p = &fb_display[fg_console];
 }
 
+static void fbcon_free_font(struct display *p)
+{
+	if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+		kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
+	p->fontdata = NULL;
+	p->userfont = 0;
+}
+
 static void fbcon_deinit(struct vc_data *vc)
 {
 	struct display *p = &fb_display[vc->vc_num];
+	struct fb_info *info;
+	struct fbcon_ops *ops;
+	int idx;
 
-	if (info_idx != -1)
-	    return;
 	fbcon_free_font(p);
+	idx = con2fb_map[vc->vc_num];
+
+	if (idx == -1)
+		goto finished;
+
+	info = registered_fb[idx];
+
+	if (!info)
+		goto finished;
+
+	ops = info->fbcon_par;
+
+	if (!ops)
+		goto finished;
+
+	if (CON_IS_VISIBLE(vc))
+		fbcon_del_cursor_timer(info);
+
+	ops->flags &= ~FBCON_FLAGS_INIT;
+finished:
+
+	if (!con_is_bound(&fb_con))
+		fbcon_exit();
+
+	return;
 }
 
 /* ====================================================================== */
@@ -2099,12 +2164,11 @@
 		if (info->fbops->fb_set_par)
 			info->fbops->fb_set_par(info);
 
-		if (old_info != info) {
+		if (old_info != info)
 			fbcon_del_cursor_timer(old_info);
-			fbcon_add_cursor_timer(info);
-		}
 	}
 
+	fbcon_add_cursor_timer(info);
 	set_blitting_type(vc, info);
 	ops->cursor_reset = 1;
 
@@ -2222,14 +2286,6 @@
 	return 0;
 }
 
-static void fbcon_free_font(struct display *p)
-{
-	if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
-		kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
-	p->fontdata = NULL;
-	p->userfont = 0;
-}
-
 static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
 {
 	u8 *fontdata = vc->vc_font.data;
@@ -2443,7 +2499,7 @@
 
 	FNTSUM(new_data) = csum;
 	/* Check if the same font is on some other console already */
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		struct vc_data *tmp = vc_cons[i].d;
 		
 		if (fb_display[i].userfont &&
@@ -2768,7 +2824,7 @@
 	if (!ops || ops->currcon < 0)
 		return;
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		vc = vc_cons[i].d;
 		if (!vc || vc->vc_mode != KD_TEXT ||
 		    registered_fb[con2fb_map[i]] != info)
@@ -2830,22 +2886,57 @@
 	return found;
 }
 
+static int fbcon_fb_unregistered(int idx)
+{
+	int i;
+
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
+		if (con2fb_map[i] == idx)
+			con2fb_map[i] = -1;
+	}
+
+	if (idx == info_idx) {
+		info_idx = -1;
+
+		for (i = 0; i < FB_MAX; i++) {
+			if (registered_fb[i] != NULL) {
+				info_idx = i;
+				break;
+			}
+		}
+	}
+
+	if (info_idx != -1) {
+		for (i = first_fb_vc; i <= last_fb_vc; i++) {
+			if (con2fb_map[i] == -1)
+				con2fb_map[i] = info_idx;
+		}
+	}
+
+	if (!num_registered_fb)
+		unregister_con_driver(&fb_con);
+
+	return 0;
+}
+
 static int fbcon_fb_registered(int idx)
 {
 	int ret = 0, i;
 
 	if (info_idx == -1) {
-		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		for (i = first_fb_vc; i <= last_fb_vc; i++) {
 			if (con2fb_map_boot[i] == idx) {
 				info_idx = idx;
 				break;
 			}
 		}
+
 		if (info_idx != -1)
 			ret = fbcon_takeover(1);
 	} else {
-		for (i = 0; i < MAX_NR_CONSOLES; i++) {
-			if (con2fb_map_boot[i] == idx)
+		for (i = first_fb_vc; i <= last_fb_vc; i++) {
+			if (con2fb_map_boot[i] == idx &&
+			    con2fb_map[i] == -1)
 				set_con2fb_map(i, idx, 0);
 		}
 	}
@@ -2882,7 +2973,7 @@
 	struct fb_var_screeninfo var;
 	struct fb_videomode *mode;
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = first_fb_vc; i <= last_fb_vc; i++) {
 		if (registered_fb[con2fb_map[i]] != info)
 			continue;
 		if (!fb_display[i].mode)
@@ -2910,6 +3001,14 @@
 	struct fb_con2fbmap *con2fb;
 	int ret = 0;
 
+	/*
+	 * ignore all events except driver registration and deregistration
+	 * if fbcon is not active
+	 */
+	if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
+				  action == FB_EVENT_FB_UNREGISTERED))
+		goto done;
+
 	switch(action) {
 	case FB_EVENT_SUSPEND:
 		fbcon_suspended(info);
@@ -2930,6 +3029,9 @@
 	case FB_EVENT_FB_REGISTERED:
 		ret = fbcon_fb_registered(info->node);
 		break;
+	case FB_EVENT_FB_UNREGISTERED:
+		ret = fbcon_fb_unregistered(info->node);
+		break;
 	case FB_EVENT_SET_CONSOLE_MAP:
 		con2fb = event->data;
 		ret = set_con2fb_map(con2fb->console - 1,
@@ -2945,16 +3047,9 @@
 	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);
 	}
 
+done:
 	return ret;
 }
 
@@ -2992,27 +3087,181 @@
 	.notifier_call	= fbcon_event_notify,
 };
 
-static int __init fb_console_init(void)
+static ssize_t store_rotate(struct class_device *class_device,
+			    const char *buf, size_t count)
+{
+	struct fb_info *info;
+	int rotate, idx;
+	char **last = NULL;
+
+	if (fbcon_has_exited)
+		return count;
+
+	acquire_console_sem();
+	idx = con2fb_map[fg_console];
+
+	if (idx == -1 || registered_fb[idx] == NULL)
+		goto err;
+
+	info = registered_fb[idx];
+	rotate = simple_strtoul(buf, last, 0);
+	fbcon_rotate(info, rotate);
+err:
+	release_console_sem();
+	return count;
+}
+
+static ssize_t store_rotate_all(struct class_device *class_device,
+				const char *buf, size_t count)
+{
+	struct fb_info *info;
+	int rotate, idx;
+	char **last = NULL;
+
+	if (fbcon_has_exited)
+		return count;
+
+	acquire_console_sem();
+	idx = con2fb_map[fg_console];
+
+	if (idx == -1 || registered_fb[idx] == NULL)
+		goto err;
+
+	info = registered_fb[idx];
+	rotate = simple_strtoul(buf, last, 0);
+	fbcon_rotate_all(info, rotate);
+err:
+	release_console_sem();
+	return count;
+}
+
+static ssize_t show_rotate(struct class_device *class_device, char *buf)
+{
+	struct fb_info *info;
+	int rotate = 0, idx;
+
+	if (fbcon_has_exited)
+		return 0;
+
+	acquire_console_sem();
+	idx = con2fb_map[fg_console];
+
+	if (idx == -1 || registered_fb[idx] == NULL)
+		goto err;
+
+	info = registered_fb[idx];
+	rotate = fbcon_get_rotate(info);
+err:
+	release_console_sem();
+	return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
+}
+
+static struct class_device_attribute class_device_attrs[] = {
+	__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+	__ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
+};
+
+static int fbcon_init_class_device(void)
 {
 	int i;
 
-	acquire_console_sem();
-	fb_register_client(&fbcon_event_notifier);
-	release_console_sem();
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_create_file(fbcon_class_device,
+					 &class_device_attrs[i]);
+	return 0;
+}
 
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-		con2fb_map[i] = -1;
-
+static void fbcon_start(void)
+{
 	if (num_registered_fb) {
+		int i;
+
+		acquire_console_sem();
+
 		for (i = 0; i < FB_MAX; i++) {
 			if (registered_fb[i] != NULL) {
 				info_idx = i;
 				break;
 			}
 		}
+
+		release_console_sem();
 		fbcon_takeover(0);
 	}
+}
 
+static void fbcon_exit(void)
+{
+	struct fb_info *info;
+	int i, j, mapped;
+
+	if (fbcon_has_exited)
+		return;
+
+#ifdef CONFIG_ATARI
+	free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
+#endif
+#ifdef CONFIG_MAC
+	if (MACH_IS_MAC && vbl_detected)
+		free_irq(IRQ_MAC_VBL, fbcon_vbl_handler);
+#endif
+
+	kfree((void *)softback_buf);
+	softback_buf = 0UL;
+
+	for (i = 0; i < FB_MAX; i++) {
+		mapped = 0;
+		info = registered_fb[i];
+
+		if (info == NULL)
+			continue;
+
+		for (j = first_fb_vc; j <= last_fb_vc; j++) {
+			if (con2fb_map[j] == i)
+				mapped = 1;
+		}
+
+		if (mapped) {
+			if (info->fbops->fb_release)
+				info->fbops->fb_release(info, 0);
+			module_put(info->fbops->owner);
+
+			if (info->fbcon_par) {
+				fbcon_del_cursor_timer(info);
+				kfree(info->fbcon_par);
+				info->fbcon_par = NULL;
+			}
+
+			if (info->queue.func == fb_flashcursor)
+				info->queue.func = NULL;
+		}
+	}
+
+	fbcon_has_exited = 1;
+}
+
+static int __init fb_console_init(void)
+{
+	int i;
+
+	acquire_console_sem();
+	fb_register_client(&fbcon_event_notifier);
+	fbcon_class_device =
+	    class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon");
+
+	if (IS_ERR(fbcon_class_device)) {
+		printk(KERN_WARNING "Unable to create class_device "
+		       "for fbcon; errno = %ld\n",
+		       PTR_ERR(fbcon_class_device));
+		fbcon_class_device = NULL;
+	} else
+		fbcon_init_class_device();
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		con2fb_map[i] = -1;
+
+	release_console_sem();
+	fbcon_start();
 	return 0;
 }
 
@@ -3020,12 +3269,24 @@
 
 #ifdef MODULE
 
+static void __exit fbcon_deinit_class_device(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+		class_device_remove_file(fbcon_class_device,
+					 &class_device_attrs[i]);
+}
+
 static void __exit fb_console_exit(void)
 {
 	acquire_console_sem();
 	fb_unregister_client(&fbcon_event_notifier);
+	fbcon_deinit_class_device();
+	class_device_destroy(fb_class, MKDEV(0, 0));
+	fbcon_exit();
 	release_console_sem();
-	give_up_console(&fb_con);
+	unregister_con_driver(&fb_con);
 }	
 
 module_exit(fb_console_exit);
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index c38c3d8..3487a63 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -175,6 +175,7 @@
 #endif
 extern void fbcon_set_bitops(struct fbcon_ops *ops);
 extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
+extern struct class *fb_class;
 
 #define FBCON_ATTRIBUTE_UNDERLINE 1
 #define FBCON_ATTRIBUTE_REVERSE   2
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 7f939d0..c89f90e 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -308,7 +308,7 @@
 	outb_p(0x00, mda_gfx_port);
 }
 
-static const char __init *mdacon_startup(void)
+static const char *mdacon_startup(void)
 {
 	mda_num_columns = 80;
 	mda_num_lines   = 25;
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index e99fe30..0304131 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -51,6 +51,7 @@
 static int xcurs_correction = 29;
 static int newport_xsize;
 static int newport_ysize;
+static int newport_has_init;
 
 static int newport_set_def_font(int unit, struct console_font *op);
 
@@ -283,6 +284,15 @@
 		xcurs_correction = 21;
 }
 
+static void newport_exit(void)
+{
+	int i;
+
+	/* free memory used by user font */
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		newport_set_def_font(i, NULL);
+}
+
 /* Can't be __init, take_over_console may call it later */
 static const char *newport_startup(void)
 {
@@ -290,8 +300,10 @@
 
 	if (!sgi_gfxaddr)
 		return NULL;
-	npregs = (struct newport_regs *)	/* ioremap cannot fail */
-		 ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+
+	if (!npregs)
+		npregs = (struct newport_regs *)/* ioremap cannot fail */
+			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
 	npregs->cset.config = NPORT_CFG_GD0;
 
 	if (newport_wait(npregs))
@@ -307,11 +319,11 @@
 	newport_reset();
 	newport_get_revisions();
 	newport_get_screensize();
+	newport_has_init = 1;
 
 	return "SGI Newport";
 
 out_unmap:
-	iounmap((void *)npregs);
 	return NULL;
 }
 
@@ -324,11 +336,10 @@
 
 static void newport_deinit(struct vc_data *c)
 {
-	int i;
-
-	/* free memory used by user font */
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-		newport_set_def_font(i, NULL);
+	if (!con_is_bound(&newport_con) && newport_has_init) {
+		newport_exit();
+		newport_has_init = 0;
+	}
 }
 
 static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
@@ -728,16 +739,23 @@
 #ifdef MODULE
 static int __init newport_console_init(void)
 {
+
+	if (!sgi_gfxaddr)
+		return NULL;
+
+	if (!npregs)
+		npregs = (struct newport_regs *)/* ioremap cannot fail */
+			ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+
 	return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 }
+module_init(newport_console_init);
 
 static void __exit newport_console_exit(void)
 {
 	give_up_console(&newport_con);
 	iounmap((void *)npregs);
 }
-
-module_init(newport_console_init);
 module_exit(newport_console_exit);
 #endif
 
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
index 04f42fc..d6e6ad5 100644
--- a/drivers/video/console/promcon.c
+++ b/drivers/video/console/promcon.c
@@ -109,7 +109,7 @@
 	return b - p;
 }
 
-const char __init *promcon_startup(void)
+const char *promcon_startup(void)
 {
 	const char *display_desc = "PROM";
 	int node;
@@ -133,7 +133,7 @@
 	return display_desc;
 }
 
-static void __init 
+static void
 promcon_init_unimap(struct vc_data *conp)
 {
 	mm_segment_t old_fs = get_fs();
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index fd5940f..45c4f22 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -75,7 +75,7 @@
     cursor_drawn = 0;
 }
 
-static const char *__init sticon_startup(void)
+static const char *sticon_startup(void)
 {
     return "STI console";
 }
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index e64d42e..f32b590 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -114,6 +114,7 @@
 static int 		vga_video_font_height;
 static int 		vga_scan_lines;
 static unsigned int 	vga_rolled_over = 0;
+static int              vga_init_done;
 
 static int __init no_scroll(char *str)
 {
@@ -190,7 +191,7 @@
 	}
 }
 
-static void __init vgacon_scrollback_startup(void)
+static void vgacon_scrollback_startup(void)
 {
 	vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
 					  * 1024);
@@ -355,7 +356,7 @@
 }
 #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
 
-static const char __init *vgacon_startup(void)
+static const char *vgacon_startup(void)
 {
 	const char *display_desc = NULL;
 	u16 saved1, saved2;
@@ -523,7 +524,12 @@
 
 	vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
 	vgacon_yres = vga_scan_lines;
-	vgacon_scrollback_startup();
+
+	if (!vga_init_done) {
+		vgacon_scrollback_startup();
+		vga_init_done = 1;
+	}
+
 	return display_desc;
 }
 
@@ -531,10 +537,20 @@
 {
 	unsigned long p;
 
-	/* We cannot be loaded as a module, therefore init is always 1 */
+	/*
+	 * We cannot be loaded as a module, therefore init is always 1,
+	 * but vgacon_init can be called more than once, and init will
+	 * not be 1.
+	 */
 	c->vc_can_do_color = vga_can_do_color;
-	c->vc_cols = vga_video_num_columns;
-	c->vc_rows = vga_video_num_lines;
+
+	/* set dimensions manually if init != 0 since vc_resize() will fail */
+	if (init) {
+		c->vc_cols = vga_video_num_columns;
+		c->vc_rows = vga_video_num_lines;
+	} else
+		vc_resize(c, vga_video_num_columns, vga_video_num_lines);
+
 	c->vc_scan_lines = vga_scan_lines;
 	c->vc_font.height = vga_video_font_height;
 	c->vc_complement_mask = 0x7700;
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 0827594..f0a621e 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -605,11 +605,6 @@
 		fb_writeb(0, dst);
 }
 
-static void epson1355fb_platform_release(struct device *device)
-{
-	dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
-}
-
 static int epson1355fb_remove(struct platform_device *dev)
 {
 	struct fb_info *info = platform_get_drvdata(dev);
@@ -733,13 +728,7 @@
 	},
 };
 
-static struct platform_device epson1355fb_device = {
-	.name	= "epson1355fb",
-	.id	= 0,
-	.dev	= {
-		.release = epson1355fb_platform_release,
-	}
-};
+static struct platform_device *epson1355fb_device;
 
 int __init epson1355fb_init(void)
 {
@@ -749,11 +738,21 @@
 		return -ENODEV;
 
 	ret = platform_driver_register(&epson1355fb_driver);
+
 	if (!ret) {
-		ret = platform_device_register(&epson1355fb_device);
-		if (ret)
+		epson1355fb_device = platform_device_alloc("epson1355fb", 0);
+
+		if (epson1355fb_device)
+			ret = platform_device_add(epson1355fb_device);
+		else
+			ret = -ENOMEM;
+
+		if (ret) {
+			platform_device_put(epson1355fb_device);
 			platform_driver_unregister(&epson1355fb_driver);
+		}
 	}
+
 	return ret;
 }
 
@@ -762,7 +761,7 @@
 #ifdef MODULE
 static void __exit epson1355fb_exit(void)
 {
-	platform_device_unregister(&epson1355fb_device);
+	platform_device_unregister(epson1355fb_device);
 	platform_driver_unregister(&epson1355fb_driver);
 }
 
diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c
index ac90883..b549899 100644
--- a/drivers/video/fbcvt.c
+++ b/drivers/video/fbcvt.c
@@ -376,4 +376,3 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(fb_find_mode_cvt);
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 372aa17..31143af 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -34,7 +34,6 @@
 #endif
 #include <linux/devfs_fs_kernel.h>
 #include <linux/err.h>
-#include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/efi.h>
 
@@ -162,7 +161,6 @@
 }
 
 #ifdef CONFIG_LOGO
-#include <linux/linux_logo.h>
 
 static inline unsigned safe_shift(unsigned d, int n)
 {
@@ -336,11 +334,11 @@
 
 static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
 {
-	int i, j, w = width - 1;
+	int i, j, h = height - 1;
 
 	for (i = 0; i < height; i++)
 		for (j = 0; j < width; j++)
-			out[height * j + w - i] = *in++;
+				out[height * j + h - i] = *in++;
 }
 
 static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
@@ -358,24 +356,24 @@
 	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);
+		image->dx = info->var.xres - image->width;
+		image->dy = info->var.yres - 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;
+		image->dx = info->var.xres - image->width;
+	} else if (rotate == FB_ROTATE_CCW) {
 		fb_rotate_logo_ccw(image->data, dst, image->width,
 				   image->height);
+		tmp = image->width;
+		image->width = image->height;
+		image->height = tmp;
+		image->dy = info->var.yres - image->height;
 	}
 
 	image->data = dst;
@@ -435,7 +433,7 @@
 			depth = info->var.green.length;
 	}
 
-	if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) {
+	if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
 		/* assume console colormap */
 		depth = 4;
 	}
@@ -1278,8 +1276,8 @@
 #endif
 };
 
-static struct class *fb_class;
-
+struct class *fb_class;
+EXPORT_SYMBOL(fb_class);
 /**
  *	register_framebuffer - registers a frame buffer device
  *	@fb_info: frame buffer info structure
@@ -1355,6 +1353,7 @@
 int
 unregister_framebuffer(struct fb_info *fb_info)
 {
+	struct fb_event event;
 	int i;
 
 	i = fb_info->node;
@@ -1362,13 +1361,17 @@
 		return -EINVAL;
 	devfs_remove("fb/%d", i);
 
-	if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+	if (fb_info->pixmap.addr &&
+	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
 	fb_cleanup_class_device(fb_info);
 	class_device_destroy(fb_class, MKDEV(FB_MAJOR, i));
+	event.info = fb_info;
+	blocking_notifier_call_chain(&fb_notifier_list,
+				     FB_EVENT_FB_UNREGISTERED, &event);
 	return 0;
 }
 
@@ -1491,28 +1494,6 @@
 	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 blocking_notifier_call_chain(&fb_notifier_list, event, &evnt);
-}
-EXPORT_SYMBOL(fb_con_duit);
-
 static char *video_options[FB_MAX];
 static int ofonly;
 
@@ -1622,6 +1603,5 @@
 EXPORT_SYMBOL(fb_register_client);
 EXPORT_SYMBOL(fb_unregister_client);
 EXPORT_SYMBOL(fb_get_options);
-EXPORT_SYMBOL(fb_new_modelist);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 53beeb4..3ccfff7 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -29,9 +29,9 @@
 #include <linux/tty.h>
 #include <linux/fb.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <video/edid.h>
 #ifdef CONFIG_PPC_OF
-#include <linux/pci.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #endif
@@ -605,6 +605,7 @@
 	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
 
 	DPRINTK("      Monitor Operating Limits: ");
+
 	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
 		if (edid_is_limits_block(block)) {
 			specs->hfmin = H_MIN_RATE * 1000;
@@ -618,11 +619,12 @@
 			break;
 		}
 	}
-	
+
 	/* estimate monitor limits based on modes supported */
 	if (retval) {
-		struct fb_videomode *modes;
+		struct fb_videomode *modes, *mode;
 		int num_modes, i, hz, hscan, pixclock;
+		int vtotal, htotal;
 
 		modes = fb_create_modedb(edid, &num_modes);
 		if (!modes) {
@@ -632,20 +634,38 @@
 
 		retval = 0;
 		for (i = 0; i < num_modes; i++) {
-			hz = modes[i].refresh;
+			mode = &modes[i];
 			pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
-			hscan = (modes[i].yres * 105 * hz + 5000)/100;
+			htotal = mode->xres + mode->right_margin + mode->hsync_len
+				+ mode->left_margin;
+			vtotal = mode->yres + mode->lower_margin + mode->vsync_len
+				+ mode->upper_margin;
+
+			if (mode->vmode & FB_VMODE_INTERLACED)
+				vtotal /= 2;
+
+			if (mode->vmode & FB_VMODE_DOUBLE)
+				vtotal *= 2;
+
+			hscan = (pixclock + htotal / 2) / htotal;
+			hscan = (hscan + 500) / 1000 * 1000;
+			hz = (hscan + vtotal / 2) / vtotal;
 			
 			if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
 				specs->dclkmax = pixclock;
+
 			if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
 				specs->dclkmin = pixclock;
+
 			if (specs->hfmax == 0 || specs->hfmax < hscan)
 				specs->hfmax = hscan;
+
 			if (specs->hfmin == 0 || specs->hfmin > hscan)
 				specs->hfmin = hscan;
+
 			if (specs->vfmax == 0 || specs->vfmax < hz)
 				specs->vfmax = hz;
+
 			if (specs->vfmin == 0 || specs->vfmin > hz)
 				specs->vfmin = hz;
 		}
@@ -1281,8 +1301,7 @@
 		-EINVAL : 0;
 }
 
-#if defined(CONFIG_FB_FIRMWARE_EDID) && defined(__i386__)
-#include <linux/pci.h>
+#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
 
 /*
  * We need to ensure that the EDID block is only returned for
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 34e0739..4f78f23 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/fb.h>
 #include <linux/console.h>
+#include <linux/module.h>
 
 /**
  * framebuffer_alloc - creates a new frame buffer info structure
@@ -55,6 +56,10 @@
 
 	info->device = dev;
 
+#ifdef CONFIG_FB_BACKLIGHT
+	mutex_init(&info->bl_mutex);
+#endif
+
 	return info;
 #undef PADDING
 #undef BYTES_PER_LONG
@@ -95,13 +100,22 @@
 		       const struct fb_videomode *mode)
 {
 	char m = 'U';
+	char v = 'p';
+
 	if (mode->flag & FB_MODE_IS_DETAILED)
 		m = 'D';
 	if (mode->flag & FB_MODE_IS_VESA)
 		m = 'V';
 	if (mode->flag & FB_MODE_IS_STANDARD)
 		m = 'S';
-	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh);
+
+	if (mode->vmode & FB_VMODE_INTERLACED)
+		v = 'i';
+	if (mode->vmode & FB_VMODE_DOUBLE)
+		v = 'd';
+
+	return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
+	                m, mode->xres, mode->yres, v, mode->refresh);
 }
 
 static ssize_t store_mode(struct class_device *class_device, const char * buf,
@@ -233,45 +247,6 @@
 	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)
 {
@@ -414,6 +389,65 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
 }
 
+#ifdef CONFIG_FB_BACKLIGHT
+static ssize_t store_bl_curve(struct class_device *class_device,
+		const char *buf, size_t count)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+	u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+	unsigned int i;
+
+	if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+		return -EINVAL;
+
+	for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
+		if (sscanf(&buf[i * 24],
+			"%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
+			&tmp_curve[i * 8 + 0],
+			&tmp_curve[i * 8 + 1],
+			&tmp_curve[i * 8 + 2],
+			&tmp_curve[i * 8 + 3],
+			&tmp_curve[i * 8 + 4],
+			&tmp_curve[i * 8 + 5],
+			&tmp_curve[i * 8 + 6],
+			&tmp_curve[i * 8 + 7]) != 8)
+			return -EINVAL;
+
+	/* If there has been an error in the input data, we won't
+	 * reach this loop.
+	 */
+	mutex_lock(&fb_info->bl_mutex);
+	for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
+		fb_info->bl_curve[i] = tmp_curve[i];
+	mutex_unlock(&fb_info->bl_mutex);
+
+	return count;
+}
+
+static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
+{
+	struct fb_info *fb_info = class_get_devdata(class_device);
+	ssize_t len = 0;
+	unsigned int i;
+
+	mutex_lock(&fb_info->bl_mutex);
+	for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+		len += snprintf(&buf[len], PAGE_SIZE,
+				"%02x %02x %02x %02x %02x %02x %02x %02x\n",
+				fb_info->bl_curve[i + 0],
+				fb_info->bl_curve[i + 1],
+				fb_info->bl_curve[i + 2],
+				fb_info->bl_curve[i + 3],
+				fb_info->bl_curve[i + 4],
+				fb_info->bl_curve[i + 5],
+				fb_info->bl_curve[i + 6],
+				fb_info->bl_curve[i + 7]);
+	mutex_unlock(&fb_info->bl_mutex);
+
+	return len;
+}
+#endif
+
 /* When cmap is added back in it should be a binary attribute
  * not a text one. Consideration should also be given to converting
  * fbdev to use configfs instead of sysfs */
@@ -429,9 +463,10 @@
 	__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),
 	__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
+#ifdef CONFIG_FB_BACKLIGHT
+	__ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
+#endif
 };
 
 int fb_init_class_device(struct fb_info *fb_info)
@@ -454,4 +489,25 @@
 					 &class_device_attrs[i]);
 }
 
+#ifdef CONFIG_FB_BACKLIGHT
+/* This function generates a linear backlight curve
+ *
+ *     0: off
+ *   1-7: min
+ * 8-127: linear from min to max
+ */
+void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
+{
+	unsigned int i, flat, count, range = (max - min);
 
+	fb_info->bl_curve[0] = off;
+
+	for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+		fb_info->bl_curve[flat] = min;
+
+	count = FB_BACKLIGHT_LEVELS * 15 / 16;
+	for (i = 0; i < count; ++i)
+		fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+}
+EXPORT_SYMBOL_GPL(fb_bl_default_curve);
+#endif
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
index 20e6915..4d3a887 100644
--- a/drivers/video/geode/gx1fb_core.c
+++ b/drivers/video/geode/gx1fb_core.c
@@ -376,8 +376,6 @@
 		release_mem_region(gx1_gx_base() + 0x8300, 0x100);
 	}
 
-	pci_disable_device(pdev);
-
 	if (info)
 		framebuffer_release(info);
 	return ret;
@@ -399,7 +397,6 @@
 	iounmap(par->dc_regs);
 	release_mem_region(gx1_gx_base() + 0x8300, 0x100);
 
-	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 
 	framebuffer_release(info);
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 89c34b1..5ef12a3 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -354,8 +354,6 @@
 		pci_release_region(pdev, 2);
 	}
 
-	pci_disable_device(pdev);
-
 	if (info)
 		framebuffer_release(info);
 	return ret;
@@ -377,7 +375,6 @@
 	iounmap(par->dc_regs);
 	pci_release_region(pdev, 2);
 
-	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 
 	framebuffer_release(info);
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 44aa2ff..a1f7d80 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -2110,9 +2110,6 @@
 	if (par->res_flags & MMIO_REQ)
 		release_mem_region(par->mmio_start_phys, MMIO_SIZE);
 
-	if (par->res_flags & PCI_DEVICE_ENABLED)
-		pci_disable_device(par->dev);
-
 	framebuffer_release(info);
 
 }
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 6b88050..8a0c2d3 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -232,9 +232,6 @@
 
 	size = vma->vm_end - vma->vm_start;
 
-	/* To stop the swapper from even considering these pages. */
-	vma->vm_flags |= (VM_SHM | VM_LOCKED);
-
 	/* Each page, see which map applies */
 	for (page = 0; page < size; ) {
 		map_size = 0;
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
new file mode 100644
index 0000000..7b1c168
--- /dev/null
+++ b/drivers/video/imacfb.c
@@ -0,0 +1,345 @@
+/*
+ * framebuffer driver for Intel Based Mac's
+ *
+ * (c) 2006 Edgar Hucek <gimli@dark-green.com>
+ * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+
+#include <asm/io.h>
+
+#include <video/vga.h>
+
+typedef enum _MAC_TYPE {
+	M_I17,
+	M_I20,
+	M_MINI,
+	M_MACBOOK,
+	M_NEW
+} MAC_TYPE;
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo imacfb_defined __initdata = {
+	.activate		= FB_ACTIVATE_NOW,
+	.height			= -1,
+	.width			= -1,
+	.right_margin		= 32,
+	.upper_margin		= 16,
+	.lower_margin		= 4,
+	.vsync_len		= 4,
+	.vmode			= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo imacfb_fix __initdata = {
+	.id			= "IMAC VGA",
+	.type			= FB_TYPE_PACKED_PIXELS,
+	.accel			= FB_ACCEL_NONE,
+	.visual			= FB_VISUAL_TRUECOLOR,
+};
+
+static int inverse;
+static int model		= M_NEW;
+static int manual_height;
+static int manual_width;
+
+#define	DEFAULT_FB_MEM	1024*1024*16
+
+/* --------------------------------------------------------------------- */
+
+static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *info)
+{
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	if (regno < 16) {
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+	}
+	return 0;
+}
+
+static struct fb_ops imacfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= imacfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __init imacfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+
+		if (!strcmp(this_opt, "inverse"))
+			inverse = 1;
+		else if (!strcmp(this_opt, "i17"))
+			model = M_I17;
+		else if (!strcmp(this_opt, "i20"))
+			model = M_I20;
+		else if (!strcmp(this_opt, "mini"))
+			model = M_MINI;
+		else if (!strcmp(this_opt, "macbook"))
+			model = M_MACBOOK;
+		else if (!strncmp(this_opt, "height:", 7))
+			manual_height = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "width:", 6))
+			manual_width = simple_strtoul(this_opt+6, NULL, 0);
+	}
+	return 0;
+}
+
+static int __init imacfb_probe(struct platform_device *dev)
+{
+	struct fb_info *info;
+	int err;
+	unsigned int size_vmode;
+	unsigned int size_remap;
+	unsigned int size_total;
+
+	screen_info.lfb_depth = 32;
+	screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
+	screen_info.pages=1;
+	screen_info.blue_size = 8;
+	screen_info.blue_pos = 0;
+	screen_info.green_size = 8;
+	screen_info.green_pos = 8;
+	screen_info.red_size = 8;
+	screen_info.red_pos = 16;
+	screen_info.rsvd_size = 8;
+	screen_info.rsvd_pos = 24;
+
+	switch (model) {
+	case M_I17:
+		screen_info.lfb_width = 1440;
+		screen_info.lfb_height = 900;
+		screen_info.lfb_linelength = 1472 * 4;
+		screen_info.lfb_base = 0x80010000;
+		break;
+	case M_NEW:
+	case M_I20:
+		screen_info.lfb_width = 1680;
+		screen_info.lfb_height = 1050;
+		screen_info.lfb_linelength = 1728 * 4;
+		screen_info.lfb_base = 0x80010000;
+		break;
+	case M_MINI:
+		screen_info.lfb_width = 1024;
+		screen_info.lfb_height = 768;
+		screen_info.lfb_linelength = 2048 * 4;
+		screen_info.lfb_base = 0x80000000;
+		break;
+	case M_MACBOOK:
+		screen_info.lfb_width = 1280;
+		screen_info.lfb_height = 800;
+		screen_info.lfb_linelength = 2048 * 4;
+		screen_info.lfb_base = 0x80000000;
+		break;
+ 	}
+
+	/* if the user wants to manually specify height/width,
+	   we will override the defaults */
+	/* TODO: eventually get auto-detection working */
+	if (manual_height > 0)
+		screen_info.lfb_height = manual_height;
+	if (manual_width > 0)
+		screen_info.lfb_width = manual_width;
+
+	imacfb_fix.smem_start = screen_info.lfb_base;
+	imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
+	imacfb_defined.xres = screen_info.lfb_width;
+	imacfb_defined.yres = screen_info.lfb_height;
+	imacfb_fix.line_length = screen_info.lfb_linelength;
+
+	/*   size_vmode -- that is the amount of memory needed for the
+	 *                 used video mode, i.e. the minimum amount of
+	 *                 memory we need. */
+	size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
+
+	/*   size_total -- all video memory we have. Used for
+	 *                 entries, ressource allocation and bounds
+	 *                 checking. */
+	size_total = screen_info.lfb_size * 65536;
+	if (size_total < size_vmode)
+		size_total = size_vmode;
+
+	/*   size_remap -- the amount of video memory we are going to
+	 *                 use for imacfb.  With modern cards it is no
+	 *                 option to simply use size_total as that
+	 *                 wastes plenty of kernel address space. */
+	size_remap  = size_vmode * 2;
+	if (size_remap < size_vmode)
+		size_remap = size_vmode;
+	if (size_remap > size_total)
+		size_remap = size_total;
+	imacfb_fix.smem_len = size_remap;
+
+#ifndef __i386__
+	screen_info.imacpm_seg = 0;
+#endif
+
+	if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
+		printk(KERN_WARNING
+		       "imacfb: cannot reserve video memory at 0x%lx\n",
+			imacfb_fix.smem_start);
+		/* We cannot make this fatal. Sometimes this comes from magic
+		   spaces our resource handlers simply don't know about */
+	}
+
+	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+	if (!info) {
+		err = -ENOMEM;
+		goto err_release_mem;
+	}
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+
+	info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR "imacfb: abort, cannot ioremap video memory "
+				"0x%x @ 0x%lx\n",
+			imacfb_fix.smem_len, imacfb_fix.smem_start);
+		err = -EIO;
+		goto err_unmap;
+	}
+
+	printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
+	       "using %dk, total %dk\n",
+	       imacfb_fix.smem_start, info->screen_base,
+	       size_remap/1024, size_total/1024);
+	printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+	       imacfb_defined.xres, imacfb_defined.yres,
+	       imacfb_defined.bits_per_pixel, imacfb_fix.line_length,
+	       screen_info.pages);
+
+	imacfb_defined.xres_virtual = imacfb_defined.xres;
+	imacfb_defined.yres_virtual = imacfb_fix.smem_len /
+					imacfb_fix.line_length;
+	printk(KERN_INFO "imacfb: scrolling: redraw\n");
+	imacfb_defined.yres_virtual = imacfb_defined.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	imacfb_defined.pixclock     = 10000000 / imacfb_defined.xres *
+					1000 / imacfb_defined.yres;
+	imacfb_defined.left_margin  = (imacfb_defined.xres / 8) & 0xf8;
+	imacfb_defined.hsync_len    = (imacfb_defined.xres / 8) & 0xf8;
+
+	imacfb_defined.red.offset    = screen_info.red_pos;
+	imacfb_defined.red.length    = screen_info.red_size;
+	imacfb_defined.green.offset  = screen_info.green_pos;
+	imacfb_defined.green.length  = screen_info.green_size;
+	imacfb_defined.blue.offset   = screen_info.blue_pos;
+	imacfb_defined.blue.length   = screen_info.blue_size;
+	imacfb_defined.transp.offset = screen_info.rsvd_pos;
+	imacfb_defined.transp.length = screen_info.rsvd_size;
+
+	printk(KERN_INFO "imacfb: %s: "
+	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+	       "Truecolor",
+	       screen_info.rsvd_size,
+	       screen_info.red_size,
+	       screen_info.green_size,
+	       screen_info.blue_size,
+	       screen_info.rsvd_pos,
+	       screen_info.red_pos,
+	       screen_info.green_pos,
+	       screen_info.blue_pos);
+
+	imacfb_fix.ypanstep  = 0;
+	imacfb_fix.ywrapstep = 0;
+
+	/* request failure does not faze us, as vgacon probably has this
+	 * region already (FIXME) */
+	request_region(0x3c0, 32, "imacfb");
+
+	info->fbops = &imacfb_ops;
+	info->var = imacfb_defined;
+	info->fix = imacfb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		err = -ENOMEM;
+		goto err_unmap;
+	}
+	if (register_framebuffer(info)<0) {
+		err = -EINVAL;
+		goto err_fb_dealoc;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+	return 0;
+
+err_fb_dealoc:
+	fb_dealloc_cmap(&info->cmap);
+err_unmap:
+	iounmap(info->screen_base);
+	framebuffer_release(info);
+err_release_mem:
+	release_mem_region(imacfb_fix.smem_start, size_total);
+	return err;
+}
+
+static struct platform_driver imacfb_driver = {
+	.probe	= imacfb_probe,
+	.driver	= {
+		.name	= "imacfb",
+	},
+};
+
+static struct platform_device imacfb_device = {
+	.name	= "imacfb",
+};
+
+static int __init imacfb_init(void)
+{
+	int ret;
+	char *option = NULL;
+
+	/* ignore error return of fb_get_options */
+	fb_get_options("imacfb", &option);
+	imacfb_setup(option);
+	ret = platform_driver_register(&imacfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&imacfb_device);
+		if (ret)
+			platform_driver_unregister(&imacfb_driver);
+	}
+	return ret;
+}
+module_init(imacfb_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index c0385c6..d21321c 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -327,7 +327,6 @@
     }
     return -EINVAL;
 }
-EXPORT_SYMBOL(mac_var_to_vmode);
 
 /**
  *	mac_map_monitor_sense - Convert monitor sense to vmode
@@ -371,8 +370,9 @@
  *
  */
 
-int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
-			 const char *mode_option, unsigned int default_bpp)
+int __devinit mac_find_mode(struct fb_var_screeninfo *var,
+			    struct fb_info *info, const char *mode_option,
+			    unsigned int default_bpp)
 {
     const struct fb_videomode *db = NULL;
     unsigned int dbsize = 0;
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h
index 232f5a0..babeb81 100644
--- a/drivers/video/macmodes.h
+++ b/drivers/video/macmodes.h
@@ -55,9 +55,10 @@
 extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
 			    int *cmode);
 extern int mac_map_monitor_sense(int sense);
-extern int __init mac_find_mode(struct fb_var_screeninfo *var,
-				struct fb_info *info, const char *mode_option,
-				unsigned int default_bpp);
+extern int __devinit mac_find_mode(struct fb_var_screeninfo *var,
+				   struct fb_info *info,
+				   const char *mode_option,
+				   unsigned int default_bpp);
 
 
     /*
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 23c1827..f4ddd34 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -102,6 +102,8 @@
 #include <linux/config.h>
 #include <linux/version.h>
 
+#define __OLD_VIDIOC_
+
 #include "matroxfb_base.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_accel.h"
@@ -158,9 +160,9 @@
 
 	/* Make sure that displays are compatible */
 	if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
-	         && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
-	         && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
-	         ) {
+		 && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
+		 && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
+		 ) {
 		switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
 			case 16:
 			case 32:
@@ -224,7 +226,7 @@
 
 int matroxfb_enable_irq(WPMINFO int reenable) {
 	u_int32_t bm;
-	
+
 	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
 		bm = 0x220;
 	else
@@ -241,7 +243,7 @@
 		mga_outl(M_IEN, mga_inl(M_IEN) | bm);
 	} else if (reenable) {
 		u_int32_t ien;
-		
+
 		ien = mga_inl(M_IEN);
 		if ((ien & bm) != bm) {
 			printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
@@ -347,7 +349,7 @@
 		mga_setr(M_EXTVGA_INDEX, 0x00, p2);
 	}
 	matroxfb_DAC_unlock_irqrestore(flags);
-	
+
 	update_crtc2(PMINFO pos);
 
 	CRITEND
@@ -390,7 +392,7 @@
 static int matroxfb_open(struct fb_info *info, int user)
 {
 	MINFO_FROM_INFO(info);
-	
+
 	DBG_LOOP(__FUNCTION__)
 
 	if (ACCESS_FBINFO(dead)) {
@@ -406,7 +408,7 @@
 static int matroxfb_release(struct fb_info *info, int user)
 {
 	MINFO_FROM_INFO(info);
-	
+
 	DBG_LOOP(__FUNCTION__)
 
 	if (user) {
@@ -854,7 +856,7 @@
 		vblank->flags |= FB_VBLANK_VBLANKING;
 	if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
 		vblank->flags |= FB_VBLANK_HAVE_COUNT;
-		/* Only one writer, aligned int value... 
+		/* Only one writer, aligned int value...
 		   it should work without lock and without atomic_t */
 		vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
 	}
@@ -870,7 +872,7 @@
 {
 	void __user *argp = (void __user *)arg;
 	MINFO_FROM_INFO(info);
-	
+
 	DBG(__FUNCTION__)
 
 	if (ACCESS_FBINFO(dead)) {
@@ -1081,7 +1083,7 @@
 		case VIDIOC_QUERYCAP:
 			{
 				struct v4l2_capability r;
-				
+
 				memset(&r, 0, sizeof(r));
 				strcpy(r.driver, "matroxfb");
 				strcpy(r.card, "Matrox");
@@ -1091,7 +1093,7 @@
 				if (copy_to_user(argp, &r, sizeof(r)))
 					return -EFAULT;
 				return 0;
-				
+
 			}
 		case VIDIOC_QUERYCTRL:
 			{
@@ -1690,8 +1692,8 @@
 		pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
 		mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
 		mga_option |= MX_OPTION_BSWAP;
-                /* disable palette snooping */
-                cmd &= ~PCI_COMMAND_VGA_PALETTE;
+		/* disable palette snooping */
+		cmd &= ~PCI_COMMAND_VGA_PALETTE;
 		if (pci_dev_present(intel_82437)) {
 			if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
 				printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
@@ -1809,12 +1811,12 @@
 
 		if (fv) {
 			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
-			          + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+				  + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
 			if ((tmp < fh) || (fh == 0)) fh = tmp;
 		}
 		if (fh) {
 			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
-			          + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+				  + vesafb_defined.right_margin + vesafb_defined.hsync_len);
 			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
 		}
 		tmp = (maxclk + 499) / 500;
@@ -1890,14 +1892,14 @@
 
 	/* there is no console on this fb... but we have to initialize hardware
 	 * until someone tells me what is proper thing to do */
- 	if (!ACCESS_FBINFO(initialized)) {
- 		printk(KERN_INFO "fb%d: initializing hardware\n",
- 		       ACCESS_FBINFO(fbcon.node));
- 		/* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
- 		 * already before, so register_framebuffer works correctly. */
- 		vesafb_defined.activate |= FB_ACTIVATE_FORCE;
- 		fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
- 	}
+	if (!ACCESS_FBINFO(initialized)) {
+		printk(KERN_INFO "fb%d: initializing hardware\n",
+		       ACCESS_FBINFO(fbcon.node));
+		/* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+		 * already before, so register_framebuffer works correctly. */
+		vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+		fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
+	}
 
 	return 0;
 failVideoIO:;
@@ -2356,7 +2358,7 @@
 		else if (!strncmp(this_opt, "dfp:", 4)) {
 			dfp_type = simple_strtoul(this_opt+4, NULL, 0);
 			dfp = 1;
-		}	
+		}
 #ifdef CONFIG_PPC_PMAC
 		else if (!strncmp(this_opt, "vmode:", 6)) {
 			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 26a1c61..ff54546 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -259,6 +259,10 @@
 	/* 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
+    }, {
+	/* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
+	NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5,
+	0, FB_VMODE_NONINTERLACED
     },
 };
 
@@ -787,8 +791,9 @@
 			if (diff > d) {
 				diff = d;
 				best = mode;
-			} else if (diff == d && mode->refresh > best->refresh)
-			    best = mode;
+			} else if (diff == d && best &&
+				   mode->refresh > best->refresh)
+				best = mode;
 		}
 	}
 	return best;
@@ -1016,8 +1021,6 @@
 EXPORT_SYMBOL(fb_var_to_videomode);
 EXPORT_SYMBOL(fb_mode_is_equal);
 EXPORT_SYMBOL(fb_add_videomode);
-EXPORT_SYMBOL(fb_delete_videomode);
-EXPORT_SYMBOL(fb_destroy_modelist);
 EXPORT_SYMBOL(fb_match_mode);
 EXPORT_SYMBOL(fb_find_best_mode);
 EXPORT_SYMBOL(fb_find_nearest_mode);
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 24b12f7..2f156b7 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -1333,17 +1333,22 @@
 	 *  run "setterm -powersave powerdown" to take advantage
 	 */
 	struct neofb_par *par = info->par;
-	int seqflags, lcdflags, dpmsflags, reg;
-
+	int seqflags, lcdflags, dpmsflags, reg, tmpdisp;
 
 	/*
-	 * Reload the value stored in the register, if sensible. It might have
-	 * been changed via FN keystroke.
+	 * Read back the register bits related to display configuration. They might
+	 * have been changed underneath the driver via Fn key stroke.
+	 */
+	neoUnlock();
+	tmpdisp = vga_rgfx(NULL, 0x20) & 0x03;
+	neoLock(&par->state);
+
+	/* In case we blank the screen, we want to store the possibly new
+	 * configuration in the driver. During un-blank, we re-apply this setting,
+	 * since the LCD bit will be cleared in order to switch off the backlight.
 	 */
 	if (par->PanelDispCntlRegRead) {
-		neoUnlock();
-		par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
-		neoLock(&par->state);
+		par->PanelDispCntlReg1 = tmpdisp;
 	}
 	par->PanelDispCntlRegRead = !blank_mode;
 
@@ -1378,12 +1383,21 @@
 		break;
 	case FB_BLANK_NORMAL:		/* just blank screen (backlight stays on) */
 		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
-		lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+		/*
+		 * During a blank operation with the LID shut, we might store "LCD off"
+		 * by mistake. Due to timing issues, the BIOS may switch the lights
+		 * back on, and we turn it back off once we "unblank".
+		 *
+		 * So here is an attempt to implement ">=" - if we are in the process
+		 * of unblanking, and the LCD bit is unset in the driver but set in the
+		 * register, we must keep it.
+		 */
+		lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
 		dpmsflags = 0x00;	/* no hsync/vsync suppression */
 		break;
 	case FB_BLANK_UNBLANK:		/* unblank */
 		seqflags = 0;			/* Enable sequencer */
-		lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+		lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
 		dpmsflags = 0x00;	/* no hsync/vsync suppression */
 #ifdef CONFIG_TOSHIBA
 		/* Do we still need this ? */
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
index 690d37e..ca47432 100644
--- a/drivers/video/nvidia/Makefile
+++ b/drivers/video/nvidia/Makefile
@@ -7,6 +7,7 @@
 nvidiafb-y                       := nvidia.o nv_hw.o nv_setup.o \
 			            nv_accel.o
 nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
+nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT)  += nv_backlight.o
 nvidiafb-$(CONFIG_PPC_OF)	 += nv_of.o
 
-nvidiafb-objs                    := $(nvidiafb-y)
\ No newline at end of file
+nvidiafb-objs                    := $(nvidiafb-y)
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
new file mode 100644
index 0000000..1c1c10c
--- /dev/null
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -0,0 +1,175 @@
+/*
+ * Backlight code for nVidia based graphic cards
+ *
+ * Copyright 2004 Antonino Daplas <adaplas@pol.net>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * 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/backlight.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#include <asm/machdep.h>
+#endif
+
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+
+static struct backlight_properties nvidia_bl_data;
+
+static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
+		int level)
+{
+	struct fb_info *info = pci_get_drvdata(par->pci_dev);
+	int nlevel;
+
+	/* Get and convert the value */
+	mutex_lock(&info->bl_mutex);
+	nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+	mutex_unlock(&info->bl_mutex);
+
+	if (nlevel < 0)
+		nlevel = 0;
+	else if (nlevel < MIN_LEVEL)
+		nlevel = MIN_LEVEL;
+	else if (nlevel > MAX_LEVEL)
+		nlevel = MAX_LEVEL;
+
+	return nlevel;
+}
+
+static int nvidia_bl_update_status(struct backlight_device *bd)
+{
+	struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+	u32 tmp_pcrt, tmp_pmc, fpcontrol;
+	int level;
+
+	if (!par->FlatPanel)
+		return 0;
+
+	if (bd->props->power != FB_BLANK_UNBLANK ||
+	    bd->props->fb_blank != FB_BLANK_UNBLANK)
+		level = 0;
+	else
+		level = bd->props->brightness;
+
+	tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
+	tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
+	fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
+
+	if (level > 0) {
+		tmp_pcrt |= 0x1;
+		tmp_pmc |= (1 << 31); /* backlight bit */
+		tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
+		fpcontrol |= par->fpSyncs;
+	} else
+		fpcontrol |= 0x20000022;
+
+	NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
+	NV_WR32(par->PMC, 0x10F0, tmp_pmc);
+	NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
+
+	return 0;
+}
+
+static int nvidia_bl_get_brightness(struct backlight_device *bd)
+{
+	return bd->props->brightness;
+}
+
+static struct backlight_properties nvidia_bl_data = {
+	.owner		= THIS_MODULE,
+	.get_brightness = nvidia_bl_get_brightness,
+	.update_status	= nvidia_bl_update_status,
+	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void nvidia_bl_init(struct nvidia_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pci_dev);
+	struct backlight_device *bd;
+	char name[12];
+
+	if (!par->FlatPanel)
+		return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if (!machine_is(powermac) ||
+	    !pmac_has_backlight_type("mnca"))
+		return;
+#endif
+
+	snprintf(name, sizeof(name), "nvidiabl%d", info->node);
+
+	bd = backlight_device_register(name, par, &nvidia_bl_data);
+	if (IS_ERR(bd)) {
+		info->bl_dev = NULL;
+		printk("nvidia: Backlight registration failed\n");
+		goto error;
+	}
+
+	mutex_lock(&info->bl_mutex);
+	info->bl_dev = bd;
+	fb_bl_default_curve(info, 0,
+		0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+		0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+	mutex_unlock(&info->bl_mutex);
+
+	up(&bd->sem);
+	bd->props->brightness = nvidia_bl_data.max_brightness;
+	bd->props->power = FB_BLANK_UNBLANK;
+	bd->props->update_status(bd);
+	down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+	if (!pmac_backlight)
+		pmac_backlight = bd;
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+	printk("nvidia: Backlight initialized (%s)\n", name);
+
+	return;
+
+error:
+	return;
+}
+
+void nvidia_bl_exit(struct nvidia_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pci_dev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+#endif
+
+	mutex_lock(&info->bl_mutex);
+	if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+		if (pmac_backlight == info->bl_dev)
+			pmac_backlight = NULL;
+#endif
+
+		backlight_device_unregister(info->bl_dev);
+
+		printk("nvidia: Backlight unloaded\n");
+	}
+	mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index 99c3a8e..9ed640d 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -886,7 +886,10 @@
 	case NV_ARCH_20:
 	case NV_ARCH_30:
 	default:
-		if (((par->Chipset & 0xffff) == 0x01A0) ||
+		if ((par->Chipset & 0xfff0) == 0x0240) {
+			state->arbitration0 = 256;
+			state->arbitration1 = 0x0480;
+		} else if (((par->Chipset & 0xffff) == 0x01A0) ||
 		    ((par->Chipset & 0xffff) == 0x01f0)) {
 			nForceUpdateArbitrationSettings(VClk,
 							pixelDepth * 8,
@@ -1235,6 +1238,7 @@
 					break;
 				case 0x0160:
 				case 0x01D0:
+				case 0x0240:
 					NV_WR32(par->PMC, 0x1700,
 						NV_RD32(par->PFB, 0x020C));
 					NV_WR32(par->PMC, 0x1704, 0);
@@ -1359,7 +1363,9 @@
 						if(((par->Chipset & 0xfff0)
 						    != 0x0160) &&
 						   ((par->Chipset & 0xfff0)
-						    != 0x0220))
+						    != 0x0220) &&
+						   ((par->Chipset & 0xfff0)
+						    != 0x240))
 							NV_WR32(par->PGRAPH,
 								0x6900 + i*4,
 								NV_RD32(par->PFB,
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index b149a69..6fba656 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -63,4 +63,14 @@
 			       const struct fb_image *image);
 extern int nvidiafb_sync(struct fb_info *info);
 extern u8 byte_rev[256];
+
+/* in nv_backlight.h */
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+extern void nvidia_bl_init(struct nvidia_par *par);
+extern void nvidia_bl_exit(struct nvidia_par *par);
+#else
+static inline void nvidia_bl_init(struct nvidia_par *par) {}
+static inline void nvidia_bl_exit(struct nvidia_par *par) {}
+#endif
+
 #endif				/* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 093ab99..7b5cffb 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/console.h>
+#include <linux/backlight.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -29,10 +30,6 @@
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #endif
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/machdep.h>
-#include <asm/backlight.h>
-#endif
 
 #include "nv_local.h"
 #include "nv_type.h"
@@ -70,359 +67,10 @@
 #define MAX_CURS		32
 
 static struct pci_device_id nvidiafb_pci_tbl[] = {
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0252,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0313,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0316,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0317,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x031D,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x031E,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x031F,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0329,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x032F,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0345,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0349,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x034B,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x034F,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x00c0,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x00cd,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0142,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0143,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0144,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0145,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0146,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0147,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0148,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0149,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x014b,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x14c,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x014d,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0160,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0162,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0163,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0165,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0169,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x016b,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x016c,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x016d,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x016e,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0210,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x021d,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x021e,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0220,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0221,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0222,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{PCI_VENDOR_ID_NVIDIA, 0x0228,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0,}			/* terminate list */
+	{PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0},
+	{ 0, }
 };
-
 MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
 
 /* command line data, set in nvidiafb_setup() */
@@ -470,75 +118,6 @@
 	.vmode = FB_VMODE_NONINTERLACED
 };
 
-/*
- * Backlight control
- */
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-static int nvidia_backlight_levels[] = {
-	0x158,
-	0x192,
-	0x1c6,
-	0x200,
-	0x234,
-	0x268,
-	0x2a2,
-	0x2d6,
-	0x310,
-	0x344,
-	0x378,
-	0x3b2,
-	0x3e6,
-	0x41a,
-	0x454,
-	0x534,
-};
-
-/* ------------------------------------------------------------------------- *
- *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-static int nvidia_set_backlight_enable(int on, int level, void *data)
-{
-	struct nvidia_par *par = data;
-	u32 tmp_pcrt, tmp_pmc, fpcontrol;
-
-	tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
-	tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
-	fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
-
-	if (on && (level > BACKLIGHT_OFF)) {
-		tmp_pcrt |= 0x1;
-		tmp_pmc |= (1 << 31);	// backlight bit
-		tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
-	}
-
-	if (on)
-		fpcontrol |= par->fpSyncs;
-	else
-		fpcontrol |= 0x20000022;
-
-	NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
-	NV_WR32(par->PMC, 0x10F0, tmp_pmc);
-	NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
-
-	return 0;
-}
-
-static int nvidia_set_backlight_level(int level, void *data)
-{
-	return nvidia_set_backlight_enable(1, level, data);
-}
-
-static struct backlight_controller nvidia_backlight_controller = {
-	nvidia_set_backlight_enable,
-	nvidia_set_backlight_level
-};
-
-#endif				/* CONFIG_PMAC_BACKLIGHT */
-
 static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
 				       u16 bg, u16 fg, u32 w, u32 h)
 {
@@ -1355,10 +934,15 @@
 	NVWriteSeq(par, 0x01, tmp);
 	NVWriteCrtc(par, 0x1a, vesa);
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (par->FlatPanel && machine_is(powermac)) {
-		set_backlight_enable(!blank);
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+	mutex_lock(&info->bl_mutex);
+	if (info->bl_dev) {
+		down(&info->bl_dev->sem);
+		info->bl_dev->props->power = blank;
+		info->bl_dev->props->update_status(info->bl_dev);
+		up(&info->bl_dev->sem);
 	}
+	mutex_unlock(&info->bl_mutex);
 #endif
 
 	NVTRACE_LEAVE();
@@ -1532,10 +1116,10 @@
 	struct nvidia_par *par = info->par;
 	u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
 
-	printk("nvidiafb: PCI id - %x\n", id);
+	printk(KERN_INFO PFX "Device ID: %x \n", id);
+
 	if ((id & 0xfff0) == 0x00f0) {
 		/* pci-e */
-		printk("nvidiafb: PCI-E card\n");
 		id = NV_RD32(par->REGS, 0x1800);
 
 		if ((id & 0x0000ffff) == 0x000010DE)
@@ -1543,9 +1127,9 @@
 		else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */
 			id = 0x10DE0000 | ((id << 8) & 0x0000ff00) |
                             ((id >> 8) & 0x000000ff);
+		printk(KERN_INFO PFX "Subsystem ID: %x \n", id);
 	}
 
-	printk("nvidiafb: Actual id - %x\n", id);
 	return id;
 }
 
@@ -1587,6 +1171,7 @@
 	case 0x0210:
 	case 0x0220:
 	case 0x0230:
+	case 0x0240:
 	case 0x0290:
 	case 0x0390:
 		arch = NV_ARCH_40;
@@ -1634,7 +1219,7 @@
 
 	if (pci_request_regions(pd, "nvidiafb")) {
 		printk(KERN_ERR PFX "cannot request PCI regions\n");
-		goto err_out_request;
+		goto err_out_enable;
 	}
 
 	par->FlatPanel = flatpanel;
@@ -1663,7 +1248,6 @@
 	}
 
 	par->Chipset = nvidia_get_chipset(info);
-	printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset);
 	par->Architecture = nvidia_get_arch(info);
 
 	if (par->Architecture == 0) {
@@ -1741,11 +1325,9 @@
 	       "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
 	       info->fix.id,
 	       par->FbMapSize / (1024 * 1024), info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (par->FlatPanel && machine_is(powermac))
-		register_backlight_controller(&nvidia_backlight_controller,
-					      par, "mnca");
-#endif
+
+	nvidia_bl_init(par);
+
 	NVTRACE_LEAVE();
 	return 0;
 
@@ -1756,10 +1338,8 @@
 	nvidia_delete_i2c_busses(par);
 err_out_arch:
 	iounmap(par->REGS);
-err_out_free_base0:
+ err_out_free_base0:
 	pci_release_regions(pd);
-err_out_request:
-	pci_disable_device(pd);
 err_out_enable:
 	kfree(info->pixmap.addr);
 err_out_kfree:
@@ -1775,6 +1355,8 @@
 
 	NVTRACE_ENTER();
 
+	nvidia_bl_exit(par);
+
 	unregister_framebuffer(info);
 #ifdef CONFIG_MTRR
 	if (par->mtrr.vram_valid)
@@ -1787,7 +1369,6 @@
 	nvidia_delete_i2c_busses(par);
 	iounmap(par->REGS);
 	pci_release_regions(pd);
-	pci_disable_device(pd);
 	kfree(info->pixmap.addr);
 	framebuffer_release(info);
 	pci_set_drvdata(pd, NULL);
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 3e9308f..12af58c 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -41,6 +41,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/backlight.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -272,34 +273,154 @@
 /*
  * Backlight control
  */
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+
+static struct backlight_properties riva_bl_data;
+
+static int riva_bl_get_level_brightness(struct riva_par *par,
+		int level)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	int nlevel;
+
+	/* Get and convert the value */
+	mutex_lock(&info->bl_mutex);
+	nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+	mutex_unlock(&info->bl_mutex);
+
+	if (nlevel < 0)
+		nlevel = 0;
+	else if (nlevel < MIN_LEVEL)
+		nlevel = MIN_LEVEL;
+	else if (nlevel > MAX_LEVEL)
+		nlevel = MAX_LEVEL;
+
+	return nlevel;
+}
+
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+	struct riva_par *par = class_get_devdata(&bd->class_dev);
+	U032 tmp_pcrt, tmp_pmc;
+	int level;
+
+	if (bd->props->power != FB_BLANK_UNBLANK ||
+	    bd->props->fb_blank != FB_BLANK_UNBLANK)
+		level = 0;
+	else
+		level = bd->props->brightness;
+
+	tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
+	tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+	if(level > 0) {
+		tmp_pcrt |= 0x1;
+		tmp_pmc |= (1 << 31); /* backlight bit */
+		tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
+	}
+	par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
+	par->riva.PMC[0x10F0/4] = tmp_pmc;
+
+	return 0;
+}
+
+static int riva_bl_get_brightness(struct backlight_device *bd)
+{
+	return bd->props->brightness;
+}
+
+static struct backlight_properties riva_bl_data = {
+	.owner    = THIS_MODULE,
+	.get_brightness = riva_bl_get_brightness,
+	.update_status	= riva_bl_update_status,
+	.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+static void riva_bl_init(struct riva_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+	struct backlight_device *bd;
+	char name[12];
+
+	if (!par->FlatPanel)
+		return;
+
 #ifdef CONFIG_PMAC_BACKLIGHT
+	if (!machine_is(powermac) ||
+	    !pmac_has_backlight_type("mnca"))
+		return;
+#endif
 
-static int riva_backlight_levels[] = {
-    0x158,
-    0x192,
-    0x1c6,
-    0x200,
-    0x234,
-    0x268,
-    0x2a2,
-    0x2d6,
-    0x310,
-    0x344,
-    0x378,
-    0x3b2,
-    0x3e6,
-    0x41a,
-    0x454,
-    0x534,
-};
+	snprintf(name, sizeof(name), "rivabl%d", info->node);
 
-static int riva_set_backlight_enable(int on, int level, void *data);
-static int riva_set_backlight_level(int level, void *data);
-static struct backlight_controller riva_backlight_controller = {
-	riva_set_backlight_enable,
-	riva_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
+	bd = backlight_device_register(name, par, &riva_bl_data);
+	if (IS_ERR(bd)) {
+		info->bl_dev = NULL;
+		printk("riva: Backlight registration failed\n");
+		goto error;
+	}
+
+	mutex_lock(&info->bl_mutex);
+	info->bl_dev = bd;
+	fb_bl_default_curve(info, 0,
+		0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+		0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+	mutex_unlock(&info->bl_mutex);
+
+	up(&bd->sem);
+	bd->props->brightness = riva_bl_data.max_brightness;
+	bd->props->power = FB_BLANK_UNBLANK;
+	bd->props->update_status(bd);
+	down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+	if (!pmac_backlight)
+		pmac_backlight = bd;
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+	printk("riva: Backlight initialized (%s)\n", name);
+
+	return;
+
+error:
+	return;
+}
+
+static void riva_bl_exit(struct riva_par *par)
+{
+	struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_lock(&pmac_backlight_mutex);
+#endif
+
+	mutex_lock(&info->bl_mutex);
+	if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+		if (pmac_backlight == info->bl_dev)
+			pmac_backlight = NULL;
+#endif
+
+		backlight_device_unregister(info->bl_dev);
+
+		printk("riva: Backlight unloaded\n");
+	}
+	mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+	mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#else
+static inline void riva_bl_init(struct riva_par *par) {}
+static inline void riva_bl_exit(struct riva_par *par) {}
+#endif /* CONFIG_FB_RIVA_BACKLIGHT */
 
 /* ------------------------------------------------------------------------- *
  *
@@ -973,36 +1094,6 @@
 
 /* ------------------------------------------------------------------------- *
  *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int riva_set_backlight_enable(int on, int level, void *data)
-{
-	struct riva_par *par = data;
-	U032 tmp_pcrt, tmp_pmc;
-
-	tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
-	tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
-	if(on && (level > BACKLIGHT_OFF)) {
-		tmp_pcrt |= 0x1;
-		tmp_pmc |= (1 << 31); // backlight bit
-		tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
-	}
-	par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
-	par->riva.PMC[0x10F0/4] = tmp_pmc;
-	return 0;
-}
-
-static int riva_set_backlight_level(int level, void *data)
-{
-	return riva_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-/* ------------------------------------------------------------------------- *
- *
  * framebuffer operations
  *
  * ------------------------------------------------------------------------- */
@@ -1247,10 +1338,15 @@
 	SEQout(par, 0x01, tmp);
 	CRTCout(par, 0x1a, vesa);
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if ( par->FlatPanel && machine_is(powermac)) {
-		set_backlight_enable(!blank);
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+	mutex_lock(&info->bl_mutex);
+	if (info->bl_dev) {
+		down(&info->bl_dev->sem);
+		info->bl_dev->props->power = blank;
+		info->bl_dev->props->update_status(info->bl_dev);
+		up(&info->bl_dev->sem);
 	}
+	mutex_unlock(&info->bl_mutex);
 #endif
 
 	NVTRACE_LEAVE();
@@ -2037,11 +2133,9 @@
 		RIVAFB_VERSION,
 		info->fix.smem_len / (1024 * 1024),
 		info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
-	if (default_par->FlatPanel && machine_is(powermac))
-		register_backlight_controller(&riva_backlight_controller,
-					      default_par, "mnca");
-#endif
+
+	riva_bl_init(info->par);
+
 	NVTRACE_LEAVE();
 	return 0;
 
@@ -2058,7 +2152,6 @@
 err_release_region:
 	pci_release_regions(pd);
 err_disable_device:
-	pci_disable_device(pd);
 err_free_pixmap:
 	kfree(info->pixmap.addr);
 err_framebuffer_release:
@@ -2074,6 +2167,8 @@
 	
 	NVTRACE_ENTER();
 
+	riva_bl_exit(par);
+
 #ifdef CONFIG_FB_RIVA_I2C
 	riva_delete_i2c_busses(par);
 	kfree(par->EDID);
@@ -2091,7 +2186,6 @@
 	if (par->riva.Architecture == NV_ARCH_03)
 		iounmap(par->riva.PRAMIN);
 	pci_release_regions(pd);
-	pci_disable_device(pd);
 	kfree(info->pixmap.addr);
 	framebuffer_release(info);
 	pci_set_drvdata(pd, NULL);
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 9451932..fbc4118 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -641,6 +641,7 @@
 	int ret;
 	int irq;
 	int i;
+	u32 lcdcon1;
 
 	mach_info = pdev->dev.platform_data;
 	if (mach_info == NULL) {
@@ -672,6 +673,11 @@
 
 	memcpy(&info->regs, &mach_info->regs, sizeof(info->regs));
 
+	/* Stop the video and unset ENVID if set */
+	info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
+	lcdcon1 = readl(S3C2410_LCDCON1);
+	writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+
 	info->mach_info		    = pdev->dev.platform_data;
 
 	fbinfo->fix.type	    = FB_TYPE_PACKED_PIXELS;
@@ -794,15 +800,14 @@
  * shutdown the lcd controller
 */
 
-static void s3c2410fb_stop_lcd(void)
+static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
 {
 	unsigned long flags;
-	unsigned long tmp;
 
 	local_irq_save(flags);
 
-	tmp = readl(S3C2410_LCDCON1);
-	writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+	fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
+	writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
 
 	local_irq_restore(flags);
 }
@@ -816,7 +821,7 @@
 	struct s3c2410fb_info *info = fbinfo->par;
 	int irq;
 
-	s3c2410fb_stop_lcd();
+	s3c2410fb_stop_lcd(info);
 	msleep(1);
 
 	s3c2410fb_unmap_video_memory(info);
@@ -844,7 +849,7 @@
 	struct fb_info	   *fbinfo = platform_get_drvdata(dev);
 	struct s3c2410fb_info *info = fbinfo->par;
 
-	s3c2410fb_stop_lcd();
+	s3c2410fb_stop_lcd(info);
 
 	/* sleep before disabling the clock, we need to ensure
 	 * the LCD DMA engine is not going to get back on the bus
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
index 58cfdfb..e648a6c 100644
--- a/drivers/video/savage/savagefb.h
+++ b/drivers/video/savage/savagefb.h
@@ -147,77 +147,7 @@
 	int	       interlaced;
 };
 
-
-/* --------------------------------------------------------------------- */
-
-#define NR_PALETTE	256
-
-
-struct savagefb_par;
-
-struct savagefb_i2c_chan {
-	struct savagefb_par *par;
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data algo;
-	volatile u8 __iomem *ioaddr;
-	u32   reg;
-};
-
-struct savagefb_par {
-	struct pci_dev *pcidev;
-	savage_chipset  chip;
-	struct savagefb_i2c_chan chan;
-	unsigned char   *edid;
-	u32 pseudo_palette[16];
-	int paletteEnabled;
-	int pm_state;
-	int display_type;
-	int dvi;
-	int crtonly;
-	int dacSpeedBpp;
-	int maxClock;
-	int minClock;
-	int numClocks;
-	int clock[4];
-	struct {
-		u8   __iomem *vbase;
-		u32    pbase;
-		u32    len;
-#ifdef CONFIG_MTRR
-		int    mtrr;
-#endif
-	} video;
-
-	struct {
-		volatile u8  __iomem *vbase;
-		u32           pbase;
-		u32           len;
-	} mmio;
-
-	volatile u32  __iomem *bci_base;
-	unsigned int  bci_ptr;
-
-	u32           cob_offset;
-	u32           cob_size;
-	int           cob_index;
-
-	void (*SavageWaitIdle) (struct savagefb_par *par);
-	void (*SavageWaitFifo) (struct savagefb_par *par, int space);
-
-	int MCLK, REFCLK, LCDclk;
-	int HorizScaleFactor;
-
-	/* Panels size */
-	int SavagePanelWidth;
-	int SavagePanelHeight;
-
-	struct {
-		u16 red, green, blue, transp;
-	} palette[NR_PALETTE];
-
-	int depth;
-	int vwidth;
-
+struct savage_reg {
 	unsigned char MiscOutReg;     /* Misc */
 	unsigned char CRTC[25];       /* Crtc Controller */
 	unsigned char Sequencer[5];   /* Video Sequencer */
@@ -238,6 +168,77 @@
 	unsigned int  STREAMS[22];	/* yuck, streams regs */
 	unsigned int  MMPR0, MMPR1, MMPR2, MMPR3;
 };
+/* --------------------------------------------------------------------- */
+
+#define NR_PALETTE	256
+
+
+struct savagefb_par;
+
+struct savagefb_i2c_chan {
+	struct savagefb_par *par;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+	volatile u8 __iomem *ioaddr;
+	u32   reg;
+};
+
+struct savagefb_par {
+	struct pci_dev *pcidev;
+	savage_chipset  chip;
+	struct savagefb_i2c_chan chan;
+	struct savage_reg state;
+	struct savage_reg save;
+	unsigned char   *edid;
+	u32 pseudo_palette[16];
+	int paletteEnabled;
+	int pm_state;
+	int display_type;
+	int dvi;
+	int crtonly;
+	int dacSpeedBpp;
+	int maxClock;
+	int minClock;
+	int numClocks;
+	int clock[4];
+	int MCLK, REFCLK, LCDclk;
+	struct {
+		u8   __iomem *vbase;
+		u32    pbase;
+		u32    len;
+#ifdef CONFIG_MTRR
+		int    mtrr;
+#endif
+	} video;
+
+	struct {
+		volatile u8  __iomem *vbase;
+		u32           pbase;
+		u32           len;
+	} mmio;
+
+	volatile u32  __iomem *bci_base;
+	unsigned int  bci_ptr;
+	u32           cob_offset;
+	u32           cob_size;
+	int           cob_index;
+
+	void (*SavageWaitIdle) (struct savagefb_par *par);
+	void (*SavageWaitFifo) (struct savagefb_par *par, int space);
+
+	int HorizScaleFactor;
+
+	/* Panels size */
+	int SavagePanelWidth;
+	int SavagePanelHeight;
+
+	struct {
+		u16 red, green, blue, transp;
+	} palette[NR_PALETTE];
+
+	int depth;
+	int vwidth;
+};
 
 #define BCI_BD_BW_DISABLE            0x10000000
 #define BCI_BD_SET_BPP(bd, bpp)      ((bd) |= (((bpp) & 0xFF) << 16))
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 0da624e..78883cf 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -86,15 +86,15 @@
 
 /* --------------------------------------------------------------------- */
 
-static void vgaHWSeqReset (struct savagefb_par *par, int start)
+static void vgaHWSeqReset(struct savagefb_par *par, int start)
 {
 	if (start)
-		VGAwSEQ (0x00, 0x01, par);	/* Synchronous Reset */
+		VGAwSEQ(0x00, 0x01, par);	/* Synchronous Reset */
 	else
-		VGAwSEQ (0x00, 0x03, par);	/* End Reset */
+		VGAwSEQ(0x00, 0x03, par);	/* End Reset */
 }
 
-static void vgaHWProtect (struct savagefb_par *par, int on)
+static void vgaHWProtect(struct savagefb_par *par, int on)
 {
 	unsigned char tmp;
 
@@ -102,10 +102,10 @@
 		/*
 		 * Turn off screen and disable sequencer.
 		 */
-		tmp = VGArSEQ (0x01, par);
+		tmp = VGArSEQ(0x01, par);
 
-		vgaHWSeqReset (par, 1);	        /* start synchronous reset */
-		VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */
+		vgaHWSeqReset(par, 1);	        /* start synchronous reset */
+		VGAwSEQ(0x01, tmp | 0x20, par);/* disable the display */
 
 		VGAenablePalette(par);
 	} else {
@@ -113,75 +113,76 @@
 		 * Reenable sequencer, then turn on screen.
 		 */
 
-		tmp = VGArSEQ (0x01, par);
+		tmp = VGArSEQ(0x01, par);
 
-		VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */
-		vgaHWSeqReset (par, 0);	        /* clear synchronous reset */
+		VGAwSEQ(0x01, tmp & ~0x20, par);/* reenable display */
+		vgaHWSeqReset(par, 0);	        /* clear synchronous reset */
 
 		VGAdisablePalette(par);
 	}
 }
 
-static void vgaHWRestore (struct savagefb_par  *par)
+static void vgaHWRestore(struct savagefb_par  *par, struct savage_reg *reg)
 {
 	int i;
 
-	VGAwMISC (par->MiscOutReg, par);
+	VGAwMISC(reg->MiscOutReg, par);
 
 	for (i = 1; i < 5; i++)
-		VGAwSEQ (i, par->Sequencer[i], par);
+		VGAwSEQ(i, reg->Sequencer[i], par);
 
 	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
 	   CRTC[17] */
-	VGAwCR (17, par->CRTC[17] & ~0x80, par);
+	VGAwCR(17, reg->CRTC[17] & ~0x80, par);
 
 	for (i = 0; i < 25; i++)
-		VGAwCR (i, par->CRTC[i], par);
+		VGAwCR(i, reg->CRTC[i], par);
 
 	for (i = 0; i < 9; i++)
-		VGAwGR (i, par->Graphics[i], par);
+		VGAwGR(i, reg->Graphics[i], par);
 
 	VGAenablePalette(par);
 
 	for (i = 0; i < 21; i++)
-		VGAwATTR (i, par->Attribute[i], par);
+		VGAwATTR(i, reg->Attribute[i], par);
 
 	VGAdisablePalette(par);
 }
 
-static void vgaHWInit (struct fb_var_screeninfo *var,
-		       struct savagefb_par            *par,
-		       struct xtimings                *timings)
+static void vgaHWInit(struct fb_var_screeninfo *var,
+		      struct savagefb_par            *par,
+		      struct xtimings                *timings,
+		      struct savage_reg              *reg)
 {
-	par->MiscOutReg = 0x23;
+	reg->MiscOutReg = 0x23;
 
 	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
-		par->MiscOutReg |= 0x40;
+		reg->MiscOutReg |= 0x40;
 
 	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
-		par->MiscOutReg |= 0x80;
+		reg->MiscOutReg |= 0x80;
 
 	/*
 	 * Time Sequencer
 	 */
-	par->Sequencer[0x00] = 0x00;
-	par->Sequencer[0x01] = 0x01;
-	par->Sequencer[0x02] = 0x0F;
-	par->Sequencer[0x03] = 0x00;          /* Font select */
-	par->Sequencer[0x04] = 0x0E;          /* Misc */
+	reg->Sequencer[0x00] = 0x00;
+	reg->Sequencer[0x01] = 0x01;
+	reg->Sequencer[0x02] = 0x0F;
+	reg->Sequencer[0x03] = 0x00;          /* Font select */
+	reg->Sequencer[0x04] = 0x0E;          /* Misc */
 
 	/*
 	 * CRTC Controller
 	 */
-	par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
-	par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
-	par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
-	par->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
-	par->CRTC[0x04] = (timings->HSyncStart >> 3);
-	par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
+	reg->CRTC[0x00] = (timings->HTotal >> 3) - 5;
+	reg->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
+	reg->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
+	reg->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
+	reg->CRTC[0x04] = (timings->HSyncStart >> 3);
+	reg->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
 		(((timings->HSyncEnd >> 3)) & 0x1f);
-	par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
-	par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
+	reg->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
+	reg->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
 		(((timings->VDisplay - 1) & 0x100) >> 7) |
 		((timings->VSyncStart & 0x100) >> 6) |
 		(((timings->VSyncStart - 1) & 0x100) >> 5) |
@@ -189,27 +190,27 @@
 		(((timings->VTotal - 2) & 0x200) >> 4) |
 		(((timings->VDisplay - 1) & 0x200) >> 3) |
 		((timings->VSyncStart & 0x200) >> 2);
-	par->CRTC[0x08] = 0x00;
-	par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
+	reg->CRTC[0x08] = 0x00;
+	reg->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
 
 	if (timings->dblscan)
-		par->CRTC[0x09] |= 0x80;
+		reg->CRTC[0x09] |= 0x80;
 
-	par->CRTC[0x0a] = 0x00;
-	par->CRTC[0x0b] = 0x00;
-	par->CRTC[0x0c] = 0x00;
-	par->CRTC[0x0d] = 0x00;
-	par->CRTC[0x0e] = 0x00;
-	par->CRTC[0x0f] = 0x00;
-	par->CRTC[0x10] = timings->VSyncStart & 0xff;
-	par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
-	par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
-	par->CRTC[0x13] = var->xres_virtual >> 4;
-	par->CRTC[0x14] = 0x00;
-	par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
-	par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
-	par->CRTC[0x17] = 0xc3;
-	par->CRTC[0x18] = 0xff;
+	reg->CRTC[0x0a] = 0x00;
+	reg->CRTC[0x0b] = 0x00;
+	reg->CRTC[0x0c] = 0x00;
+	reg->CRTC[0x0d] = 0x00;
+	reg->CRTC[0x0e] = 0x00;
+	reg->CRTC[0x0f] = 0x00;
+	reg->CRTC[0x10] = timings->VSyncStart & 0xff;
+	reg->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
+	reg->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
+	reg->CRTC[0x13] = var->xres_virtual >> 4;
+	reg->CRTC[0x14] = 0x00;
+	reg->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
+	reg->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
+	reg->CRTC[0x17] = 0xc3;
+	reg->CRTC[0x18] = 0xff;
 
 	/*
 	 * are these unnecessary?
@@ -220,38 +221,38 @@
 	/*
 	 * Graphics Display Controller
 	 */
-	par->Graphics[0x00] = 0x00;
-	par->Graphics[0x01] = 0x00;
-	par->Graphics[0x02] = 0x00;
-	par->Graphics[0x03] = 0x00;
-	par->Graphics[0x04] = 0x00;
-	par->Graphics[0x05] = 0x40;
-	par->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
-	par->Graphics[0x07] = 0x0F;
-	par->Graphics[0x08] = 0xFF;
+	reg->Graphics[0x00] = 0x00;
+	reg->Graphics[0x01] = 0x00;
+	reg->Graphics[0x02] = 0x00;
+	reg->Graphics[0x03] = 0x00;
+	reg->Graphics[0x04] = 0x00;
+	reg->Graphics[0x05] = 0x40;
+	reg->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
+	reg->Graphics[0x07] = 0x0F;
+	reg->Graphics[0x08] = 0xFF;
 
 
-	par->Attribute[0x00]  = 0x00; /* standard colormap translation */
-	par->Attribute[0x01]  = 0x01;
-	par->Attribute[0x02]  = 0x02;
-	par->Attribute[0x03]  = 0x03;
-	par->Attribute[0x04]  = 0x04;
-	par->Attribute[0x05]  = 0x05;
-	par->Attribute[0x06]  = 0x06;
-	par->Attribute[0x07]  = 0x07;
-	par->Attribute[0x08]  = 0x08;
-	par->Attribute[0x09]  = 0x09;
-	par->Attribute[0x0a] = 0x0A;
-	par->Attribute[0x0b] = 0x0B;
-	par->Attribute[0x0c] = 0x0C;
-	par->Attribute[0x0d] = 0x0D;
-	par->Attribute[0x0e] = 0x0E;
-	par->Attribute[0x0f] = 0x0F;
-	par->Attribute[0x10] = 0x41;
-	par->Attribute[0x11] = 0xFF;
-	par->Attribute[0x12] = 0x0F;
-	par->Attribute[0x13] = 0x00;
-	par->Attribute[0x14] = 0x00;
+	reg->Attribute[0x00]  = 0x00; /* standard colormap translation */
+	reg->Attribute[0x01]  = 0x01;
+	reg->Attribute[0x02]  = 0x02;
+	reg->Attribute[0x03]  = 0x03;
+	reg->Attribute[0x04]  = 0x04;
+	reg->Attribute[0x05]  = 0x05;
+	reg->Attribute[0x06]  = 0x06;
+	reg->Attribute[0x07]  = 0x07;
+	reg->Attribute[0x08]  = 0x08;
+	reg->Attribute[0x09]  = 0x09;
+	reg->Attribute[0x0a] = 0x0A;
+	reg->Attribute[0x0b] = 0x0B;
+	reg->Attribute[0x0c] = 0x0C;
+	reg->Attribute[0x0d] = 0x0D;
+	reg->Attribute[0x0e] = 0x0E;
+	reg->Attribute[0x0f] = 0x0F;
+	reg->Attribute[0x10] = 0x41;
+	reg->Attribute[0x11] = 0xFF;
+	reg->Attribute[0x12] = 0x0F;
+	reg->Attribute[0x13] = 0x00;
+	reg->Attribute[0x14] = 0x00;
 }
 
 /* -------------------- Hardware specific routines ------------------------- */
@@ -304,15 +305,15 @@
 	while ((savage_in32(0x48C60, par) & 0x009fffff));
 }
 
-
+#ifdef CONFIG_FB_SAVAGE_ACCEL
 static void
-SavageSetup2DEngine (struct savagefb_par  *par)
+SavageSetup2DEngine(struct savagefb_par  *par)
 {
 	unsigned long GlobalBitmapDescriptor;
 
 	GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
-	BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
-	BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
+	BCI_BD_SET_BPP(GlobalBitmapDescriptor, par->depth);
+	BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, par->vwidth);
 
 	switch(par->chip) {
 	case S3_SAVAGE3D:
@@ -361,32 +362,48 @@
 	vga_out8(0x3d5, 0x0c, par);
 
 	/* Set stride to use GBD. */
-	vga_out8 (0x3d4, 0x50, par);
-	vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par);
+	vga_out8(0x3d4, 0x50, par);
+	vga_out8(0x3d5, vga_in8(0x3d5, par) | 0xC1, par);
 
 	/* Enable 2D engine. */
-	vga_out8 (0x3d4, 0x40, par);
-	vga_out8 (0x3d5, 0x01, par);
+	vga_out8(0x3d4, 0x40, par);
+	vga_out8(0x3d5, 0x01, par);
 
-	savage_out32 (MONO_PAT_0, ~0, par);
-	savage_out32 (MONO_PAT_1, ~0, par);
+	savage_out32(MONO_PAT_0, ~0, par);
+	savage_out32(MONO_PAT_1, ~0, par);
 
 	/* Setup plane masks */
-	savage_out32 (0x8128, ~0, par); /* enable all write planes */
-	savage_out32 (0x812C, ~0, par); /* enable all read planes */
-	savage_out16 (0x8134, 0x27, par);
-	savage_out16 (0x8136, 0x07, par);
+	savage_out32(0x8128, ~0, par); /* enable all write planes */
+	savage_out32(0x812C, ~0, par); /* enable all read planes */
+	savage_out16(0x8134, 0x27, par);
+	savage_out16(0x8136, 0x07, par);
 
 	/* Now set the GBD */
 	par->bci_ptr = 0;
-	par->SavageWaitFifo (par, 4);
+	par->SavageWaitFifo(par, 4);
 
-	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
-	BCI_SEND( 0 );
-	BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
-	BCI_SEND( GlobalBitmapDescriptor );
+	BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1);
+	BCI_SEND(0);
+	BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2);
+	BCI_SEND(GlobalBitmapDescriptor);
 }
 
+static void savagefb_set_clip(struct fb_info *info)
+{
+	struct savagefb_par *par = info->par;
+	int cmd;
+
+	cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
+	par->bci_ptr = 0;
+	par->SavageWaitFifo(par,3);
+	BCI_SEND(cmd);
+	BCI_SEND(BCI_CLIP_TL(0, 0));
+	BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
+}
+#else
+static void SavageSetup2DEngine(struct savagefb_par  *par) {}
+
+#endif
 
 static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
 			    int min_n2, int max_n2, long freq_min,
@@ -398,11 +415,11 @@
 	unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
 
 	if (freq < freq_min / (1 << max_n2)) {
-		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+		printk(KERN_ERR "invalid frequency %ld Khz\n", freq);
 		freq = freq_min / (1 << max_n2);
 	}
 	if (freq > freq_max / (1 << min_n2)) {
-		printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+		printk(KERN_ERR "invalid frequency %ld Khz\n", freq);
 		freq = freq_max / (1 << min_n2);
 	}
 
@@ -453,12 +470,12 @@
 				BASE_FREQ;
 			if (m < min_m + 2 || m > 127+2)
 				continue;
-			if((m * BASE_FREQ >= freq_min * n1) &&
-			   (m * BASE_FREQ <= freq_max * n1)) {
+			if ((m * BASE_FREQ >= freq_min * n1) &&
+			    (m * BASE_FREQ <= freq_max * n1)) {
 				diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
-				if(diff < 0)
+				if (diff < 0)
 					diff = -diff;
-				if(diff < best_diff) {
+				if (diff < best_diff) {
 					best_diff = diff;
 					best_m = m;
 					best_n1 = n1;
@@ -468,7 +485,7 @@
 		}
 	}
 
-	if(max_n1 == 63)
+	if (max_n1 == 63)
 		*ndiv = (best_n1 - 2) | (best_n2 << 6);
 	else
 		*ndiv = (best_n1 - 2) | (best_n2 << 5);
@@ -488,23 +505,23 @@
 	int vgaCRReg = 0x3d5;
 
 	printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
-	       "xF" );
+	       "xF");
 
-	for( i = 0; i < 0x70; i++ ) {
-		if( !(i % 16) )
-			printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
-		vga_out8( 0x3c4, i, par);
-		printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) );
+	for (i = 0; i < 0x70; i++) {
+		if (!(i % 16))
+			printk(KERN_DEBUG "\nSR%xx ", i >> 4);
+		vga_out8(0x3c4, i, par);
+		printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par));
 	}
 
 	printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
-	       "xD xE xF" );
+	       "xD xE xF");
 
-	for( i = 0; i < 0xB7; i++ ) {
-		if( !(i % 16) )
-			printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
-		vga_out8( vgaCRIndex, i, par);
-		printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) );
+	for (i = 0; i < 0xB7; i++) {
+		if (!(i % 16))
+			printk(KERN_DEBUG "\nCR%xx ", i >> 4);
+		vga_out8(vgaCRIndex, i, par);
+		printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par));
 	}
 
 	printk(KERN_DEBUG "\n\n");
@@ -513,156 +530,309 @@
 
 /* --------------------------------------------------------------------- */
 
-static void savage_get_default_par(struct savagefb_par *par)
+static void savage_get_default_par(struct savagefb_par *par, struct savage_reg *reg)
 {
 	unsigned char cr3a, cr53, cr66;
 
-	vga_out16 (0x3d4, 0x4838, par);
-	vga_out16 (0x3d4, 0xa039, par);
-	vga_out16 (0x3c4, 0x0608, par);
+	vga_out16(0x3d4, 0x4838, par);
+	vga_out16(0x3d4, 0xa039, par);
+	vga_out16(0x3c4, 0x0608, par);
 
-	vga_out8 (0x3d4, 0x66, par);
-	cr66 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr66 | 0x80, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	cr3a = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr3a | 0x80, par);
-	vga_out8 (0x3d4, 0x53, par);
-	cr53 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr53 & 0x7f, par);
+	vga_out8(0x3d4, 0x66, par);
+	cr66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr66 | 0x80, par);
+	vga_out8(0x3d4, 0x3a, par);
+	cr3a = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr3a | 0x80, par);
+	vga_out8(0x3d4, 0x53, par);
+	cr53 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr53 & 0x7f, par);
 
-	vga_out8 (0x3d4, 0x66, par);
-	vga_out8 (0x3d5, cr66, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	vga_out8 (0x3d5, cr3a, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
 
-	vga_out8 (0x3d4, 0x66, par);
-	vga_out8 (0x3d5, cr66, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	vga_out8 (0x3d5, cr3a, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
 
 	/* unlock extended seq regs */
-	vga_out8 (0x3c4, 0x08, par);
-	par->SR08 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c5, 0x06, par);
+	vga_out8(0x3c4, 0x08, par);
+	reg->SR08 = vga_in8(0x3c5, par);
+	vga_out8(0x3c5, 0x06, par);
 
 	/* now save all the extended regs we need */
-	vga_out8 (0x3d4, 0x31, par);
-	par->CR31 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x32, par);
-	par->CR32 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x34, par);
-	par->CR34 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x36, par);
-	par->CR36 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	par->CR3A = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x40, par);
-	par->CR40 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x42, par);
-	par->CR42 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x45, par);
-	par->CR45 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x50, par);
-	par->CR50 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x51, par);
-	par->CR51 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x53, par);
-	par->CR53 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x58, par);
-	par->CR58 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x60, par);
-	par->CR60 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x66, par);
-	par->CR66 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x67, par);
-	par->CR67 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x68, par);
-	par->CR68 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x69, par);
-	par->CR69 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x6f, par);
-	par->CR6F = vga_in8 (0x3d5, par);
+	vga_out8(0x3d4, 0x31, par);
+	reg->CR31 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x32, par);
+	reg->CR32 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x34, par);
+	reg->CR34 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x36, par);
+	reg->CR36 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x3a, par);
+	reg->CR3A = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x40, par);
+	reg->CR40 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x42, par);
+	reg->CR42 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x45, par);
+	reg->CR45 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x50, par);
+	reg->CR50 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x51, par);
+	reg->CR51 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x53, par);
+	reg->CR53 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x58, par);
+	reg->CR58 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x60, par);
+	reg->CR60 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x66, par);
+	reg->CR66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x67, par);
+	reg->CR67 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x68, par);
+	reg->CR68 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x69, par);
+	reg->CR69 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x6f, par);
+	reg->CR6F = vga_in8(0x3d5, par);
 
-	vga_out8 (0x3d4, 0x33, par);
-	par->CR33 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x86, par);
-	par->CR86 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x88, par);
-	par->CR88 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x90, par);
-	par->CR90 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x91, par);
-	par->CR91 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0xb0, par);
-	par->CRB0 = vga_in8 (0x3d5, par) | 0x80;
+	vga_out8(0x3d4, 0x33, par);
+	reg->CR33 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x86, par);
+	reg->CR86 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x88, par);
+	reg->CR88 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x90, par);
+	reg->CR90 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x91, par);
+	reg->CR91 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0xb0, par);
+	reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
 
 	/* extended mode timing regs */
-	vga_out8 (0x3d4, 0x3b, par);
-	par->CR3B = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x3c, par);
-	par->CR3C = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x43, par);
-	par->CR43 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x5d, par);
-	par->CR5D = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x5e, par);
-	par->CR5E = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x65, par);
-	par->CR65 = vga_in8 (0x3d5, par);
+	vga_out8(0x3d4, 0x3b, par);
+	reg->CR3B = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x3c, par);
+	reg->CR3C = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x43, par);
+	reg->CR43 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x5d, par);
+	reg->CR5D = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x5e, par);
+	reg->CR5E = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x65, par);
+	reg->CR65 = vga_in8(0x3d5, par);
 
 	/* save seq extended regs for DCLK PLL programming */
-	vga_out8 (0x3c4, 0x0e, par);
-	par->SR0E = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x0f, par);
-	par->SR0F = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x10, par);
-	par->SR10 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x11, par);
-	par->SR11 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x12, par);
-	par->SR12 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x13, par);
-	par->SR13 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x29, par);
-	par->SR29 = vga_in8 (0x3c5, par);
+	vga_out8(0x3c4, 0x0e, par);
+	reg->SR0E = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x0f, par);
+	reg->SR0F = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x10, par);
+	reg->SR10 = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x11, par);
+	reg->SR11 = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x12, par);
+	reg->SR12 = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x13, par);
+	reg->SR13 = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x29, par);
+	reg->SR29 = vga_in8(0x3c5, par);
 
-	vga_out8 (0x3c4, 0x15, par);
-	par->SR15 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x30, par);
-	par->SR30 = vga_in8 (0x3c5, par);
-	vga_out8 (0x3c4, 0x18, par);
-	par->SR18 = vga_in8 (0x3c5, par);
+	vga_out8(0x3c4, 0x15, par);
+	reg->SR15 = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x30, par);
+	reg->SR30 = vga_in8(0x3c5, par);
+	vga_out8(0x3c4, 0x18, par);
+	reg->SR18 = vga_in8(0x3c5, par);
 
 	/* Save flat panel expansion regsters. */
 	if (par->chip == S3_SAVAGE_MX) {
 		int i;
 
 		for (i = 0; i < 8; i++) {
-			vga_out8 (0x3c4, 0x54+i, par);
-			par->SR54[i] = vga_in8 (0x3c5, par);
+			vga_out8(0x3c4, 0x54+i, par);
+			reg->SR54[i] = vga_in8(0x3c5, par);
 		}
 	}
 
-	vga_out8 (0x3d4, 0x66, par);
-	cr66 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr66 | 0x80, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	cr3a = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr3a | 0x80, par);
+	vga_out8(0x3d4, 0x66, par);
+	cr66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr66 | 0x80, par);
+	vga_out8(0x3d4, 0x3a, par);
+	cr3a = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr3a | 0x80, par);
 
 	/* now save MIU regs */
 	if (par->chip != S3_SAVAGE_MX) {
-		par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);
-		par->MMPR1 = savage_in32(MIU_CONTROL_REG, par);
-		par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);
-		par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);
+		reg->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);
+		reg->MMPR1 = savage_in32(MIU_CONTROL_REG, par);
+		reg->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);
+		reg->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);
 	}
 
-	vga_out8 (0x3d4, 0x3a, par);
-	vga_out8 (0x3d5, cr3a, par);
-	vga_out8 (0x3d4, 0x66, par);
-	vga_out8 (0x3d5, cr66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
+}
+
+static void savage_set_default_par(struct savagefb_par *par,
+				struct savage_reg *reg)
+{
+	unsigned char cr3a, cr53, cr66;
+
+	vga_out16(0x3d4, 0x4838, par);
+	vga_out16(0x3d4, 0xa039, par);
+	vga_out16(0x3c4, 0x0608, par);
+
+	vga_out8(0x3d4, 0x66, par);
+	cr66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr66 | 0x80, par);
+	vga_out8(0x3d4, 0x3a, par);
+	cr3a = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr3a | 0x80, par);
+	vga_out8(0x3d4, 0x53, par);
+	cr53 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr53 & 0x7f, par);
+
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
+
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
+
+	/* unlock extended seq regs */
+	vga_out8(0x3c4, 0x08, par);
+	vga_out8(0x3c5, reg->SR08, par);
+	vga_out8(0x3c5, 0x06, par);
+
+	/* now restore all the extended regs we need */
+	vga_out8(0x3d4, 0x31, par);
+	vga_out8(0x3d5, reg->CR31, par);
+	vga_out8(0x3d4, 0x32, par);
+	vga_out8(0x3d5, reg->CR32, par);
+	vga_out8(0x3d4, 0x34, par);
+	vga_out8(0x3d5, reg->CR34, par);
+	vga_out8(0x3d4, 0x36, par);
+	vga_out8(0x3d5,reg->CR36, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, reg->CR3A, par);
+	vga_out8(0x3d4, 0x40, par);
+	vga_out8(0x3d5, reg->CR40, par);
+	vga_out8(0x3d4, 0x42, par);
+	vga_out8(0x3d5, reg->CR42, par);
+	vga_out8(0x3d4, 0x45, par);
+	vga_out8(0x3d5, reg->CR45, par);
+	vga_out8(0x3d4, 0x50, par);
+	vga_out8(0x3d5, reg->CR50, par);
+	vga_out8(0x3d4, 0x51, par);
+	vga_out8(0x3d5, reg->CR51, par);
+	vga_out8(0x3d4, 0x53, par);
+	vga_out8(0x3d5, reg->CR53, par);
+	vga_out8(0x3d4, 0x58, par);
+	vga_out8(0x3d5, reg->CR58, par);
+	vga_out8(0x3d4, 0x60, par);
+	vga_out8(0x3d5, reg->CR60, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, reg->CR66, par);
+	vga_out8(0x3d4, 0x67, par);
+	vga_out8(0x3d5, reg->CR67, par);
+	vga_out8(0x3d4, 0x68, par);
+	vga_out8(0x3d5, reg->CR68, par);
+	vga_out8(0x3d4, 0x69, par);
+	vga_out8(0x3d5, reg->CR69, par);
+	vga_out8(0x3d4, 0x6f, par);
+	vga_out8(0x3d5, reg->CR6F, par);
+
+	vga_out8(0x3d4, 0x33, par);
+	vga_out8(0x3d5, reg->CR33, par);
+	vga_out8(0x3d4, 0x86, par);
+	vga_out8(0x3d5, reg->CR86, par);
+	vga_out8(0x3d4, 0x88, par);
+	vga_out8(0x3d5, reg->CR88, par);
+	vga_out8(0x3d4, 0x90, par);
+	vga_out8(0x3d5, reg->CR90, par);
+	vga_out8(0x3d4, 0x91, par);
+	vga_out8(0x3d5, reg->CR91, par);
+	vga_out8(0x3d4, 0xb0, par);
+	vga_out8(0x3d5, reg->CRB0, par);
+
+	/* extended mode timing regs */
+	vga_out8(0x3d4, 0x3b, par);
+	vga_out8(0x3d5, reg->CR3B, par);
+	vga_out8(0x3d4, 0x3c, par);
+	vga_out8(0x3d5, reg->CR3C, par);
+	vga_out8(0x3d4, 0x43, par);
+	vga_out8(0x3d5, reg->CR43, par);
+	vga_out8(0x3d4, 0x5d, par);
+	vga_out8(0x3d5, reg->CR5D, par);
+	vga_out8(0x3d4, 0x5e, par);
+	vga_out8(0x3d5, reg->CR5E, par);
+	vga_out8(0x3d4, 0x65, par);
+	vga_out8(0x3d5, reg->CR65, par);
+
+	/* save seq extended regs for DCLK PLL programming */
+	vga_out8(0x3c4, 0x0e, par);
+	vga_out8(0x3c5, reg->SR0E, par);
+	vga_out8(0x3c4, 0x0f, par);
+	vga_out8(0x3c5, reg->SR0F, par);
+	vga_out8(0x3c4, 0x10, par);
+	vga_out8(0x3c5, reg->SR10, par);
+	vga_out8(0x3c4, 0x11, par);
+	vga_out8(0x3c5, reg->SR11, par);
+	vga_out8(0x3c4, 0x12, par);
+	vga_out8(0x3c5, reg->SR12, par);
+	vga_out8(0x3c4, 0x13, par);
+	vga_out8(0x3c5, reg->SR13, par);
+	vga_out8(0x3c4, 0x29, par);
+	vga_out8(0x3c5, reg->SR29, par);
+
+	vga_out8(0x3c4, 0x15, par);
+	vga_out8(0x3c5, reg->SR15, par);
+	vga_out8(0x3c4, 0x30, par);
+	vga_out8(0x3c5, reg->SR30, par);
+	vga_out8(0x3c4, 0x18, par);
+	vga_out8(0x3c5, reg->SR18, par);
+
+	/* Save flat panel expansion regsters. */
+	if (par->chip == S3_SAVAGE_MX) {
+		int i;
+
+		for (i = 0; i < 8; i++) {
+			vga_out8(0x3c4, 0x54+i, par);
+			vga_out8(0x3c5, reg->SR54[i], par);
+		}
+	}
+
+	vga_out8(0x3d4, 0x66, par);
+	cr66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr66 | 0x80, par);
+	vga_out8(0x3d4, 0x3a, par);
+	cr3a = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr3a | 0x80, par);
+
+	/* now save MIU regs */
+	if (par->chip != S3_SAVAGE_MX) {
+		savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par);
+		savage_out32(MIU_CONTROL_REG, reg->MMPR1, par);
+		savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par);
+		savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par);
+	}
+
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
 }
 
 static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
@@ -683,8 +853,8 @@
         var->vmode = modedb->vmode;
 }
 
-static int savagefb_check_var (struct fb_var_screeninfo   *var,
-			       struct fb_info *info)
+static int savagefb_check_var(struct fb_var_screeninfo   *var,
+			      struct fb_info *info)
 {
 	struct savagefb_par *par = info->par;
 	int memlen, vramlen, mode_valid = 0;
@@ -750,10 +920,10 @@
 	if (par->SavagePanelWidth &&
 	    (var->xres > par->SavagePanelWidth ||
 	     var->yres > par->SavagePanelHeight)) {
-		printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
-			"(%dx%d)\n", var->xres,  var->yres,
-			par->SavagePanelWidth,
-			par->SavagePanelHeight);
+		printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel "
+		       "(%dx%d)\n", var->xres,  var->yres,
+		       par->SavagePanelWidth,
+		       par->SavagePanelHeight);
 		return -1;
 	}
 
@@ -788,8 +958,9 @@
 }
 
 
-static int savagefb_decode_var (struct fb_var_screeninfo   *var,
-				struct savagefb_par        *par)
+static int savagefb_decode_var(struct fb_var_screeninfo   *var,
+			       struct savagefb_par        *par,
+			       struct savage_reg          *reg)
 {
 	struct xtimings timings;
 	int width, dclk, i, j; /*, refresh; */
@@ -799,7 +970,7 @@
 
 	DBG("savagefb_decode_var");
 
-	memset (&timings, 0, sizeof(timings));
+	memset(&timings, 0, sizeof(timings));
 
 	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
 	timings.Clock = 1000000000 / pixclock;
@@ -831,39 +1002,39 @@
 	 * This will allocate the datastructure and initialize all of the
 	 * generic VGA registers.
 	 */
-	vgaHWInit (var, par, &timings);
+	vgaHWInit(var, par, &timings, reg);
 
 	/* We need to set CR67 whether or not we use the BIOS. */
 
 	dclk = timings.Clock;
-	par->CR67 = 0x00;
+	reg->CR67 = 0x00;
 
-	switch( var->bits_per_pixel ) {
+	switch(var->bits_per_pixel) {
 	case 8:
-		if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
-			par->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
+		if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))
+			reg->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
 		else
-			par->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
+			reg->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
 		break;
 	case 15:
-		if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
-		     ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
-			par->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
+		if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
+			reg->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
 		else
-			par->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
+			reg->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
 		break;
 	case 16:
-		if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
-		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
-			par->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
+		if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+		   ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
+			reg->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
 		else
-			par->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
+			reg->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
 		break;
 	case 24:
-		par->CR67 = 0x70;
+		reg->CR67 = 0x70;
 		break;
 	case 32:
-		par->CR67 = 0xd0;
+		reg->CR67 = 0xd0;
 		break;
 	}
 
@@ -872,61 +1043,61 @@
 	 * match.  Fall back to traditional register-crunching.
 	 */
 
-	vga_out8 (0x3d4, 0x3a, par);
-	tmp = vga_in8 (0x3d5, par);
+	vga_out8(0x3d4, 0x3a, par);
+	tmp = vga_in8(0x3d5, par);
 	if (1 /*FIXME:psav->pci_burst*/)
-		par->CR3A = (tmp & 0x7f) | 0x15;
+		reg->CR3A = (tmp & 0x7f) | 0x15;
 	else
-		par->CR3A = tmp | 0x95;
+		reg->CR3A = tmp | 0x95;
 
-	par->CR53 = 0x00;
-	par->CR31 = 0x8c;
-	par->CR66 = 0x89;
+	reg->CR53 = 0x00;
+	reg->CR31 = 0x8c;
+	reg->CR66 = 0x89;
 
-	vga_out8 (0x3d4, 0x58, par);
-	par->CR58 = vga_in8 (0x3d5, par) & 0x80;
-	par->CR58 |= 0x13;
+	vga_out8(0x3d4, 0x58, par);
+	reg->CR58 = vga_in8(0x3d5, par) & 0x80;
+	reg->CR58 |= 0x13;
 
-	par->SR15 = 0x03 | 0x80;
-	par->SR18 = 0x00;
-	par->CR43 = par->CR45 = par->CR65 = 0x00;
+	reg->SR15 = 0x03 | 0x80;
+	reg->SR18 = 0x00;
+	reg->CR43 = reg->CR45 = reg->CR65 = 0x00;
 
-	vga_out8 (0x3d4, 0x40, par);
-	par->CR40 = vga_in8 (0x3d5, par) & ~0x01;
+	vga_out8(0x3d4, 0x40, par);
+	reg->CR40 = vga_in8(0x3d5, par) & ~0x01;
 
-	par->MMPR0 = 0x010400;
-	par->MMPR1 = 0x00;
-	par->MMPR2 = 0x0808;
-	par->MMPR3 = 0x08080810;
+	reg->MMPR0 = 0x010400;
+	reg->MMPR1 = 0x00;
+	reg->MMPR2 = 0x0808;
+	reg->MMPR3 = 0x08080810;
 
-	SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
+	SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
 	/* m = 107; n = 4; r = 2; */
 
 	if (par->MCLK <= 0) {
-		par->SR10 = 255;
-		par->SR11 = 255;
+		reg->SR10 = 255;
+		reg->SR11 = 255;
 	} else {
-		common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
-				   &par->SR11, &par->SR10);
-		/*      par->SR10 = 80; // MCLK == 286000 */
-		/*      par->SR11 = 125; */
+		common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
+				   &reg->SR11, &reg->SR10);
+		/*      reg->SR10 = 80; // MCLK == 286000 */
+		/*      reg->SR11 = 125; */
 	}
 
-	par->SR12 = (r << 6) | (n & 0x3f);
-	par->SR13 = m & 0xff;
-	par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
+	reg->SR12 = (r << 6) | (n & 0x3f);
+	reg->SR13 = m & 0xff;
+	reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
 
 	if (var->bits_per_pixel < 24)
-		par->MMPR0 -= 0x8000;
+		reg->MMPR0 -= 0x8000;
 	else
-		par->MMPR0 -= 0x4000;
+		reg->MMPR0 -= 0x4000;
 
 	if (timings.interlaced)
-		par->CR42 = 0x20;
+		reg->CR42 = 0x20;
 	else
-		par->CR42 = 0x00;
+		reg->CR42 = 0x00;
 
-	par->CR34 = 0x10; /* display fifo */
+	reg->CR34 = 0x10; /* display fifo */
 
 	i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
 		((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
@@ -938,77 +1109,77 @@
 	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
 		i |= 0x20;
 
-	j = (par->CRTC[0] + ((i & 0x01) << 8) +
-	     par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
+	j = (reg->CRTC[0] + ((i & 0x01) << 8) +
+	     reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
 
-	if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
-		if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
-		    par->CRTC[0] + ((i & 0x01) << 8))
-			j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
+	if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) {
+		if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <=
+		    reg->CRTC[0] + ((i & 0x01) << 8))
+			j = reg->CRTC[4] + ((i & 0x10) << 4) + 4;
 		else
-			j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
+			j = reg->CRTC[0] + ((i & 0x01) << 8) + 1;
 	}
 
-	par->CR3B = j & 0xff;
+	reg->CR3B = j & 0xff;
 	i |= (j & 0x100) >> 2;
-	par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
-	par->CR5D = i;
-	par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
+	reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2;
+	reg->CR5D = i;
+	reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
 		(((timings.VDisplay - 1) & 0x400) >> 9) |
 		(((timings.VSyncStart) & 0x400) >> 8) |
 		(((timings.VSyncStart) & 0x400) >> 6) | 0x40;
 	width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
-	par->CR91 = par->CRTC[19] = 0xff & width;
-	par->CR51 = (0x300 & width) >> 4;
-	par->CR90 = 0x80 | (width >> 8);
-	par->MiscOutReg |= 0x0c;
+	reg->CR91 = reg->CRTC[19] = 0xff & width;
+	reg->CR51 = (0x300 & width) >> 4;
+	reg->CR90 = 0x80 | (width >> 8);
+	reg->MiscOutReg |= 0x0c;
 
 	/* Set frame buffer description. */
 
 	if (var->bits_per_pixel <= 8)
-		par->CR50 = 0;
+		reg->CR50 = 0;
 	else if (var->bits_per_pixel <= 16)
-		par->CR50 = 0x10;
+		reg->CR50 = 0x10;
 	else
-		par->CR50 = 0x30;
+		reg->CR50 = 0x30;
 
 	if (var->xres_virtual <= 640)
-		par->CR50 |= 0x40;
+		reg->CR50 |= 0x40;
 	else if (var->xres_virtual == 800)
-		par->CR50 |= 0x80;
+		reg->CR50 |= 0x80;
 	else if (var->xres_virtual == 1024)
-		par->CR50 |= 0x00;
+		reg->CR50 |= 0x00;
 	else if (var->xres_virtual == 1152)
-		par->CR50 |= 0x01;
+		reg->CR50 |= 0x01;
 	else if (var->xres_virtual == 1280)
-		par->CR50 |= 0xc0;
+		reg->CR50 |= 0xc0;
 	else if (var->xres_virtual == 1600)
-		par->CR50 |= 0x81;
+		reg->CR50 |= 0x81;
 	else
-		par->CR50 |= 0xc1;	/* Use GBD */
+		reg->CR50 |= 0xc1;	/* Use GBD */
 
-	if( par->chip == S3_SAVAGE2000 )
-		par->CR33 = 0x08;
+	if (par->chip == S3_SAVAGE2000)
+		reg->CR33 = 0x08;
 	else
-		par->CR33 = 0x20;
+		reg->CR33 = 0x20;
 
-	par->CRTC[0x17] = 0xeb;
+	reg->CRTC[0x17] = 0xeb;
 
-	par->CR67 |= 1;
+	reg->CR67 |= 1;
 
 	vga_out8(0x3d4, 0x36, par);
-	par->CR36 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x68, par);
-	par->CR68 = vga_in8 (0x3d5, par);
-	par->CR69 = 0;
-	vga_out8 (0x3d4, 0x6f, par);
-	par->CR6F = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x86, par);
-	par->CR86 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d4, 0x88, par);
-	par->CR88 = vga_in8 (0x3d5, par) | 0x08;
-	vga_out8 (0x3d4, 0xb0, par);
-	par->CRB0 = vga_in8 (0x3d5, par) | 0x80;
+	reg->CR36 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x68, par);
+	reg->CR68 = vga_in8(0x3d5, par);
+	reg->CR69 = 0;
+	vga_out8(0x3d4, 0x6f, par);
+	reg->CR6F = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x86, par);
+	reg->CR86 = vga_in8(0x3d5, par);
+	vga_out8(0x3d4, 0x88, par);
+	reg->CR88 = vga_in8(0x3d5, par) | 0x08;
+	vga_out8(0x3d4, 0xb0, par);
+	reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
 
 	return 0;
 }
@@ -1037,11 +1208,11 @@
 
 	switch (info->var.bits_per_pixel) {
 	case 8:
-		vga_out8 (0x3c8, regno, par);
+		vga_out8(0x3c8, regno, par);
 
-		vga_out8 (0x3c9, red   >> 10, par);
-		vga_out8 (0x3c9, green >> 10, par);
-		vga_out8 (0x3c9, blue  >> 10, par);
+		vga_out8(0x3c9, red   >> 10, par);
+		vga_out8(0x3c9, green >> 10, par);
+		vga_out8(0x3c9, blue  >> 10, par);
 		break;
 
 	case 16:
@@ -1075,21 +1246,21 @@
 	return 0;
 }
 
-static void savagefb_set_par_int (struct savagefb_par  *par)
+static void savagefb_set_par_int(struct savagefb_par  *par, struct savage_reg *reg)
 {
 	unsigned char tmp, cr3a, cr66, cr67;
 
-	DBG ("savagefb_set_par_int");
+	DBG("savagefb_set_par_int");
 
-	par->SavageWaitIdle (par);
+	par->SavageWaitIdle(par);
 
-	vga_out8 (0x3c2, 0x23, par);
+	vga_out8(0x3c2, 0x23, par);
 
-	vga_out16 (0x3d4, 0x4838, par);
-	vga_out16 (0x3d4, 0xa539, par);
-	vga_out16 (0x3c4, 0x0608, par);
+	vga_out16(0x3d4, 0x4838, par);
+	vga_out16(0x3d4, 0xa539, par);
+	vga_out16(0x3c4, 0x0608, par);
 
-	vgaHWProtect (par, 1);
+	vgaHWProtect(par, 1);
 
 	/*
 	 * Some Savage/MX and /IX systems go nuts when trying to exit the
@@ -1099,203 +1270,202 @@
 	 */
 
 	VerticalRetraceWait(par);
-	vga_out8 (0x3d4, 0x67, par);
-	cr67 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */
+	vga_out8(0x3d4, 0x67, par);
+	cr67 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */
 
-	vga_out8 (0x3d4, 0x23, par);
-	vga_out8 (0x3d5, 0x00, par);
-	vga_out8 (0x3d4, 0x26, par);
-	vga_out8 (0x3d5, 0x00, par);
+	vga_out8(0x3d4, 0x23, par);
+	vga_out8(0x3d5, 0x00, par);
+	vga_out8(0x3d4, 0x26, par);
+	vga_out8(0x3d5, 0x00, par);
 
 	/* restore extended regs */
-	vga_out8 (0x3d4, 0x66, par);
-	vga_out8 (0x3d5, par->CR66, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	vga_out8 (0x3d5, par->CR3A, par);
-	vga_out8 (0x3d4, 0x31, par);
-	vga_out8 (0x3d5, par->CR31, par);
-	vga_out8 (0x3d4, 0x32, par);
-	vga_out8 (0x3d5, par->CR32, par);
-	vga_out8 (0x3d4, 0x58, par);
-	vga_out8 (0x3d5, par->CR58, par);
-	vga_out8 (0x3d4, 0x53, par);
-	vga_out8 (0x3d5, par->CR53 & 0x7f, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, reg->CR66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, reg->CR3A, par);
+	vga_out8(0x3d4, 0x31, par);
+	vga_out8(0x3d5, reg->CR31, par);
+	vga_out8(0x3d4, 0x32, par);
+	vga_out8(0x3d5, reg->CR32, par);
+	vga_out8(0x3d4, 0x58, par);
+	vga_out8(0x3d5, reg->CR58, par);
+	vga_out8(0x3d4, 0x53, par);
+	vga_out8(0x3d5, reg->CR53 & 0x7f, par);
 
-	vga_out16 (0x3c4, 0x0608, par);
+	vga_out16(0x3c4, 0x0608, par);
 
 	/* Restore DCLK registers. */
 
-	vga_out8 (0x3c4, 0x0e, par);
-	vga_out8 (0x3c5, par->SR0E, par);
-	vga_out8 (0x3c4, 0x0f, par);
-	vga_out8 (0x3c5, par->SR0F, par);
-	vga_out8 (0x3c4, 0x29, par);
-	vga_out8 (0x3c5, par->SR29, par);
-	vga_out8 (0x3c4, 0x15, par);
-	vga_out8 (0x3c5, par->SR15, par);
+	vga_out8(0x3c4, 0x0e, par);
+	vga_out8(0x3c5, reg->SR0E, par);
+	vga_out8(0x3c4, 0x0f, par);
+	vga_out8(0x3c5, reg->SR0F, par);
+	vga_out8(0x3c4, 0x29, par);
+	vga_out8(0x3c5, reg->SR29, par);
+	vga_out8(0x3c4, 0x15, par);
+	vga_out8(0x3c5, reg->SR15, par);
 
 	/* Restore flat panel expansion regsters. */
-	if( par->chip == S3_SAVAGE_MX ) {
+	if (par->chip == S3_SAVAGE_MX) {
 		int i;
 
-		for( i = 0; i < 8; i++ ) {
-			vga_out8 (0x3c4, 0x54+i, par);
-			vga_out8 (0x3c5, par->SR54[i], par);
+		for (i = 0; i < 8; i++) {
+			vga_out8(0x3c4, 0x54+i, par);
+			vga_out8(0x3c5, reg->SR54[i], par);
 		}
 	}
 
-	vgaHWRestore (par);
+	vgaHWRestore (par, reg);
 
 	/* extended mode timing registers */
-	vga_out8 (0x3d4, 0x53, par);
-	vga_out8 (0x3d5, par->CR53, par);
-	vga_out8 (0x3d4, 0x5d, par);
-	vga_out8 (0x3d5, par->CR5D, par);
-	vga_out8 (0x3d4, 0x5e, par);
-	vga_out8 (0x3d5, par->CR5E, par);
-	vga_out8 (0x3d4, 0x3b, par);
-	vga_out8 (0x3d5, par->CR3B, par);
-	vga_out8 (0x3d4, 0x3c, par);
-	vga_out8 (0x3d5, par->CR3C, par);
-	vga_out8 (0x3d4, 0x43, par);
-	vga_out8 (0x3d5, par->CR43, par);
-	vga_out8 (0x3d4, 0x65, par);
-	vga_out8 (0x3d5, par->CR65, par);
+	vga_out8(0x3d4, 0x53, par);
+	vga_out8(0x3d5, reg->CR53, par);
+	vga_out8(0x3d4, 0x5d, par);
+	vga_out8(0x3d5, reg->CR5D, par);
+	vga_out8(0x3d4, 0x5e, par);
+	vga_out8(0x3d5, reg->CR5E, par);
+	vga_out8(0x3d4, 0x3b, par);
+	vga_out8(0x3d5, reg->CR3B, par);
+	vga_out8(0x3d4, 0x3c, par);
+	vga_out8(0x3d5, reg->CR3C, par);
+	vga_out8(0x3d4, 0x43, par);
+	vga_out8(0x3d5, reg->CR43, par);
+	vga_out8(0x3d4, 0x65, par);
+	vga_out8(0x3d5, reg->CR65, par);
 
 	/* restore the desired video mode with cr67 */
-	vga_out8 (0x3d4, 0x67, par);
+	vga_out8(0x3d4, 0x67, par);
 	/* following part not present in X11 driver */
-	cr67 = vga_in8 (0x3d5, par) & 0xf;
-	vga_out8 (0x3d5, 0x50 | cr67, par);
-	udelay (10000);
-	vga_out8 (0x3d4, 0x67, par);
+	cr67 = vga_in8(0x3d5, par) & 0xf;
+	vga_out8(0x3d5, 0x50 | cr67, par);
+	udelay(10000);
+	vga_out8(0x3d4, 0x67, par);
 	/* end of part */
-	vga_out8 (0x3d5, par->CR67 & ~0x0c, par);
+	vga_out8(0x3d5, reg->CR67 & ~0x0c, par);
 
 	/* other mode timing and extended regs */
-	vga_out8 (0x3d4, 0x34, par);
-	vga_out8 (0x3d5, par->CR34, par);
-	vga_out8 (0x3d4, 0x40, par);
-	vga_out8 (0x3d5, par->CR40, par);
-	vga_out8 (0x3d4, 0x42, par);
-	vga_out8 (0x3d5, par->CR42, par);
-	vga_out8 (0x3d4, 0x45, par);
-	vga_out8 (0x3d5, par->CR45, par);
-	vga_out8 (0x3d4, 0x50, par);
-	vga_out8 (0x3d5, par->CR50, par);
-	vga_out8 (0x3d4, 0x51, par);
-	vga_out8 (0x3d5, par->CR51, par);
+	vga_out8(0x3d4, 0x34, par);
+	vga_out8(0x3d5, reg->CR34, par);
+	vga_out8(0x3d4, 0x40, par);
+	vga_out8(0x3d5, reg->CR40, par);
+	vga_out8(0x3d4, 0x42, par);
+	vga_out8(0x3d5, reg->CR42, par);
+	vga_out8(0x3d4, 0x45, par);
+	vga_out8(0x3d5, reg->CR45, par);
+	vga_out8(0x3d4, 0x50, par);
+	vga_out8(0x3d5, reg->CR50, par);
+	vga_out8(0x3d4, 0x51, par);
+	vga_out8(0x3d5, reg->CR51, par);
 
 	/* memory timings */
-	vga_out8 (0x3d4, 0x36, par);
-	vga_out8 (0x3d5, par->CR36, par);
-	vga_out8 (0x3d4, 0x60, par);
-	vga_out8 (0x3d5, par->CR60, par);
-	vga_out8 (0x3d4, 0x68, par);
-	vga_out8 (0x3d5, par->CR68, par);
-	vga_out8 (0x3d4, 0x69, par);
-	vga_out8 (0x3d5, par->CR69, par);
-	vga_out8 (0x3d4, 0x6f, par);
-	vga_out8 (0x3d5, par->CR6F, par);
+	vga_out8(0x3d4, 0x36, par);
+	vga_out8(0x3d5, reg->CR36, par);
+	vga_out8(0x3d4, 0x60, par);
+	vga_out8(0x3d5, reg->CR60, par);
+	vga_out8(0x3d4, 0x68, par);
+	vga_out8(0x3d5, reg->CR68, par);
+	vga_out8(0x3d4, 0x69, par);
+	vga_out8(0x3d5, reg->CR69, par);
+	vga_out8(0x3d4, 0x6f, par);
+	vga_out8(0x3d5, reg->CR6F, par);
 
-	vga_out8 (0x3d4, 0x33, par);
-	vga_out8 (0x3d5, par->CR33, par);
-	vga_out8 (0x3d4, 0x86, par);
-	vga_out8 (0x3d5, par->CR86, par);
-	vga_out8 (0x3d4, 0x88, par);
-	vga_out8 (0x3d5, par->CR88, par);
-	vga_out8 (0x3d4, 0x90, par);
-	vga_out8 (0x3d5, par->CR90, par);
-	vga_out8 (0x3d4, 0x91, par);
-	vga_out8 (0x3d5, par->CR91, par);
+	vga_out8(0x3d4, 0x33, par);
+	vga_out8(0x3d5, reg->CR33, par);
+	vga_out8(0x3d4, 0x86, par);
+	vga_out8(0x3d5, reg->CR86, par);
+	vga_out8(0x3d4, 0x88, par);
+	vga_out8(0x3d5, reg->CR88, par);
+	vga_out8(0x3d4, 0x90, par);
+	vga_out8(0x3d5, reg->CR90, par);
+	vga_out8(0x3d4, 0x91, par);
+	vga_out8(0x3d5, reg->CR91, par);
 
 	if (par->chip == S3_SAVAGE4) {
-		vga_out8 (0x3d4, 0xb0, par);
-		vga_out8 (0x3d5, par->CRB0, par);
+		vga_out8(0x3d4, 0xb0, par);
+		vga_out8(0x3d5, reg->CRB0, par);
 	}
 
-	vga_out8 (0x3d4, 0x32, par);
-	vga_out8 (0x3d5, par->CR32, par);
+	vga_out8(0x3d4, 0x32, par);
+	vga_out8(0x3d5, reg->CR32, par);
 
 	/* unlock extended seq regs */
-	vga_out8 (0x3c4, 0x08, par);
-	vga_out8 (0x3c5, 0x06, par);
+	vga_out8(0x3c4, 0x08, par);
+	vga_out8(0x3c5, 0x06, par);
 
 	/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
 	 * that we should leave the default SR10 and SR11 values there.
 	 */
-	if (par->SR10 != 255) {
-		vga_out8 (0x3c4, 0x10, par);
-		vga_out8 (0x3c5, par->SR10, par);
-		vga_out8 (0x3c4, 0x11, par);
-		vga_out8 (0x3c5, par->SR11, par);
+	if (reg->SR10 != 255) {
+		vga_out8(0x3c4, 0x10, par);
+		vga_out8(0x3c5, reg->SR10, par);
+		vga_out8(0x3c4, 0x11, par);
+		vga_out8(0x3c5, reg->SR11, par);
 	}
 
 	/* restore extended seq regs for dclk */
-	vga_out8 (0x3c4, 0x0e, par);
-	vga_out8 (0x3c5, par->SR0E, par);
-	vga_out8 (0x3c4, 0x0f, par);
-	vga_out8 (0x3c5, par->SR0F, par);
-	vga_out8 (0x3c4, 0x12, par);
-	vga_out8 (0x3c5, par->SR12, par);
-	vga_out8 (0x3c4, 0x13, par);
-	vga_out8 (0x3c5, par->SR13, par);
-	vga_out8 (0x3c4, 0x29, par);
-	vga_out8 (0x3c5, par->SR29, par);
-
-	vga_out8 (0x3c4, 0x18, par);
-	vga_out8 (0x3c5, par->SR18, par);
+	vga_out8(0x3c4, 0x0e, par);
+	vga_out8(0x3c5, reg->SR0E, par);
+	vga_out8(0x3c4, 0x0f, par);
+	vga_out8(0x3c5, reg->SR0F, par);
+	vga_out8(0x3c4, 0x12, par);
+	vga_out8(0x3c5, reg->SR12, par);
+	vga_out8(0x3c4, 0x13, par);
+	vga_out8(0x3c5, reg->SR13, par);
+	vga_out8(0x3c4, 0x29, par);
+	vga_out8(0x3c5, reg->SR29, par);
+	vga_out8(0x3c4, 0x18, par);
+	vga_out8(0x3c5, reg->SR18, par);
 
 	/* load new m, n pll values for dclk & mclk */
-	vga_out8 (0x3c4, 0x15, par);
-	tmp = vga_in8 (0x3c5, par) & ~0x21;
+	vga_out8(0x3c4, 0x15, par);
+	tmp = vga_in8(0x3c5, par) & ~0x21;
 
-	vga_out8 (0x3c5, tmp | 0x03, par);
-	vga_out8 (0x3c5, tmp | 0x23, par);
-	vga_out8 (0x3c5, tmp | 0x03, par);
-	vga_out8 (0x3c5, par->SR15, par);
-	udelay (100);
+	vga_out8(0x3c5, tmp | 0x03, par);
+	vga_out8(0x3c5, tmp | 0x23, par);
+	vga_out8(0x3c5, tmp | 0x03, par);
+	vga_out8(0x3c5, reg->SR15, par);
+	udelay(100);
 
-	vga_out8 (0x3c4, 0x30, par);
-	vga_out8 (0x3c5, par->SR30, par);
-	vga_out8 (0x3c4, 0x08, par);
-	vga_out8 (0x3c5, par->SR08, par);
+	vga_out8(0x3c4, 0x30, par);
+	vga_out8(0x3c5, reg->SR30, par);
+	vga_out8(0x3c4, 0x08, par);
+	vga_out8(0x3c5, reg->SR08, par);
 
 	/* now write out cr67 in full, possibly starting STREAMS */
 	VerticalRetraceWait(par);
-	vga_out8 (0x3d4, 0x67, par);
-	vga_out8 (0x3d5, par->CR67, par);
+	vga_out8(0x3d4, 0x67, par);
+	vga_out8(0x3d5, reg->CR67, par);
 
-	vga_out8 (0x3d4, 0x66, par);
-	cr66 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr66 | 0x80, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	cr3a = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr3a | 0x80, par);
+	vga_out8(0x3d4, 0x66, par);
+	cr66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr66 | 0x80, par);
+	vga_out8(0x3d4, 0x3a, par);
+	cr3a = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr3a | 0x80, par);
 
 	if (par->chip != S3_SAVAGE_MX) {
 		VerticalRetraceWait(par);
-		savage_out32 (FIFO_CONTROL_REG, par->MMPR0, par);
-		par->SavageWaitIdle (par);
-		savage_out32 (MIU_CONTROL_REG, par->MMPR1, par);
-		par->SavageWaitIdle (par);
-		savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2, par);
-		par->SavageWaitIdle (par);
-		savage_out32 (MISC_TIMEOUT_REG, par->MMPR3, par);
+		savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par);
+		par->SavageWaitIdle(par);
+		savage_out32(MIU_CONTROL_REG, reg->MMPR1, par);
+		par->SavageWaitIdle(par);
+		savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par);
+		par->SavageWaitIdle(par);
+		savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par);
 	}
 
-	vga_out8 (0x3d4, 0x66, par);
-	vga_out8 (0x3d5, cr66, par);
-	vga_out8 (0x3d4, 0x3a, par);
-	vga_out8 (0x3d5, cr3a, par);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66, par);
+	vga_out8(0x3d4, 0x3a, par);
+	vga_out8(0x3d5, cr3a, par);
 
-	SavageSetup2DEngine (par);
-	vgaHWProtect (par, 0);
+	SavageSetup2DEngine(par);
+	vgaHWProtect(par, 0);
 }
 
-static void savagefb_update_start (struct savagefb_par      *par,
-				   struct fb_var_screeninfo *var)
+static void savagefb_update_start(struct savagefb_par      *par,
+				  struct fb_var_screeninfo *var)
 {
 	int base;
 
@@ -1305,8 +1475,8 @@
 	/* now program the start address registers */
 	vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par);
 	vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par);
-	vga_out8 (0x3d4, 0x69, par);
-	vga_out8 (0x3d5, (base & 0x7f0000) >> 16, par);
+	vga_out8(0x3d4, 0x69, par);
+	vga_out8(0x3d5, (base & 0x7f0000) >> 16, par);
 }
 
 
@@ -1325,29 +1495,14 @@
 
 }
 
-#if defined(CONFIG_FB_SAVAGE_ACCEL)
-static void savagefb_set_clip(struct fb_info *info)
-{
-    struct savagefb_par *par = info->par;
-    int cmd;
-
-    cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
-    par->bci_ptr = 0;
-    par->SavageWaitFifo(par,3);
-    BCI_SEND(cmd);
-    BCI_SEND(BCI_CLIP_TL(0, 0));
-    BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
-}
-#endif
-
-static int savagefb_set_par (struct fb_info *info)
+static int savagefb_set_par(struct fb_info *info)
 {
 	struct savagefb_par *par = info->par;
 	struct fb_var_screeninfo *var = &info->var;
 	int err;
 
 	DBG("savagefb_set_par");
-	err = savagefb_decode_var (var, par);
+	err = savagefb_decode_var(var, par, &par->state);
 	if (err)
 		return err;
 
@@ -1366,8 +1521,8 @@
 	par->maxClock = par->dacSpeedBpp;
 	par->minClock = 10000;
 
-	savagefb_set_par_int (par);
-	fb_set_cmap (&info->cmap, info);
+	savagefb_set_par_int(par, &par->state);
+	fb_set_cmap(&info->cmap, info);
 	savagefb_set_fix(info);
 	savagefb_set_clip(info);
 
@@ -1378,12 +1533,12 @@
 /*
  *    Pan or Wrap the Display
  */
-static int savagefb_pan_display (struct fb_var_screeninfo *var,
-				 struct fb_info           *info)
+static int savagefb_pan_display(struct fb_var_screeninfo *var,
+				struct fb_info           *info)
 {
 	struct savagefb_par *par = info->par;
 
-	savagefb_update_start (par, var);
+	savagefb_update_start(par, var);
 	return 0;
 }
 
@@ -1440,6 +1595,22 @@
 	return (blank == FB_BLANK_NORMAL) ? 1 : 0;
 }
 
+static void savagefb_save_state(struct fb_info *info)
+{
+	struct savagefb_par *par = info->par;
+
+	savage_get_default_par(par, &par->save);
+}
+
+static void savagefb_restore_state(struct fb_info *info)
+{
+	struct savagefb_par *par = info->par;
+
+	savagefb_blank(FB_BLANK_POWERDOWN, info);
+	savage_set_default_par(par, &par->save);
+	savagefb_blank(FB_BLANK_UNBLANK, info);
+}
+
 static struct fb_ops savagefb_ops = {
 	.owner          = THIS_MODULE,
 	.fb_check_var   = savagefb_check_var,
@@ -1447,6 +1618,8 @@
 	.fb_setcolreg   = savagefb_setcolreg,
 	.fb_pan_display = savagefb_pan_display,
 	.fb_blank       = savagefb_blank,
+	.fb_save_state  = savagefb_save_state,
+	.fb_restore_state = savagefb_restore_state,
 #if defined(CONFIG_FB_SAVAGE_ACCEL)
 	.fb_fillrect    = savagefb_fillrect,
 	.fb_copyarea    = savagefb_copyarea,
@@ -1479,59 +1652,59 @@
 	.vmode =	FB_VMODE_NONINTERLACED
 };
 
-static void savage_enable_mmio (struct savagefb_par *par)
+static void savage_enable_mmio(struct savagefb_par *par)
 {
 	unsigned char val;
 
-	DBG ("savage_enable_mmio\n");
+	DBG("savage_enable_mmio\n");
 
-	val = vga_in8 (0x3c3, par);
-	vga_out8 (0x3c3, val | 0x01, par);
-	val = vga_in8 (0x3cc, par);
-	vga_out8 (0x3c2, val | 0x01, par);
+	val = vga_in8(0x3c3, par);
+	vga_out8(0x3c3, val | 0x01, par);
+	val = vga_in8(0x3cc, par);
+	vga_out8(0x3c2, val | 0x01, par);
 
 	if (par->chip >= S3_SAVAGE4) {
-		vga_out8 (0x3d4, 0x40, par);
-		val = vga_in8 (0x3d5, par);
-		vga_out8 (0x3d5, val | 1, par);
+		vga_out8(0x3d4, 0x40, par);
+		val = vga_in8(0x3d5, par);
+		vga_out8(0x3d5, val | 1, par);
 	}
 }
 
 
-static void savage_disable_mmio (struct savagefb_par *par)
+static void savage_disable_mmio(struct savagefb_par *par)
 {
 	unsigned char val;
 
-	DBG ("savage_disable_mmio\n");
+	DBG("savage_disable_mmio\n");
 
-	if(par->chip >= S3_SAVAGE4 ) {
-		vga_out8 (0x3d4, 0x40, par);
-		val = vga_in8 (0x3d5, par);
-		vga_out8 (0x3d5, val | 1, par);
+	if (par->chip >= S3_SAVAGE4) {
+		vga_out8(0x3d4, 0x40, par);
+		val = vga_in8(0x3d5, par);
+		vga_out8(0x3d5, val | 1, par);
 	}
 }
 
 
-static int __devinit savage_map_mmio (struct fb_info *info)
+static int __devinit savage_map_mmio(struct fb_info *info)
 {
 	struct savagefb_par *par = info->par;
-	DBG ("savage_map_mmio");
+	DBG("savage_map_mmio");
 
-	if (S3_SAVAGE3D_SERIES (par->chip))
-		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+	if (S3_SAVAGE3D_SERIES(par->chip))
+		par->mmio.pbase = pci_resource_start(par->pcidev, 0) +
 			SAVAGE_NEWMMIO_REGBASE_S3;
 	else
-		par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+		par->mmio.pbase = pci_resource_start(par->pcidev, 0) +
 			SAVAGE_NEWMMIO_REGBASE_S4;
 
 	par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
 
-	par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
+	par->mmio.vbase = ioremap(par->mmio.pbase, par->mmio.len);
 	if (!par->mmio.vbase) {
-		printk ("savagefb: unable to map memory mapped IO\n");
+		printk("savagefb: unable to map memory mapped IO\n");
 		return -ENOMEM;
 	} else
-		printk (KERN_INFO "savagefb: mapped io at %p\n",
+		printk(KERN_INFO "savagefb: mapped io at %p\n",
 			par->mmio.vbase);
 
 	info->fix.mmio_start = par->mmio.pbase;
@@ -1540,15 +1713,15 @@
 	par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
 	par->bci_ptr  = 0;
 
-	savage_enable_mmio (par);
+	savage_enable_mmio(par);
 
 	return 0;
 }
 
-static void savage_unmap_mmio (struct fb_info *info)
+static void savage_unmap_mmio(struct fb_info *info)
 {
 	struct savagefb_par *par = info->par;
-	DBG ("savage_unmap_mmio");
+	DBG("savage_unmap_mmio");
 
 	savage_disable_mmio(par);
 
@@ -1558,46 +1731,46 @@
 	}
 }
 
-static int __devinit savage_map_video (struct fb_info *info,
-				       int video_len)
+static int __devinit savage_map_video(struct fb_info *info,
+				      int video_len)
 {
 	struct savagefb_par *par = info->par;
 	int resource;
 
 	DBG("savage_map_video");
 
-	if (S3_SAVAGE3D_SERIES (par->chip))
+	if (S3_SAVAGE3D_SERIES(par->chip))
 		resource = 0;
 	else
 		resource = 1;
 
-	par->video.pbase = pci_resource_start (par->pcidev, resource);
+	par->video.pbase = pci_resource_start(par->pcidev, resource);
 	par->video.len   = video_len;
-	par->video.vbase = ioremap (par->video.pbase, par->video.len);
+	par->video.vbase = ioremap(par->video.pbase, par->video.len);
 
 	if (!par->video.vbase) {
-		printk ("savagefb: unable to map screen memory\n");
+		printk("savagefb: unable to map screen memory\n");
 		return -ENOMEM;
 	} else
-		printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
-			"pbase == %x\n", par->video.vbase, par->video.pbase);
+		printk(KERN_INFO "savagefb: mapped framebuffer at %p, "
+		       "pbase == %x\n", par->video.vbase, par->video.pbase);
 
 	info->fix.smem_start = par->video.pbase;
 	info->fix.smem_len   = par->video.len - par->cob_size;
 	info->screen_base    = par->video.vbase;
 
 #ifdef CONFIG_MTRR
-	par->video.mtrr = mtrr_add (par->video.pbase, video_len,
-				     MTRR_TYPE_WRCOMB, 1);
+	par->video.mtrr = mtrr_add(par->video.pbase, video_len,
+				   MTRR_TYPE_WRCOMB, 1);
 #endif
 
 	/* Clear framebuffer, it's all white in memory after boot */
-	memset_io (par->video.vbase, 0, par->video.len);
+	memset_io(par->video.vbase, 0, par->video.len);
 
 	return 0;
 }
 
-static void savage_unmap_video (struct fb_info *info)
+static void savage_unmap_video(struct fb_info *info)
 {
 	struct savagefb_par *par = info->par;
 
@@ -1605,16 +1778,16 @@
 
 	if (par->video.vbase) {
 #ifdef CONFIG_MTRR
-		mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
+		mtrr_del(par->video.mtrr, par->video.pbase, par->video.len);
 #endif
 
-		iounmap (par->video.vbase);
+		iounmap(par->video.vbase);
 		par->video.vbase = NULL;
 		info->screen_base = NULL;
 	}
 }
 
-static int savage_init_hw (struct savagefb_par *par)
+static int savage_init_hw(struct savagefb_par *par)
 {
 	unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
 
@@ -1656,7 +1829,7 @@
 
 	switch  (par->chip) {
 	case S3_SAVAGE3D:
-		videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
+		videoRam = RamSavage3D[(config1 & 0xC0) >> 6 ] * 1024;
 		break;
 
 	case S3_SAVAGE4:
@@ -1667,22 +1840,22 @@
 		 * can do it different...
 		 */
 		vga_out8(0x3d4, 0x68, par);	/* memory control 1 */
-		if( (vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6) )
+		if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6))
 			RamSavage4[1] = 8;
 
 		/*FALLTHROUGH*/
 
 	case S3_SAVAGE2000:
-		videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
+		videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024;
 		break;
 
 	case S3_SAVAGE_MX:
 	case S3_SUPERSAVAGE:
-		videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
+		videoRam = RamSavageMX[(config1 & 0x0E) >> 1] * 1024;
 		break;
 
 	case S3_PROSAVAGE:
-		videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
+		videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024;
 		break;
 
 	default:
@@ -1693,31 +1866,31 @@
 
 	videoRambytes = videoRam * 1024;
 
-	printk (KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
+	printk(KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
 
 	/* reset graphics engine to avoid memory corruption */
-	vga_out8 (0x3d4, 0x66, par);
-	cr66 = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr66 | 0x02, par);
-	udelay (10000);
+	vga_out8(0x3d4, 0x66, par);
+	cr66 = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr66 | 0x02, par);
+	udelay(10000);
 
-	vga_out8 (0x3d4, 0x66, par);
-	vga_out8 (0x3d5, cr66 & ~0x02, par);	/* clear reset flag */
-	udelay (10000);
+	vga_out8(0x3d4, 0x66, par);
+	vga_out8(0x3d5, cr66 & ~0x02, par);	/* clear reset flag */
+	udelay(10000);
 
 
 	/*
 	 * reset memory interface, 3D engine, AGP master, PCI master,
 	 * master engine unit, motion compensation/LPB
 	 */
-	vga_out8 (0x3d4, 0x3f, par);
-	cr3f = vga_in8 (0x3d5, par);
-	vga_out8 (0x3d5, cr3f | 0x08, par);
-	udelay (10000);
+	vga_out8(0x3d4, 0x3f, par);
+	cr3f = vga_in8(0x3d5, par);
+	vga_out8(0x3d5, cr3f | 0x08, par);
+	udelay(10000);
 
-	vga_out8 (0x3d4, 0x3f, par);
-	vga_out8 (0x3d5, cr3f & ~0x08, par);	/* clear reset flags */
-	udelay (10000);
+	vga_out8(0x3d4, 0x3f, par);
+	vga_out8(0x3d5, cr3f & ~0x08, par);	/* clear reset flags */
+	udelay(10000);
 
 	/* Savage ramdac speeds */
 	par->numClocks = 4;
@@ -1740,7 +1913,7 @@
 	n1 = n & 0x1f;
 	n2 = (n >> 5) & 0x03;
 	par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
-	printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
+	printk(KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
 		par->MCLK);
 
 	/* check for DVI/flat panel */
@@ -1769,12 +1942,12 @@
 	/* Check LCD panel parrmation */
 
 	if (par->display_type == DISP_LCD) {
-		unsigned char cr6b = VGArCR( 0x6b, par);
+		unsigned char cr6b = VGArCR(0x6b, par);
 
-		int panelX = (VGArSEQ (0x61, par) +
-			      ((VGArSEQ (0x66, par) & 0x02) << 7) + 1) * 8;
-		int panelY = (VGArSEQ (0x69, par) +
-			      ((VGArSEQ (0x6e, par) & 0x70) << 4) + 1);
+		int panelX = (VGArSEQ(0x61, par) +
+			      ((VGArSEQ(0x66, par) & 0x02) << 7) + 1) * 8;
+		int panelY = (VGArSEQ(0x69, par) +
+			      ((VGArSEQ(0x6e, par) & 0x70) << 4) + 1);
 
 		char * sTechnology = "Unknown";
 
@@ -1796,26 +1969,26 @@
 			ActiveDUO = 0x80
 		};
 
-		if ((VGArSEQ (0x39, par) & 0x03) == 0) {
+		if ((VGArSEQ(0x39, par) & 0x03) == 0) {
 			sTechnology = "TFT";
-		} else if ((VGArSEQ (0x30, par) & 0x01) == 0) {
+		} else if ((VGArSEQ(0x30, par) & 0x01) == 0) {
 			sTechnology = "DSTN";
 		} else 	{
 			sTechnology = "STN";
 		}
 
-		printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
-			panelX, panelY, sTechnology,
-			cr6b & ActiveLCD ? "and active" : "but not active");
+		printk(KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
+		       panelX, panelY, sTechnology,
+		       cr6b & ActiveLCD ? "and active" : "but not active");
 
-		if( cr6b & ActiveLCD ) 	{
+		if (cr6b & ActiveLCD) 	{
 			/*
 			 * If the LCD is active and panel expansion is enabled,
 			 * we probably want to kill the HW cursor.
 			 */
 
-			printk (KERN_INFO "savagefb: Limiting video mode to "
-				"%dx%d\n", panelX, panelY );
+			printk(KERN_INFO "savagefb: Limiting video mode to "
+				"%dx%d\n", panelX, panelY);
 
 			par->SavagePanelWidth = panelX;
 			par->SavagePanelHeight = panelY;
@@ -1824,9 +1997,10 @@
 			par->display_type = DISP_CRT;
 	}
 
-	savage_get_default_par (par);
+	savage_get_default_par(par, &par->state);
+	par->save = par->state;
 
-	if( S3_SAVAGE4_SERIES(par->chip) ) {
+	if (S3_SAVAGE4_SERIES(par->chip)) {
 		/*
 		 * The Savage4 and ProSavage have COB coherency bugs which
 		 * render the buffer useless.  We disable it.
@@ -1845,9 +2019,9 @@
 	return videoRambytes;
 }
 
-static int __devinit savage_init_fb_info (struct fb_info *info,
-					  struct pci_dev *dev,
-					  const struct pci_device_id *id)
+static int __devinit savage_init_fb_info(struct fb_info *info,
+					 struct pci_dev *dev,
+					 const struct pci_device_id *id)
 {
 	struct savagefb_par *par = info->par;
 	int err = 0;
@@ -1863,63 +2037,63 @@
 	switch (info->fix.accel) {
 	case FB_ACCEL_SUPERSAVAGE:
 		par->chip = S3_SUPERSAVAGE;
-		snprintf (info->fix.id, 16, "SuperSavage");
+		snprintf(info->fix.id, 16, "SuperSavage");
 		break;
 	case FB_ACCEL_SAVAGE4:
 		par->chip = S3_SAVAGE4;
-		snprintf (info->fix.id, 16, "Savage4");
+		snprintf(info->fix.id, 16, "Savage4");
 		break;
 	case FB_ACCEL_SAVAGE3D:
 		par->chip = S3_SAVAGE3D;
-		snprintf (info->fix.id, 16, "Savage3D");
+		snprintf(info->fix.id, 16, "Savage3D");
 		break;
 	case FB_ACCEL_SAVAGE3D_MV:
 		par->chip = S3_SAVAGE3D;
-		snprintf (info->fix.id, 16, "Savage3D-MV");
+		snprintf(info->fix.id, 16, "Savage3D-MV");
 		break;
 	case FB_ACCEL_SAVAGE2000:
 		par->chip = S3_SAVAGE2000;
-		snprintf (info->fix.id, 16, "Savage2000");
+		snprintf(info->fix.id, 16, "Savage2000");
 		break;
 	case FB_ACCEL_SAVAGE_MX_MV:
 		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/MX-MV");
+		snprintf(info->fix.id, 16, "Savage/MX-MV");
 		break;
 	case FB_ACCEL_SAVAGE_MX:
 		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/MX");
+		snprintf(info->fix.id, 16, "Savage/MX");
 		break;
 	case FB_ACCEL_SAVAGE_IX_MV:
 		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/IX-MV");
+		snprintf(info->fix.id, 16, "Savage/IX-MV");
 		break;
 	case FB_ACCEL_SAVAGE_IX:
 		par->chip = S3_SAVAGE_MX;
-		snprintf (info->fix.id, 16, "Savage/IX");
+		snprintf(info->fix.id, 16, "Savage/IX");
 		break;
 	case FB_ACCEL_PROSAVAGE_PM:
 		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavagePM");
+		snprintf(info->fix.id, 16, "ProSavagePM");
 		break;
 	case FB_ACCEL_PROSAVAGE_KM:
 		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavageKM");
+		snprintf(info->fix.id, 16, "ProSavageKM");
 		break;
 	case FB_ACCEL_S3TWISTER_P:
 		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "TwisterP");
+		snprintf(info->fix.id, 16, "TwisterP");
 		break;
 	case FB_ACCEL_S3TWISTER_K:
 		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "TwisterK");
+		snprintf(info->fix.id, 16, "TwisterK");
 		break;
 	case FB_ACCEL_PROSAVAGE_DDR:
 		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavageDDR");
+		snprintf(info->fix.id, 16, "ProSavageDDR");
 		break;
 	case FB_ACCEL_PROSAVAGE_DDRK:
 		par->chip = S3_PROSAVAGE;
-		snprintf (info->fix.id, 16, "ProSavage8");
+		snprintf(info->fix.id, 16, "ProSavage8");
 		break;
 	}
 
@@ -1960,7 +2134,7 @@
 		info->pixmap.buf_align = 4;
 		info->pixmap.access_align = 32;
 
-		err = fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
+		err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
 		if (!err)
 		info->flags |= FBINFO_HWACCEL_COPYAREA |
 	                       FBINFO_HWACCEL_FILLRECT |
@@ -1972,8 +2146,8 @@
 
 /* --------------------------------------------------------------------- */
 
-static int __devinit savagefb_probe (struct pci_dev* dev,
-				     const struct pci_device_id* id)
+static int __devinit savagefb_probe(struct pci_dev* dev,
+				    const struct pci_device_id* id)
 {
 	struct fb_info *info;
 	struct savagefb_par *par;
@@ -2085,12 +2259,12 @@
 	fb_destroy_modedb(info->monspecs.modedb);
 	info->monspecs.modedb = NULL;
 
-	err = register_framebuffer (info);
+	err = register_framebuffer(info);
 	if (err < 0)
 		goto failed;
 
-	printk (KERN_INFO "fb: S3 %s frame buffer device\n",
-		info->fix.id);
+	printk(KERN_INFO "fb: S3 %s frame buffer device\n",
+	       info->fix.id);
 
 	/*
 	 * Our driver data
@@ -2103,10 +2277,10 @@
 #ifdef CONFIG_FB_SAVAGE_I2C
 	savagefb_delete_i2c_busses(info);
 #endif
-	fb_alloc_cmap (&info->cmap, 0, 0);
+	fb_alloc_cmap(&info->cmap, 0, 0);
 	savage_unmap_video(info);
  failed_video:
-	savage_unmap_mmio (info);
+	savage_unmap_mmio(info);
  failed_mmio:
 	kfree(info->pixmap.addr);
  failed_init:
@@ -2117,7 +2291,7 @@
 	return err;
 }
 
-static void __devexit savagefb_remove (struct pci_dev *dev)
+static void __devexit savagefb_remove(struct pci_dev *dev)
 {
 	struct fb_info *info = pci_get_drvdata(dev);
 
@@ -2129,16 +2303,16 @@
 		 * we will be leaving hooks that could cause
 		 * oopsen laying around.
 		 */
-		if (unregister_framebuffer (info))
-			printk (KERN_WARNING "savagefb: danger danger! "
-				"Oopsen imminent!\n");
+		if (unregister_framebuffer(info))
+			printk(KERN_WARNING "savagefb: danger danger! "
+			       "Oopsen imminent!\n");
 
 #ifdef CONFIG_FB_SAVAGE_I2C
 		savagefb_delete_i2c_busses(info);
 #endif
-		fb_alloc_cmap (&info->cmap, 0, 0);
-		savage_unmap_video (info);
-		savage_unmap_mmio (info);
+		fb_alloc_cmap(&info->cmap, 0, 0);
+		savage_unmap_video(info);
+		savage_unmap_mmio(info);
 		kfree(info->pixmap.addr);
 		pci_release_regions(dev);
 		framebuffer_release(info);
@@ -2151,7 +2325,7 @@
 	}
 }
 
-static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
+static int savagefb_suspend(struct pci_dev* dev, pm_message_t state)
 {
 	struct fb_info *info = pci_get_drvdata(dev);
 	struct savagefb_par *par = info->par;
@@ -2177,6 +2351,7 @@
 		info->fbops->fb_sync(info);
 
 	savagefb_blank(FB_BLANK_POWERDOWN, info);
+	savage_set_default_par(par, &par->save);
 	savage_disable_mmio(par);
 	pci_save_state(dev);
 	pci_disable_device(dev);
@@ -2186,7 +2361,7 @@
 	return 0;
 }
 
-static int savagefb_resume (struct pci_dev* dev)
+static int savagefb_resume(struct pci_dev* dev)
 {
 	struct fb_info *info = pci_get_drvdata(dev);
 	struct savagefb_par *par = info->par;
@@ -2210,15 +2385,15 @@
 	pci_set_power_state(dev, PCI_D0);
 	pci_restore_state(dev);
 
-	if(pci_enable_device(dev))
+	if (pci_enable_device(dev))
 		DBG("err");
 
 	pci_set_master(dev);
 	savage_enable_mmio(par);
 	savage_init_hw(par);
-	savagefb_set_par (info);
+	savagefb_set_par(info);
+	fb_set_suspend(info, 0);
 	savagefb_blank(FB_BLANK_UNBLANK, info);
-	fb_set_suspend (info, 0);
 	release_console_sem();
 
 	return 0;
@@ -2311,10 +2486,10 @@
 
 /* **************************** exit-time only **************************** */
 
-static void __exit savage_done (void)
+static void __exit savage_done(void)
 {
 	DBG("savage_done");
-	pci_unregister_driver (&savagefb_driver);
+	pci_unregister_driver(&savagefb_driver);
 }
 
 
@@ -2345,7 +2520,7 @@
 		return -ENODEV;
 
 	savagefb_setup(option);
-	return pci_register_driver (&savagefb_driver);
+	return pci_register_driver(&savagefb_driver);
 
 }
 
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 8adf5bf..c63c0e7 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -275,7 +275,7 @@
 static void __devinit
 sisfb_get_vga_mode_from_kernel(void)
 {
-#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
+#ifdef CONFIG_X86
 	char mymode[32];
 	int  mydepth = screen_info.lfb_depth;
 
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 9b70777..67f429e 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -906,11 +906,6 @@
 }
 #endif
 
-MODULE_LICENSE("GPL");
-module_init(xxxfb_init);
-module_exit(xxxfb_exit);
-
-
     /*
      *  Setup
      */
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 7398bd4..6c2c78a 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -26,7 +26,6 @@
 #include <linux/selection.h>
 #include <asm/io.h>
 #include <video/tgafb.h>
-#include <linux/selection.h>
 
 /*
  * Local functions.
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 9ac2d31..41f8c2d 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -551,7 +551,7 @@
 #define crtc_unlock()	write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
 
 /*  Return flat panel's maximum x resolution */
-static int __init get_nativex(void)
+static int __devinit get_nativex(void)
 {
 	int x,y,tmp;
 
@@ -658,7 +658,7 @@
  * If we see that FP is active we assume we have one.
  * Otherwise we have a CRT display.User can override.
  */
-static unsigned int __init get_displaytype(void)
+static unsigned int __devinit get_displaytype(void)
 {
 	if (fp)
 		return DISPLAY_FP;
@@ -668,7 +668,7 @@
 }
 
 /* Try detecting the video memory size */
-static unsigned int __init get_memsize(void)
+static unsigned int __devinit get_memsize(void)
 {
 	unsigned char tmp, tmp2;
 	unsigned int k;
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index b0b9acf..5718924 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -51,7 +51,7 @@
 static int             mtrr      = 0; /* disable mtrr */
 static int	       vram_remap __initdata = 0; /* Set amount of memory to be used */
 static int	       vram_total __initdata = 0; /* Set total amount of memory */
-static int             pmi_setpal = 0;	/* pmi for palette changes ??? */
+static int             pmi_setpal = 1;	/* pmi for palette changes ??? */
 static int             ypan       = 0;  /* 0..nothing, 1..ypan, 2..ywrap */
 static unsigned short  *pmi_base  = NULL;
 static void            (*pmi_start)(void);
@@ -80,15 +80,30 @@
 	return 0;
 }
 
-static void vesa_setpalette(int regno, unsigned red, unsigned green,
+static int vesa_setpalette(int regno, unsigned red, unsigned green,
 			    unsigned blue)
 {
 	int shift = 16 - depth;
+	int err = -EINVAL;
+
+/*
+ * Try VGA registers first...
+ */
+	if (vga_compat) {
+		outb_p(regno,       dac_reg);
+		outb_p(red   >> shift, dac_val);
+		outb_p(green >> shift, dac_val);
+		outb_p(blue  >> shift, dac_val);
+		err = 0;
+	}
 
 #ifdef __i386__
-	struct { u_char blue, green, red, pad; } entry;
+/*
+ * Fallback to the PMI....
+ */
+	if (err && pmi_setpal) {
+		struct { u_char blue, green, red, pad; } entry;
 
-	if (pmi_setpal) {
 		entry.red   = red   >> shift;
 		entry.green = green >> shift;
 		entry.blue  = blue  >> shift;
@@ -102,26 +117,19 @@
                   "d" (regno),          /* EDX */
                   "D" (&entry),         /* EDI */
                   "S" (&pmi_pal));      /* ESI */
-		return;
+		err = 0;
 	}
 #endif
 
-/*
- * without protected mode interface and if VGA compatible,
- * try VGA registers...
- */
-	if (vga_compat) {
-		outb_p(regno,       dac_reg);
-		outb_p(red   >> shift, dac_val);
-		outb_p(green >> shift, dac_val);
-		outb_p(blue  >> shift, dac_val);
-	}
+	return err;
 }
 
 static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			    unsigned blue, unsigned transp,
 			    struct fb_info *info)
 {
+	int err = 0;
+
 	/*
 	 *  Set a single color register. The values supplied are
 	 *  already rounded down to the hardware's capabilities
@@ -133,7 +141,7 @@
 		return 1;
 
 	if (info->var.bits_per_pixel == 8)
-		vesa_setpalette(regno,red,green,blue);
+		err = vesa_setpalette(regno,red,green,blue);
 	else if (regno < 16) {
 		switch (info->var.bits_per_pixel) {
 		case 16:
@@ -164,7 +172,7 @@
 		}
 	}
 
-	return 0;
+	return err;
 }
 
 static struct fb_ops vesafb_ops = {
@@ -460,9 +468,7 @@
 	},
 };
 
-static struct platform_device vesafb_device = {
-	.name	= "vesafb",
-};
+static struct platform_device *vesafb_device;
 
 static int __init vesafb_init(void)
 {
@@ -475,10 +481,19 @@
 	ret = platform_driver_register(&vesafb_driver);
 
 	if (!ret) {
-		ret = platform_device_register(&vesafb_device);
-		if (ret)
+		vesafb_device = platform_device_alloc("vesafb", 0);
+
+		if (vesafb_device)
+			ret = platform_device_add(vesafb_device);
+		else
+			ret = -ENOMEM;
+
+		if (ret) {
+			platform_device_put(vesafb_device);
 			platform_driver_unregister(&vesafb_driver);
+		}
 	}
+
 	return ret;
 }
 module_init(vesafb_init);
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 77eed1f..d073ffb 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -398,12 +398,6 @@
      *  Initialisation
      */
 
-static void vfb_platform_release(struct device *device)
-{
-	// This is called when the reference count goes to zero.
-	dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
-}
-
 static int __init vfb_probe(struct platform_device *dev)
 {
 	struct fb_info *info;
@@ -482,13 +476,7 @@
 	},
 };
 
-static struct platform_device vfb_device = {
-	.name	= "vfb",
-	.id	= 0,
-	.dev	= {
-		.release = vfb_platform_release,
-	}
-};
+static struct platform_device *vfb_device;
 
 static int __init vfb_init(void)
 {
@@ -508,10 +496,19 @@
 	ret = platform_driver_register(&vfb_driver);
 
 	if (!ret) {
-		ret = platform_device_register(&vfb_device);
-		if (ret)
+		vfb_device = platform_device_alloc("vfb", 0);
+
+		if (vfb_device)
+			ret = platform_device_add(vfb_device);
+		else
+			ret = -ENOMEM;
+
+		if (ret) {
+			platform_device_put(vfb_device);
 			platform_driver_unregister(&vfb_driver);
+		}
 	}
+
 	return ret;
 }
 
@@ -520,7 +517,7 @@
 #ifdef MODULE
 static void __exit vfb_exit(void)
 {
-	platform_device_unregister(&vfb_device);
+	platform_device_unregister(vfb_device);
 	platform_driver_unregister(&vfb_driver);
 }
 
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 4fd2a27..3c404c9 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1334,9 +1334,8 @@
 }
 #endif
 
-static int __init vga16fb_probe(struct device *device)
+static int __init vga16fb_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
 	struct fb_info *info;
 	struct vga16fb_par *par;
 	int i;
@@ -1403,7 +1402,7 @@
 
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 	       info->node, info->fix.id);
-	dev_set_drvdata(device, info);
+	platform_set_drvdata(dev, info);
 
 	return 0;
 
@@ -1417,9 +1416,9 @@
 	return ret;
 }
 
-static int vga16fb_remove(struct device *device)
+static int vga16fb_remove(struct platform_device *dev)
 {
-	struct fb_info *info = dev_get_drvdata(device);
+	struct fb_info *info = platform_get_drvdata(dev);
 
 	if (info) {
 		unregister_framebuffer(info);
@@ -1432,16 +1431,15 @@
 	return 0;
 }
 
-static struct device_driver vga16fb_driver = {
-	.name = "vga16fb",
-	.bus  = &platform_bus_type,
+static struct platform_driver vga16fb_driver = {
 	.probe = vga16fb_probe,
 	.remove = vga16fb_remove,
+	.driver = {
+		.name = "vga16fb",
+	},
 };
 
-static struct platform_device vga16fb_device = {
-	.name = "vga16fb",
-};
+static struct platform_device *vga16fb_device;
 
 static int __init vga16fb_init(void)
 {
@@ -1454,12 +1452,20 @@
 
 	vga16fb_setup(option);
 #endif
-	ret = driver_register(&vga16fb_driver);
+	ret = platform_driver_register(&vga16fb_driver);
 
 	if (!ret) {
-		ret = platform_device_register(&vga16fb_device);
-		if (ret)
-			driver_unregister(&vga16fb_driver);
+		vga16fb_device = platform_device_alloc("vga16fb", 0);
+
+		if (vga16fb_device)
+			ret = platform_device_add(vga16fb_device);
+		else
+			ret = -ENOMEM;
+
+		if (ret) {
+			platform_device_put(vga16fb_device);
+			platform_driver_unregister(&vga16fb_driver);
+		}
 	}
 
 	return ret;
@@ -1467,8 +1473,8 @@
 
 static void __exit vga16fb_exit(void)
 {
-	platform_device_unregister(&vga16fb_device);
-	driver_unregister(&vga16fb_driver);
+	platform_device_unregister(vga16fb_device);
+	platform_driver_unregister(&vga16fb_driver);
 }
 
 MODULE_LICENSE("GPL");
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
index f4407eb..12e1baa 100644
--- a/fs/9p/mux.c
+++ b/fs/9p/mux.c
@@ -712,7 +712,7 @@
  * v9fs_send_request - send 9P request
  * The function can sleep until the request is scheduled for sending.
  * The function can be interrupted. Return from the function is not
- * a guarantee that the request is sent succesfully. Can return errors
+ * a guarantee that the request is sent successfully. Can return errors
  * that can be retrieved by PTR_ERR macros.
  *
  * @m: mux data
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 2cb87ba..5c6bdf8 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -530,9 +530,6 @@
 	if (vfid)
 		v9fs_fid_destroy(vfid);
 
-	if (inode)
-		iput(inode);
-
 	return err;
 }
 
@@ -1054,6 +1051,9 @@
 	int ret;
 	char *link = __getname();
 
+	if (unlikely(!link))
+		return -ENOMEM;
+
 	if (buflen > PATH_MAX)
 		buflen = PATH_MAX;
 
@@ -1171,9 +1171,6 @@
 	if (vfid)
 		v9fs_fid_destroy(vfid);
 
-	if (inode)
-		iput(inode);
-
 	return err;
 
 }
@@ -1227,6 +1224,9 @@
 	}
 
 	name = __getname();
+	if (unlikely(!name))
+		return -ENOMEM;
+
 	sprintf(name, "%d\n", oldfid->fid);
 	retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
 	__putname(name);
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 8729430..8b15bb2 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -256,11 +256,12 @@
 }
 
 static void
-v9fs_umount_begin(struct super_block *sb)
+v9fs_umount_begin(struct vfsmount *vfsmnt, int flags)
 {
-	struct v9fs_session_info *v9ses = sb->s_fs_info;
+	struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info;
 
-	v9fs_session_cancel(v9ses);
+	if (flags & MNT_FORCE)
+		v9fs_session_cancel(v9ses);
 }
 
 static struct super_operations v9fs_super_ops = {
diff --git a/fs/Kconfig b/fs/Kconfig
index 2aa4624..6c50518 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -776,7 +776,8 @@
 menu "Pseudo filesystems"
 
 config PROC_FS
-	bool "/proc file system support"
+	bool "/proc file system support" if EMBEDDED
+	default y
 	help
 	  This is a virtual file system providing information about the status
 	  of the system. "Virtual" means that it doesn't take up any space on
@@ -1370,11 +1371,19 @@
 
 config UFS_FS_WRITE
 	bool "UFS file system write support (DANGEROUS)"
-	depends on UFS_FS && EXPERIMENTAL && BROKEN
+	depends on UFS_FS && EXPERIMENTAL
 	help
 	  Say Y here if you want to try writing to UFS partitions. This is
 	  experimental, so you should back up your UFS partitions beforehand.
 
+config UFS_DEBUG
+	bool "UFS debugging"
+	depends on UFS_FS
+	help
+	  If you are experiencing any problems with the UFS filesystem, say
+	  Y here.  This will result in _many_ additional debugging messages to be
+	  written to the system log.
+
 endmenu
 
 menu "Network File Systems"
@@ -1481,7 +1490,12 @@
 	select LOCKD
 	select SUNRPC
 	select EXPORTFS
-	select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL
+	select NFSD_V2_ACL if NFSD_V3_ACL
+	select NFS_ACL_SUPPORT if NFSD_V2_ACL
+	select NFSD_TCP if NFSD_V4
+	select CRYPTO_MD5 if NFSD_V4
+	select CRYPTO if NFSD_V4
+	select FS_POSIX_ACL if NFSD_V4
 	help
 	  If you want your Linux box to act as an NFS *server*, so that other
 	  computers on your local network which support NFS can access certain
@@ -1519,7 +1533,6 @@
 config NFSD_V3_ACL
 	bool "Provide server support for the NFSv3 ACL protocol extension"
 	depends on NFSD_V3
-	select NFSD_V2_ACL
 	help
 	  Implement the NFSv3 ACL protocol extension for manipulating POSIX
 	  Access Control Lists on exported file systems. NFS clients should
@@ -1529,10 +1542,6 @@
 config NFSD_V4
 	bool "Provide NFSv4 server support (EXPERIMENTAL)"
 	depends on NFSD_V3 && EXPERIMENTAL
-	select NFSD_TCP
-	select CRYPTO_MD5
-	select CRYPTO
-	select FS_POSIX_ACL
 	help
 	  If you would like to include the NFSv4 server as well as the NFSv2
 	  and NFSv3 servers, say Y here.  This feature is experimental, and
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 8765cba..5200f49 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -271,6 +271,7 @@
 	int			 reserved;
 	unsigned long		 mount_flags;
 	int			 tmp_flags;	/* fix remount prototype... */
+	u8			 sig[4];
 
 	pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
 
@@ -370,8 +371,9 @@
 		printk(KERN_ERR "AFFS: Cannot read boot block\n");
 		goto out_error;
 	}
-	chksum = be32_to_cpu(*(__be32 *)boot_bh->b_data);
+	memcpy(sig, boot_bh->b_data, 4);
 	brelse(boot_bh);
+	chksum = be32_to_cpu(*(__be32 *)sig);
 
 	/* Dircache filesystems are compatible with non-dircache ones
 	 * when reading. As long as they aren't supported, writing is
@@ -420,11 +422,11 @@
 	}
 
 	if (mount_flags & SF_VERBOSE) {
-		chksum = cpu_to_be32(chksum);
-		printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
-			AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
+		u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0];
+		printk(KERN_NOTICE "AFFS: Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n",
+			len > 31 ? 31 : len,
 			AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
-			(char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+			sig, sig[3] + '0', blocksize);
 	}
 
 	sb->s_flags |= MS_NODEV | MS_NOSUID;
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 009a9ae..bfc1fd2 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -413,8 +413,7 @@
 
 	/* we found it in the graveyard - resurrect it */
  found_dead_server:
-	list_del(&server->link);
-	list_add_tail(&server->link, &cell->sv_list);
+	list_move_tail(&server->link, &cell->sv_list);
 	afs_get_server(server);
 	afs_kafstimod_del_timer(&server->timeout);
 	spin_unlock(&cell->sv_gylock);
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
index 7ac07d0..f09a794 100644
--- a/fs/afs/kafsasyncd.c
+++ b/fs/afs/kafsasyncd.c
@@ -136,8 +136,7 @@
 			if (!list_empty(&kafsasyncd_async_attnq)) {
 				op = list_entry(kafsasyncd_async_attnq.next,
 						struct afs_async_op, link);
-				list_del(&op->link);
-				list_add_tail(&op->link,
+				list_move_tail(&op->link,
 					      &kafsasyncd_async_busyq);
 			}
 
@@ -204,8 +203,7 @@
 	init_waitqueue_entry(&op->waiter, kafsasyncd_task);
 	add_wait_queue(&op->call->waitq, &op->waiter);
 
-	list_del(&op->link);
-	list_add_tail(&op->link, &kafsasyncd_async_busyq);
+	list_move_tail(&op->link, &kafsasyncd_async_busyq);
 
 	spin_unlock(&kafsasyncd_async_lock);
 
@@ -223,8 +221,7 @@
 
 	spin_lock(&kafsasyncd_async_lock);
 
-	list_del(&op->link);
-	list_add_tail(&op->link, &kafsasyncd_async_attnq);
+	list_move_tail(&op->link, &kafsasyncd_async_attnq);
 
 	spin_unlock(&kafsasyncd_async_lock);
 
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index b5cf9e1..99785a7 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -203,7 +203,7 @@
 
 	/* try and do the mount */
 	kdebug("--- attempting mount %s -o %s ---", devname, options);
-	mnt = do_kern_mount("afs", 0, devname, options);
+	mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
 	kdebug("--- mount result %p ---", mnt);
 
 	free_page((unsigned long) devname);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 62b093a..22afaae 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -123,8 +123,7 @@
  resurrect_server:
 	_debug("resurrecting server");
 
-	list_del(&zombie->link);
-	list_add_tail(&zombie->link, &cell->sv_list);
+	list_move_tail(&zombie->link, &cell->sv_list);
 	afs_get_server(zombie);
 	afs_kafstimod_del_timer(&zombie->timeout);
 	spin_unlock(&cell->sv_gylock);
@@ -168,8 +167,7 @@
 	}
 
 	spin_lock(&cell->sv_gylock);
-	list_del(&server->link);
-	list_add_tail(&server->link, &cell->sv_graveyard);
+	list_move_tail(&server->link, &cell->sv_graveyard);
 
 	/* time out in 10 secs */
 	afs_kafstimod_add_timer(&server->timeout, 10 * HZ);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 82468df..67d1f5c 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -48,7 +48,7 @@
 
 static void afs_destroy_inode(struct inode *inode);
 
-static struct file_system_type afs_fs_type = {
+struct file_system_type afs_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "afs",
 	.get_sb		= afs_get_sb,
diff --git a/fs/afs/super.h b/fs/afs/super.h
index ac11362..32de8cc 100644
--- a/fs/afs/super.h
+++ b/fs/afs/super.h
@@ -38,6 +38,8 @@
 	return sb->s_fs_info;
 }
 
+extern struct file_system_type afs_fs_type;
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_AFS_SUPER_H */
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index eced206..331f730 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -326,8 +326,7 @@
 	/* found in the graveyard - resurrect */
 	_debug("found in graveyard");
 	atomic_inc(&vlocation->usage);
-	list_del(&vlocation->link);
-	list_add_tail(&vlocation->link, &cell->vl_list);
+	list_move_tail(&vlocation->link, &cell->vl_list);
 	spin_unlock(&cell->vl_gylock);
 
 	afs_kafstimod_del_timer(&vlocation->timeout);
@@ -478,8 +477,7 @@
 	}
 
 	/* move to graveyard queue */
-	list_del(&vlocation->link);
-	list_add_tail(&vlocation->link,&cell->vl_graveyard);
+	list_move_tail(&vlocation->link,&cell->vl_graveyard);
 
 	/* remove from pending timeout queue (refcounted if actually being
 	 * updated) */
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index 9867fef..cf62da5 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -104,8 +104,7 @@
 					vnode->cb_expiry * HZ);
 
 		spin_lock(&afs_cb_hash_lock);
-		list_del(&vnode->cb_hash_link);
-		list_add_tail(&vnode->cb_hash_link,
+		list_move_tail(&vnode->cb_hash_link,
 			      &afs_cb_hash(server, &vnode->fid));
 		spin_unlock(&afs_cb_hash_lock);
 
diff --git a/fs/aio.c b/fs/aio.c
index 8c34a62..9506301 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -641,7 +641,7 @@
  *	invoked both for initial i/o submission and
  *	subsequent retries via the aio_kick_handler.
  *	Expects to be invoked with iocb->ki_ctx->lock
- *	already held. The lock is released and reaquired
+ *	already held. The lock is released and reacquired
  *	as needed during processing.
  *
  * Calls the iocb retry method (already setup for the
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index b8ce026..8dbd44f 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -174,6 +174,12 @@
 			struct autofs_info *ino = autofs4_dentry_ino(p);
 			unsigned int ino_count = atomic_read(&ino->count);
 
+			/*
+			 * Clean stale dentries below that have not been
+			 * invalidated after a mount fail during lookup
+			 */
+			d_invalidate(p);
+
 			/* allow for dget above and top is already dgot */
 			if (p == top)
 				ino_count += 2;
@@ -370,8 +376,7 @@
 		DPRINTK("returning %p %.*s",
 			expired, (int)expired->d_name.len, expired->d_name.name);
 		spin_lock(&dcache_lock);
-		list_del(&expired->d_parent->d_subdirs);
-		list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+		list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
 		spin_unlock(&dcache_lock);
 		return expired;
 	}
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index b1c902e..c94d52e 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -510,7 +510,7 @@
 		}
 
 		/* OK, This is the point of no return */
-		set_personality(PER_LINUX);
+		set_personality(PER_LINUX_32BIT);
 	}
 
 	/*
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 07a4996..34ebbc1 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -55,6 +55,7 @@
 } Node;
 
 static DEFINE_RWLOCK(entries_lock);
+static struct file_system_type bm_fs_type;
 static struct vfsmount *bm_mnt;
 static int entry_count;
 
@@ -637,7 +638,7 @@
 	if (!inode)
 		goto out2;
 
-	err = simple_pin_fs("binfmt_misc", &bm_mnt, &entry_count);
+	err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
 	if (err) {
 		iput(inode);
 		inode = NULL;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 7520f46..8b4de6e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -403,12 +403,14 @@
 #endif
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-static void cifs_umount_begin(struct super_block * sblock)
+static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
 {
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo * tcon;
 
-	cifs_sb = CIFS_SB(sblock);
+	if (!(flags & MNT_FORCE))
+		return;
+	cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
 	if(cifs_sb == NULL)
 		return;
 
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 6c6771d..7caee8d 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -259,7 +259,7 @@
 	/* If request was not a signal, enqueue and don't free */
 	if (!(req->uc_flags & REQ_ASYNC)) {
 		req->uc_flags |= REQ_READ;
-		list_add(&(req->uc_chain), vcp->vc_processing.prev);
+		list_add_tail(&(req->uc_chain), &vcp->vc_processing);
 		goto out;
 	}
 
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index b040eba..a5b5e63 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -725,7 +725,7 @@
 	((union inputArgs *)buffer)->ih.unique = req->uc_unique;
 
 	/* Append msg to pending queue and poke Venus. */
-	list_add(&(req->uc_chain), vcommp->vc_pending.prev);
+	list_add_tail(&(req->uc_chain), &vcommp->vc_pending);
         
 	wake_up_interruptible(&vcommp->vc_waitq);
 	/* We can be interrupted while we wait for Venus to process
diff --git a/fs/compat.c b/fs/compat.c
index 7e7e5bc..e31e9cf 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -55,6 +55,20 @@
 
 extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
 
+int compat_log = 1;
+
+int compat_printk(const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+	if (!compat_log)
+		return 0;
+	va_start(ap, fmt);
+	ret = vprintk(fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
 /*
  * Not all architectures have sys_utime, so implement this in terms
  * of sys_utimes.
@@ -359,7 +373,7 @@
 	sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
 	if (!isprint(buf[1]))
 		sprintf(buf, "%02x", buf[1]);
-	printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
+	compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
 			"cmd(%08x){%s} arg(%08x) on %s\n",
 			current->comm, current->pid,
 			(int)fd, (unsigned int)cmd, buf,
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index d2c3887..d8ecfed 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -80,6 +80,7 @@
 #include <net/bluetooth/rfcomm.h>
 
 #include <linux/capi.h>
+#include <linux/gigaset_dev.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
@@ -205,38 +206,6 @@
 	return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
 }
 
-struct compat_dmx_event {
-	dmx_event_t	event;
-	compat_time_t	timeStamp;
-	union
-	{
-		dmx_scrambling_status_t scrambling;
-	} u;
-};
-
-static int do_dmx_get_event(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	struct dmx_event kevent;
-	mm_segment_t old_fs = get_fs();
-	int err;
-
-	set_fs(KERNEL_DS);
-	err = sys_ioctl(fd, cmd, (unsigned long) &kevent);
-	set_fs(old_fs);
-
-	if (!err) {
-		struct compat_dmx_event __user *up = compat_ptr(arg);
-
-		err  = put_user(kevent.event, &up->event);
-		err |= put_user(kevent.timeStamp, &up->timeStamp);
-		err |= put_user(kevent.u.scrambling, &up->u.scrambling);
-		if (err)
-			err = -EFAULT;
-	}
-
-	return err;
-}
-
 struct compat_video_event {
 	int32_t		type;
 	compat_time_t	timestamp;
@@ -2964,7 +2933,6 @@
 #endif
 
 /* dvb */
-HANDLE_IOCTL(DMX_GET_EVENT, do_dmx_get_event)
 HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event)
 HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture)
 HANDLE_IOCTL(VIDEO_SET_SPU_PALETTE, do_video_set_spu_palette)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 5f95218..207f800 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1009,8 +1009,7 @@
 			/* fallthrough */
 		default:
 			if (filp->f_pos == 2) {
-				list_del(q);
-				list_add(q, &parent_sd->s_children);
+				list_move(q, &parent_sd->s_children);
 			}
 			for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
 				struct configfs_dirent *next;
@@ -1033,8 +1032,7 @@
 						 dt_type(next)) < 0)
 					return 0;
 
-				list_del(q);
-				list_add(q, p);
+				list_move(q, p);
 				p = q;
 				filp->f_pos++;
 			}
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 94dab7b..3e5fe84 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -118,7 +118,7 @@
 
 int configfs_pin_fs(void)
 {
-	return simple_pin_fs("configfs", &configfs_mount,
+	return simple_pin_fs(&configfs_fs_type, &configfs_mount,
 			     &configfs_mnt_count);
 }
 
diff --git a/fs/dcache.c b/fs/dcache.c
index 313b54b..48b44a7 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -406,7 +406,7 @@
 		cond_resched_lock(&dcache_lock);
 
 		tmp = dentry_unused.prev;
-		if (unlikely(sb)) {
+		if (sb) {
 			/* Try to find a dentry for this sb, but don't try
 			 * too hard, if they aren't near the tail they will
 			 * be moved down again soon
@@ -522,8 +522,7 @@
 		dentry = list_entry(tmp, struct dentry, d_lru);
 		if (dentry->d_sb != sb)
 			continue;
-		list_del(tmp);
-		list_add(tmp, &dentry_unused);
+		list_move(tmp, &dentry_unused);
 	}
 
 	/*
@@ -638,7 +637,7 @@
 		 * of the unused list for prune_dcache
 		 */
 		if (!atomic_read(&dentry->d_count)) {
-			list_add(&dentry->d_lru, dentry_unused.prev);
+			list_add_tail(&dentry->d_lru, &dentry_unused);
 			dentry_stat.nr_unused++;
 			found++;
 		}
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 440128e..6fa1e04 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -199,7 +199,7 @@
 
 	pr_debug("debugfs: creating file '%s'\n",name);
 
-	error = simple_pin_fs("debugfs", &debugfs_mount, &debugfs_mount_count);
+	error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
 	if (error)
 		goto exit;
 
diff --git a/fs/dquot.c b/fs/dquot.c
index 81d87a4..0122a27 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -250,7 +250,7 @@
 /* Add a dquot to the tail of the free list */
 static inline void put_dquot_last(struct dquot *dquot)
 {
-	list_add(&dquot->dq_free, free_dquots.prev);
+	list_add_tail(&dquot->dq_free, &free_dquots);
 	dqstats.free_dquots++;
 }
 
@@ -266,7 +266,7 @@
 {
 	/* We add to the back of inuse list so we don't have to restart
 	 * when traversing this list and we block */
-	list_add(&dquot->dq_inuse, inuse_list.prev);
+	list_add_tail(&dquot->dq_inuse, &inuse_list);
 	dqstats.allocated_dquots++;
 }
 
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 08e7e6a..9c677bb 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1,6 +1,6 @@
 /*
  *  fs/eventpoll.c ( Efficent event polling implementation )
- *  Copyright (C) 2001,...,2003	 Davide Libenzi
+ *  Copyright (C) 2001,...,2006	 Davide Libenzi
  *
  *  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
@@ -1004,7 +1004,7 @@
 
 		/* Notify waiting tasks that events are available */
 		if (waitqueue_active(&ep->wq))
-			wake_up(&ep->wq);
+			__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);
 		if (waitqueue_active(&ep->poll_wait))
 			pwake++;
 	}
@@ -1083,7 +1083,8 @@
 
 				/* Notify waiting tasks that events are available */
 				if (waitqueue_active(&ep->wq))
-					wake_up(&ep->wq);
+					__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+							 TASK_INTERRUPTIBLE);
 				if (waitqueue_active(&ep->poll_wait))
 					pwake++;
 			}
@@ -1260,7 +1261,8 @@
 	 * wait list.
 	 */
 	if (waitqueue_active(&ep->wq))
-		wake_up(&ep->wq);
+		__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+				 TASK_INTERRUPTIBLE);
 	if (waitqueue_active(&ep->poll_wait))
 		pwake++;
 
@@ -1444,7 +1446,8 @@
 		 * wait list.
 		 */
 		if (waitqueue_active(&ep->wq))
-			wake_up(&ep->wq);
+			__wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+					 TASK_INTERRUPTIBLE);
 		if (waitqueue_active(&ep->poll_wait))
 			pwake++;
 	}
@@ -1516,7 +1519,7 @@
 		 * ep_poll_callback() when events will become available.
 		 */
 		init_waitqueue_entry(&wait, current);
-		add_wait_queue(&ep->wq, &wait);
+		__add_wait_queue(&ep->wq, &wait);
 
 		for (;;) {
 			/*
@@ -1536,7 +1539,7 @@
 			jtimeout = schedule_timeout(jtimeout);
 			write_lock_irqsave(&ep->lock, flags);
 		}
-		remove_wait_queue(&ep->wq, &wait);
+		__remove_wait_queue(&ep->wq, &wait);
 
 		set_current_state(TASK_RUNNING);
 	}
diff --git a/fs/exec.c b/fs/exec.c
index 0b88bf6..c8494f5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -666,8 +666,6 @@
 	 * and to assume its PID:
 	 */
 	if (!thread_group_leader(current)) {
-		struct dentry *proc_dentry1, *proc_dentry2;
-
 		/*
 		 * Wait for the thread group leader to be a zombie.
 		 * It should already be zombie at this point, most
@@ -689,10 +687,6 @@
 		 */
 		current->start_time = leader->start_time;
 
-		spin_lock(&leader->proc_lock);
-		spin_lock(&current->proc_lock);
-		proc_dentry1 = proc_pid_unhash(current);
-		proc_dentry2 = proc_pid_unhash(leader);
 		write_lock_irq(&tasklist_lock);
 
 		BUG_ON(leader->tgid != current->tgid);
@@ -713,7 +707,7 @@
 		attach_pid(current, PIDTYPE_PID,  current->pid);
 		attach_pid(current, PIDTYPE_PGID, current->signal->pgrp);
 		attach_pid(current, PIDTYPE_SID,  current->signal->session);
-		list_add_tail_rcu(&current->tasks, &init_task.tasks);
+		list_replace_rcu(&leader->tasks, &current->tasks);
 
 		current->group_leader = current;
 		leader->group_leader = current;
@@ -721,7 +715,6 @@
 		/* Reduce leader to a thread */
 		detach_pid(leader, PIDTYPE_PGID);
 		detach_pid(leader, PIDTYPE_SID);
-		list_del_init(&leader->tasks);
 
 		current->exit_signal = SIGCHLD;
 
@@ -729,10 +722,6 @@
 		leader->exit_state = EXIT_DEAD;
 
 		write_unlock_irq(&tasklist_lock);
-		spin_unlock(&leader->proc_lock);
-		spin_unlock(&current->proc_lock);
-		proc_pid_flush(proc_dentry1);
-		proc_pid_flush(proc_dentry2);
         }
 
 	/*
@@ -1379,67 +1368,102 @@
 	*out_ptr = 0;
 }
 
-static void zap_threads (struct mm_struct *mm)
+static void zap_process(struct task_struct *start)
+{
+	struct task_struct *t;
+
+	start->signal->flags = SIGNAL_GROUP_EXIT;
+	start->signal->group_stop_count = 0;
+
+	t = start;
+	do {
+		if (t != current && t->mm) {
+			t->mm->core_waiters++;
+			sigaddset(&t->pending.signal, SIGKILL);
+			signal_wake_up(t, 1);
+		}
+	} while ((t = next_thread(t)) != start);
+}
+
+static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
+				int exit_code)
 {
 	struct task_struct *g, *p;
+	unsigned long flags;
+	int err = -EAGAIN;
+
+	spin_lock_irq(&tsk->sighand->siglock);
+	if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) {
+		tsk->signal->group_exit_code = exit_code;
+		zap_process(tsk);
+		err = 0;
+	}
+	spin_unlock_irq(&tsk->sighand->siglock);
+	if (err)
+		return err;
+
+	if (atomic_read(&mm->mm_users) == mm->core_waiters + 1)
+		goto done;
+
+	rcu_read_lock();
+	for_each_process(g) {
+		if (g == tsk->group_leader)
+			continue;
+
+		p = g;
+		do {
+			if (p->mm) {
+				if (p->mm == mm) {
+					/*
+					 * p->sighand can't disappear, but
+					 * may be changed by de_thread()
+					 */
+					lock_task_sighand(p, &flags);
+					zap_process(p);
+					unlock_task_sighand(p, &flags);
+				}
+				break;
+			}
+		} while ((p = next_thread(p)) != g);
+	}
+	rcu_read_unlock();
+done:
+	return mm->core_waiters;
+}
+
+static int coredump_wait(int exit_code)
+{
 	struct task_struct *tsk = current;
-	struct completion *vfork_done = tsk->vfork_done;
-	int traced = 0;
+	struct mm_struct *mm = tsk->mm;
+	struct completion startup_done;
+	struct completion *vfork_done;
+	int core_waiters;
+
+	init_completion(&mm->core_done);
+	init_completion(&startup_done);
+	mm->core_startup_done = &startup_done;
+
+	core_waiters = zap_threads(tsk, mm, exit_code);
+	up_write(&mm->mmap_sem);
+
+	if (unlikely(core_waiters < 0))
+		goto fail;
 
 	/*
 	 * Make sure nobody is waiting for us to release the VM,
 	 * otherwise we can deadlock when we wait on each other
 	 */
+	vfork_done = tsk->vfork_done;
 	if (vfork_done) {
 		tsk->vfork_done = NULL;
 		complete(vfork_done);
 	}
 
-	read_lock(&tasklist_lock);
-	do_each_thread(g,p)
-		if (mm == p->mm && p != tsk) {
-			force_sig_specific(SIGKILL, p);
-			mm->core_waiters++;
-			if (unlikely(p->ptrace) &&
-			    unlikely(p->parent->mm == mm))
-				traced = 1;
-		}
-	while_each_thread(g,p);
-
-	read_unlock(&tasklist_lock);
-
-	if (unlikely(traced)) {
-		/*
-		 * We are zapping a thread and the thread it ptraces.
-		 * If the tracee went into a ptrace stop for exit tracing,
-		 * we could deadlock since the tracer is waiting for this
-		 * coredump to finish.  Detach them so they can both die.
-		 */
-		write_lock_irq(&tasklist_lock);
-		do_each_thread(g,p) {
-			if (mm == p->mm && p != tsk &&
-			    p->ptrace && p->parent->mm == mm) {
-				__ptrace_detach(p, 0);
-			}
-		} while_each_thread(g,p);
-		write_unlock_irq(&tasklist_lock);
-	}
-}
-
-static void coredump_wait(struct mm_struct *mm)
-{
-	DECLARE_COMPLETION(startup_done);
-	int core_waiters;
-
-	mm->core_startup_done = &startup_done;
-
-	zap_threads(mm);
-	core_waiters = mm->core_waiters;
-	up_write(&mm->mmap_sem);
-
 	if (core_waiters)
 		wait_for_completion(&startup_done);
+fail:
 	BUG_ON(mm->core_waiters);
+	return core_waiters;
 }
 
 int do_coredump(long signr, int exit_code, struct pt_regs * regs)
@@ -1473,22 +1497,9 @@
 	}
 	mm->dumpable = 0;
 
-	retval = -EAGAIN;
-	spin_lock_irq(&current->sighand->siglock);
-	if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
-		current->signal->flags = SIGNAL_GROUP_EXIT;
-		current->signal->group_exit_code = exit_code;
-		current->signal->group_stop_count = 0;
-		retval = 0;
-	}
-	spin_unlock_irq(&current->sighand->siglock);
-	if (retval) {
-		up_write(&mm->mmap_sem);
+	retval = coredump_wait(exit_code);
+	if (retval < 0)
 		goto fail;
-	}
-
-	init_completion(&mm->core_done);
-	coredump_wait(mm);
 
 	/*
 	 * Clear any false indication of pending signals that might
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index c5d02da..e0b2b43 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_EXT2_FS) += ext2.o
 
-ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ext2-y := balloc.o dir.o file.o fsync.o ialloc.o inode.o \
 	  ioctl.o namei.o super.o symlink.o
 
 ext2-$(CONFIG_EXT2_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 2c00953..433a213 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -521,6 +521,26 @@
 	goto out_release;
 }
 
+#ifdef EXT2FS_DEBUG
+
+static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+
+unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
+{
+	unsigned int i;
+	unsigned long sum = 0;
+
+	if (!map)
+		return (0);
+	for (i = 0; i < numchars; i++)
+		sum += nibblemap[map->b_data[i] & 0xf] +
+			nibblemap[(map->b_data[i] >> 4) & 0xf];
+	return (sum);
+}
+
+#endif  /*  EXT2FS_DEBUG  */
+
+/* Superblock must be locked */
 unsigned long ext2_count_free_blocks (struct super_block * sb)
 {
 	struct ext2_group_desc * desc;
@@ -530,7 +550,6 @@
 	unsigned long bitmap_count, x;
 	struct ext2_super_block *es;
 
-	lock_super (sb);
 	es = EXT2_SB(sb)->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -554,7 +573,6 @@
 	printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
 		(long)le32_to_cpu(es->s_free_blocks_count),
 		desc_count, bitmap_count);
-	unlock_super (sb);
 	return bitmap_count;
 #else
         for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
deleted file mode 100644
index e9983a0..0000000
--- a/fs/ext2/bitmap.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  linux/fs/ext2/bitmap.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-#ifdef EXT2FS_DEBUG
-
-#include <linux/buffer_head.h>
-
-#include "ext2.h"
-
-static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
-unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
-{
-	unsigned int i;
-	unsigned long sum = 0;
-	
-	if (!map) 
-		return (0);
-	for (i = 0; i < numchars; i++)
-		sum += nibblemap[map->b_data[i] & 0xf] +
-			nibblemap[(map->b_data[i] >> 4) & 0xf];
-	return (sum);
-}
-
-#endif  /*  EXT2FS_DEBUG  */
-
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 3c1c9aa..92ea826 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -399,8 +399,7 @@
 	de = ext2_find_entry (dir, dentry, &page);
 	if (de) {
 		res = le32_to_cpu(de->inode);
-		kunmap(page);
-		page_cache_release(page);
+		ext2_put_page(page);
 	}
 	return res;
 }
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index c9c2e5f..7806b9e 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -24,7 +24,7 @@
 
 #include "ext2.h"
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>		/* for fsync_inode_buffers() */
+#include <linux/buffer_head.h>		/* for sync_mapping_buffers() */
 
 
 /*
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index e527652..308c252 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -638,6 +638,7 @@
 	return ERR_PTR(err);
 }
 
+/* Superblock must be locked */
 unsigned long ext2_count_free_inodes (struct super_block * sb)
 {
 	struct ext2_group_desc *desc;
@@ -649,7 +650,6 @@
 	unsigned long bitmap_count = 0;
 	struct buffer_head *bitmap_bh = NULL;
 
-	lock_super (sb);
 	es = EXT2_SB(sb)->s_es;
 	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
 		unsigned x;
@@ -672,7 +672,6 @@
 	printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
 		percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter),
 		desc_count, bitmap_count);
-	unlock_super(sb);
 	return desc_count;
 #else
 	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index ee4ba75..d4233b2 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -854,7 +854,6 @@
 	}
 	if (!ext2_check_descriptors (sb)) {
 		printk ("EXT2-fs: group descriptors corrupted!\n");
-		db_count = i;
 		goto failed_mount2;
 	}
 	sbi->s_gdb_count = db_count;
@@ -1046,6 +1045,7 @@
 	unsigned long overhead;
 	int i;
 
+	lock_super(sb);
 	if (test_opt (sb, MINIX_DF))
 		overhead = 0;
 	else {
@@ -1086,6 +1086,7 @@
 	buf->f_files = le32_to_cpu(sbi->s_es->s_inodes_count);
 	buf->f_ffree = ext2_count_free_inodes (sb);
 	buf->f_namelen = EXT2_NAME_LEN;
+	unlock_super(sb);
 	return 0;
 }
 
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 77927d6..96172e8 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -163,20 +163,19 @@
 #endif
 
 static int
-goal_in_my_reservation(struct ext3_reserve_window *rsv, int goal,
+goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
 			unsigned int group, struct super_block * sb)
 {
-	unsigned long group_first_block, group_last_block;
+	ext3_fsblk_t group_first_block, group_last_block;
 
-	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-				group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_first_block = ext3_group_first_block_no(sb, group);
 	group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
 
 	if ((rsv->_rsv_start > group_last_block) ||
 	    (rsv->_rsv_end < group_first_block))
 		return 0;
-	if ((goal >= 0) && ((goal + group_first_block < rsv->_rsv_start)
-		|| (goal + group_first_block > rsv->_rsv_end)))
+	if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
+		|| (grp_goal + group_first_block > rsv->_rsv_end)))
 		return 0;
 	return 1;
 }
@@ -187,7 +186,7 @@
  * Returns NULL if there are no windows or if all windows start after the goal.
  */
 static struct ext3_reserve_window_node *
-search_reserve_window(struct rb_root *root, unsigned long goal)
+search_reserve_window(struct rb_root *root, ext3_fsblk_t goal)
 {
 	struct rb_node *n = root->rb_node;
 	struct ext3_reserve_window_node *rsv;
@@ -223,7 +222,7 @@
 {
 	struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root;
 	struct rb_node *node = &rsv->rsv_node;
-	unsigned int start = rsv->rsv_start;
+	ext3_fsblk_t start = rsv->rsv_start;
 
 	struct rb_node ** p = &root->rb_node;
 	struct rb_node * parent = NULL;
@@ -310,20 +309,20 @@
 
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
-			 unsigned long block, unsigned long count,
-			 int *pdquot_freed_blocks)
+			 ext3_fsblk_t block, unsigned long count,
+			 unsigned long *pdquot_freed_blocks)
 {
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *gd_bh;
 	unsigned long block_group;
-	unsigned long bit;
+	ext3_grpblk_t bit;
 	unsigned long i;
 	unsigned long overflow;
 	struct ext3_group_desc * desc;
 	struct ext3_super_block * es;
 	struct ext3_sb_info *sbi;
 	int err = 0, ret;
-	unsigned group_freed;
+	ext3_grpblk_t group_freed;
 
 	*pdquot_freed_blocks = 0;
 	sbi = EXT3_SB(sb);
@@ -333,7 +332,7 @@
 	    block + count > le32_to_cpu(es->s_blocks_count)) {
 		ext3_error (sb, "ext3_free_blocks",
 			    "Freeing blocks not in datazone - "
-			    "block = %lu, count = %lu", block, count);
+			    "block = "E3FSBLK", count = %lu", block, count);
 		goto error_return;
 	}
 
@@ -369,7 +368,7 @@
 		      sbi->s_itb_per_group))
 		ext3_error (sb, "ext3_free_blocks",
 			    "Freeing blocks in system zones - "
-			    "Block = %lu, count = %lu",
+			    "Block = "E3FSBLK", count = %lu",
 			    block, count);
 
 	/*
@@ -453,7 +452,8 @@
 						bit + i, bitmap_bh->b_data)) {
 			jbd_unlock_bh_state(bitmap_bh);
 			ext3_error(sb, __FUNCTION__,
-				"bit already cleared for block %lu", block + i);
+				"bit already cleared for block "E3FSBLK,
+				 block + i);
 			jbd_lock_bh_state(bitmap_bh);
 			BUFFER_TRACE(bitmap_bh, "bit already cleared");
 		} else {
@@ -493,10 +493,10 @@
 
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks(handle_t *handle, struct inode *inode,
-			unsigned long block, unsigned long count)
+			ext3_fsblk_t block, unsigned long count)
 {
 	struct super_block * sb;
-	int dquot_freed_blocks;
+	unsigned long dquot_freed_blocks;
 
 	sb = inode->i_sb;
 	if (!sb) {
@@ -525,7 +525,7 @@
  * data-writes at some point, and disable it for metadata allocations or
  * sync-data inodes.
  */
-static int ext3_test_allocatable(int nr, struct buffer_head *bh)
+static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh)
 {
 	int ret;
 	struct journal_head *jh = bh2jh(bh);
@@ -542,11 +542,11 @@
 	return ret;
 }
 
-static int
-bitmap_search_next_usable_block(int start, struct buffer_head *bh,
-					int maxblocks)
+static ext3_grpblk_t
+bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+					ext3_grpblk_t maxblocks)
 {
-	int next;
+	ext3_grpblk_t next;
 	struct journal_head *jh = bh2jh(bh);
 
 	/*
@@ -576,10 +576,11 @@
  * the initial goal; then for a free byte somewhere in the bitmap; then
  * for any free bit in the bitmap.
  */
-static int
-find_next_usable_block(int start, struct buffer_head *bh, int maxblocks)
+static ext3_grpblk_t
+find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
+			ext3_grpblk_t maxblocks)
 {
-	int here, next;
+	ext3_grpblk_t here, next;
 	char *p, *r;
 
 	if (start > 0) {
@@ -591,7 +592,7 @@
 		 * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the
 		 * next 64-bit boundary is simple..
 		 */
-		int end_goal = (start + 63) & ~63;
+		ext3_grpblk_t end_goal = (start + 63) & ~63;
 		if (end_goal > maxblocks)
 			end_goal = maxblocks;
 		here = ext3_find_next_zero_bit(bh->b_data, end_goal, start);
@@ -628,7 +629,7 @@
  * zero (failure).
  */
 static inline int
-claim_block(spinlock_t *lock, int block, struct buffer_head *bh)
+claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh)
 {
 	struct journal_head *jh = bh2jh(bh);
 	int ret;
@@ -651,19 +652,18 @@
  * new bitmap.  In that case we must release write access to the old one via
  * ext3_journal_release_buffer(), else we'll run out of credits.
  */
-static int
+static ext3_grpblk_t
 ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
-			struct buffer_head *bitmap_bh, int goal,
+			struct buffer_head *bitmap_bh, ext3_grpblk_t grp_goal,
 			unsigned long *count, struct ext3_reserve_window *my_rsv)
 {
-	int group_first_block, start, end;
+	ext3_fsblk_t group_first_block;
+	ext3_grpblk_t start, end;
 	unsigned long num = 0;
 
 	/* we do allocation within the reservation window if we have a window */
 	if (my_rsv) {
-		group_first_block =
-			le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-			group * EXT3_BLOCKS_PER_GROUP(sb);
+		group_first_block = ext3_group_first_block_no(sb, group);
 		if (my_rsv->_rsv_start >= group_first_block)
 			start = my_rsv->_rsv_start - group_first_block;
 		else
@@ -673,13 +673,13 @@
 		if (end > EXT3_BLOCKS_PER_GROUP(sb))
 			/* reservation window crosses group boundary */
 			end = EXT3_BLOCKS_PER_GROUP(sb);
-		if ((start <= goal) && (goal < end))
-			start = goal;
+		if ((start <= grp_goal) && (grp_goal < end))
+			start = grp_goal;
 		else
-			goal = -1;
+			grp_goal = -1;
 	} else {
-		if (goal > 0)
-			start = goal;
+		if (grp_goal > 0)
+			start = grp_goal;
 		else
 			start = 0;
 		end = EXT3_BLOCKS_PER_GROUP(sb);
@@ -688,43 +688,43 @@
 	BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb));
 
 repeat:
-	if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) {
-		goal = find_next_usable_block(start, bitmap_bh, end);
-		if (goal < 0)
+	if (grp_goal < 0 || !ext3_test_allocatable(grp_goal, bitmap_bh)) {
+		grp_goal = find_next_usable_block(start, bitmap_bh, end);
+		if (grp_goal < 0)
 			goto fail_access;
 		if (!my_rsv) {
 			int i;
 
-			for (i = 0; i < 7 && goal > start &&
-					ext3_test_allocatable(goal - 1,
+			for (i = 0; i < 7 && grp_goal > start &&
+					ext3_test_allocatable(grp_goal - 1,
 								bitmap_bh);
-					i++, goal--)
+					i++, grp_goal--)
 				;
 		}
 	}
-	start = goal;
+	start = grp_goal;
 
-	if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+	if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
 		/*
 		 * The block was allocated by another thread, or it was
 		 * allocated and then freed by another thread
 		 */
 		start++;
-		goal++;
+		grp_goal++;
 		if (start >= end)
 			goto fail_access;
 		goto repeat;
 	}
 	num++;
-	goal++;
-	while (num < *count && goal < end
-		&& ext3_test_allocatable(goal, bitmap_bh)
-		&& claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
+	grp_goal++;
+	while (num < *count && grp_goal < end
+		&& ext3_test_allocatable(grp_goal, bitmap_bh)
+		&& claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
 		num++;
-		goal++;
+		grp_goal++;
 	}
 	*count = num;
-	return goal - num;
+	return grp_goal - num;
 fail_access:
 	*count = num;
 	return -1;
@@ -766,12 +766,13 @@
 static int find_next_reservable_window(
 				struct ext3_reserve_window_node *search_head,
 				struct ext3_reserve_window_node *my_rsv,
-				struct super_block * sb, int start_block,
-				int last_block)
+				struct super_block * sb,
+				ext3_fsblk_t start_block,
+				ext3_fsblk_t last_block)
 {
 	struct rb_node *next;
 	struct ext3_reserve_window_node *rsv, *prev;
-	int cur;
+	ext3_fsblk_t cur;
 	int size = my_rsv->rsv_goal_size;
 
 	/* TODO: make the start of the reservation window byte-aligned */
@@ -873,10 +874,10 @@
  *
  *	@rsv: the reservation
  *
- *	@goal: The goal (group-relative).  It is where the search for a
+ *	@grp_goal: The goal (group-relative).  It is where the search for a
  *		free reservable space should start from.
- *		if we have a goal(goal >0 ), then start from there,
- *		no goal(goal = -1), we start from the first block
+ *		if we have a grp_goal(grp_goal >0 ), then start from there,
+ *		no grp_goal(grp_goal = -1), we start from the first block
  *		of the group.
  *
  *	@sb: the super block
@@ -885,25 +886,24 @@
  *
  */
 static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
-		int goal, struct super_block *sb,
+		ext3_grpblk_t grp_goal, struct super_block *sb,
 		unsigned int group, struct buffer_head *bitmap_bh)
 {
 	struct ext3_reserve_window_node *search_head;
-	int group_first_block, group_end_block, start_block;
-	int first_free_block;
+	ext3_fsblk_t group_first_block, group_end_block, start_block;
+	ext3_grpblk_t first_free_block;
 	struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root;
 	unsigned long size;
 	int ret;
 	spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
 
-	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-				group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_first_block = ext3_group_first_block_no(sb, group);
 	group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
 
-	if (goal < 0)
+	if (grp_goal < 0)
 		start_block = group_first_block;
 	else
-		start_block = goal + group_first_block;
+		start_block = grp_goal + group_first_block;
 
 	size = my_rsv->rsv_goal_size;
 
@@ -1057,14 +1057,15 @@
  * sorted double linked list should be fast.
  *
  */
-static int
+static ext3_grpblk_t
 ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
 			unsigned int group, struct buffer_head *bitmap_bh,
-			int goal, struct ext3_reserve_window_node * my_rsv,
+			ext3_grpblk_t grp_goal,
+			struct ext3_reserve_window_node * my_rsv,
 			unsigned long *count, int *errp)
 {
-	unsigned long group_first_block;
-	int ret = 0;
+	ext3_fsblk_t group_first_block;
+	ext3_grpblk_t ret = 0;
 	int fatal;
 	unsigned long num = *count;
 
@@ -1090,17 +1091,16 @@
 	 */
 	if (my_rsv == NULL ) {
 		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh,
-						goal, count, NULL);
+						grp_goal, count, NULL);
 		goto out;
 	}
 	/*
-	 * goal is a group relative block number (if there is a goal)
-	 * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
+	 * grp_goal is a group relative block number (if there is a goal)
+	 * 0 < grp_goal < EXT3_BLOCKS_PER_GROUP(sb)
 	 * first block is a filesystem wide block number
 	 * first block is the block number of the first block in this group
 	 */
-	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
-			group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_first_block = ext3_group_first_block_no(sb, group);
 
 	/*
 	 * Basically we will allocate a new block from inode's reservation
@@ -1119,24 +1119,24 @@
 	 */
 	while (1) {
 		if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
-			!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) {
+			!goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb)) {
 			if (my_rsv->rsv_goal_size < *count)
 				my_rsv->rsv_goal_size = *count;
-			ret = alloc_new_reservation(my_rsv, goal, sb,
+			ret = alloc_new_reservation(my_rsv, grp_goal, sb,
 							group, bitmap_bh);
 			if (ret < 0)
 				break;			/* failed */
 
-			if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb))
-				goal = -1;
-		} else if (goal > 0 && (my_rsv->rsv_end-goal+1) < *count)
+			if (!goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb))
+				grp_goal = -1;
+		} else if (grp_goal > 0 && (my_rsv->rsv_end-grp_goal+1) < *count)
 			try_to_extend_reservation(my_rsv, sb,
-					*count-my_rsv->rsv_end + goal - 1);
+					*count-my_rsv->rsv_end + grp_goal - 1);
 
 		if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
 		    || (my_rsv->rsv_end < group_first_block))
 			BUG();
-		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
+		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal,
 					   &num, &my_rsv->rsv_window);
 		if (ret >= 0) {
 			my_rsv->rsv_alloc_hit += num;
@@ -1164,7 +1164,7 @@
 
 static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
 {
-	int free_blocks, root_blocks;
+	ext3_fsblk_t free_blocks, root_blocks;
 
 	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
 	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
@@ -1200,19 +1200,20 @@
  * bitmap, and then for any free bit if that fails.
  * This function also updates quota and i_blocks field.
  */
-int ext3_new_blocks(handle_t *handle, struct inode *inode,
-			unsigned long goal, unsigned long *count, int *errp)
+ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
+			ext3_fsblk_t goal, unsigned long *count, int *errp)
 {
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *gdp_bh;
 	int group_no;
 	int goal_group;
-	int ret_block;
+	ext3_grpblk_t grp_target_blk;	/* blockgroup relative goal block */
+	ext3_grpblk_t grp_alloc_blk;	/* blockgroup-relative allocated block*/
+	ext3_fsblk_t ret_block;		/* filesyetem-wide allocated block */
 	int bgi;			/* blockgroup iteration index */
-	int target_block;
 	int fatal = 0, err;
 	int performed_allocation = 0;
-	int free_blocks;
+	ext3_grpblk_t free_blocks;	/* number of free blocks in a group */
 	struct super_block *sb;
 	struct ext3_group_desc *gdp;
 	struct ext3_super_block *es;
@@ -1285,16 +1286,17 @@
 		my_rsv = NULL;
 
 	if (free_blocks > 0) {
-		ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
+		grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) %
 				EXT3_BLOCKS_PER_GROUP(sb));
 		bitmap_bh = read_block_bitmap(sb, group_no);
 		if (!bitmap_bh)
 			goto io_error;
-		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
-					bitmap_bh, ret_block, my_rsv, &num, &fatal);
+		grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle,
+					group_no, bitmap_bh, grp_target_blk,
+					my_rsv,	&num, &fatal);
 		if (fatal)
 			goto out;
-		if (ret_block >= 0)
+		if (grp_alloc_blk >= 0)
 			goto allocated;
 	}
 
@@ -1327,11 +1329,15 @@
 		bitmap_bh = read_block_bitmap(sb, group_no);
 		if (!bitmap_bh)
 			goto io_error;
-		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
-					bitmap_bh, -1, my_rsv, &num, &fatal);
+		/*
+		 * try to allocate block(s) from this group, without a goal(-1).
+		 */
+		grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle,
+					group_no, bitmap_bh, -1, my_rsv,
+					&num, &fatal);
 		if (fatal)
 			goto out;
-		if (ret_block >= 0) 
+		if (grp_alloc_blk >= 0)
 			goto allocated;
 	}
 	/*
@@ -1360,18 +1366,18 @@
 	if (fatal)
 		goto out;
 
-	target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb)
-				+ le32_to_cpu(es->s_first_data_block);
+	ret_block = grp_alloc_blk + ext3_group_first_block_no(sb, group_no);
 
-	if (in_range(le32_to_cpu(gdp->bg_block_bitmap), target_block, num) ||
-	    in_range(le32_to_cpu(gdp->bg_inode_bitmap), target_block, num) ||
-	    in_range(target_block, le32_to_cpu(gdp->bg_inode_table),
+	if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) ||
+	    in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) ||
+	    in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
 		      EXT3_SB(sb)->s_itb_per_group) ||
-	    in_range(target_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
+	    in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
 		      EXT3_SB(sb)->s_itb_per_group))
 		ext3_error(sb, "ext3_new_block",
 			    "Allocating block in system zone - "
-			    "blocks from %u, length %lu", target_block, num);
+			    "blocks from "E3FSBLK", length %lu",
+			     ret_block, num);
 
 	performed_allocation = 1;
 
@@ -1380,7 +1386,7 @@
 		struct buffer_head *debug_bh;
 
 		/* Record bitmap buffer state in the newly allocated block */
-		debug_bh = sb_find_get_block(sb, target_block);
+		debug_bh = sb_find_get_block(sb, ret_block);
 		if (debug_bh) {
 			BUFFER_TRACE(debug_bh, "state when allocated");
 			BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
@@ -1393,24 +1399,21 @@
 		int i;
 
 		for (i = 0; i < num; i++) {
-			if (ext3_test_bit(ret_block,
+			if (ext3_test_bit(grp_alloc_blk+i,
 					bh2jh(bitmap_bh)->b_committed_data)) {
 				printk("%s: block was unexpectedly set in "
 					"b_committed_data\n", __FUNCTION__);
 			}
 		}
 	}
-	ext3_debug("found bit %d\n", ret_block);
+	ext3_debug("found bit %d\n", grp_alloc_blk);
 	spin_unlock(sb_bgl_lock(sbi, group_no));
 	jbd_unlock_bh_state(bitmap_bh);
 #endif
 
-	/* ret_block was blockgroup-relative.  Now it becomes fs-relative */
-	ret_block = target_block;
-
 	if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) {
 		ext3_error(sb, "ext3_new_block",
-			    "block(%d) >= blocks count(%d) - "
+			    "block("E3FSBLK") >= blocks count(%d) - "
 			    "block_group = %d, es == %p ", ret_block,
 			le32_to_cpu(es->s_blocks_count), group_no, es);
 		goto out;
@@ -1421,7 +1424,7 @@
 	 * list of some description.  We don't know in advance whether
 	 * the caller wants to use it as metadata or data.
 	 */
-	ext3_debug("allocating block %d. Goal hits %d of %d.\n",
+	ext3_debug("allocating block %lu. Goal hits %d of %d.\n",
 			ret_block, goal_hits, goal_attempts);
 
 	spin_lock(sb_bgl_lock(sbi, group_no));
@@ -1461,23 +1464,24 @@
 	return 0;
 }
 
-int ext3_new_block(handle_t *handle, struct inode *inode,
-			unsigned long goal, int *errp)
+ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode,
+			ext3_fsblk_t goal, int *errp)
 {
 	unsigned long count = 1;
 
 	return ext3_new_blocks(handle, inode, goal, &count, errp);
 }
 
-unsigned long ext3_count_free_blocks(struct super_block *sb)
+ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
 {
-	unsigned long desc_count;
+	ext3_fsblk_t desc_count;
 	struct ext3_group_desc *gdp;
 	int i;
 	unsigned long ngroups = EXT3_SB(sb)->s_groups_count;
 #ifdef EXT3FS_DEBUG
 	struct ext3_super_block *es;
-	unsigned long bitmap_count, x;
+	ext3_fsblk_t bitmap_count;
+	unsigned long x;
 	struct buffer_head *bitmap_bh = NULL;
 
 	es = EXT3_SB(sb)->s_es;
@@ -1502,8 +1506,10 @@
 		bitmap_count += x;
 	}
 	brelse(bitmap_bh);
-	printk("ext3_count_free_blocks: stored = %u, computed = %lu, %lu\n",
-	       le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
+	printk("ext3_count_free_blocks: stored = "E3FSBLK
+		", computed = "E3FSBLK", "E3FSBLK"\n",
+	       le32_to_cpu(es->s_free_blocks_count),
+		desc_count, bitmap_count);
 	return bitmap_count;
 #else
 	desc_count = 0;
@@ -1520,7 +1526,7 @@
 }
 
 static inline int
-block_in_use(unsigned long block, struct super_block *sb, unsigned char *map)
+block_in_use(ext3_fsblk_t block, struct super_block *sb, unsigned char *map)
 {
 	return ext3_test_bit ((block -
 		le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) %
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index dc82646..36546ed 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -262,9 +262,11 @@
 	int ngroups = sbi->s_groups_count;
 	int inodes_per_group = EXT3_INODES_PER_GROUP(sb);
 	int freei, avefreei;
-	int freeb, avefreeb;
-	int blocks_per_dir, ndirs;
-	int max_debt, max_dirs, min_blocks, min_inodes;
+	ext3_fsblk_t freeb, avefreeb;
+	ext3_fsblk_t blocks_per_dir;
+	int ndirs;
+	int max_debt, max_dirs, min_inodes;
+	ext3_grpblk_t min_blocks;
 	int group = -1, i;
 	struct ext3_group_desc *desc;
 	struct buffer_head *bh;
@@ -307,7 +309,7 @@
 	min_inodes = avefreei - inodes_per_group / 4;
 	min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4;
 
-	max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST);
+	max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, (ext3_fsblk_t)BLOCK_COST);
 	if (max_debt * INODE_COST > inodes_per_group)
 		max_debt = inodes_per_group / INODE_COST;
 	if (max_debt > 255)
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 2edd7ee..0321e1b 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -62,7 +62,7 @@
  * still needs to be revoked.
  */
 int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
-			struct buffer_head *bh, int blocknr)
+			struct buffer_head *bh, ext3_fsblk_t blocknr)
 {
 	int err;
 
@@ -407,13 +407,13 @@
  *
  *	Caller must make sure that @ind is valid and will stay that way.
  */
-static unsigned long ext3_find_near(struct inode *inode, Indirect *ind)
+static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind)
 {
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	__le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
 	__le32 *p;
-	unsigned long bg_start;
-	unsigned long colour;
+	ext3_fsblk_t bg_start;
+	ext3_grpblk_t colour;
 
 	/* Try to find previous block */
 	for (p = ind->p - 1; p >= start; p--) {
@@ -429,8 +429,7 @@
 	 * It is going to be referred to from the inode itself? OK, just put it
 	 * into the same cylinder group then.
 	 */
-	bg_start = (ei->i_block_group * EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
-		le32_to_cpu(EXT3_SB(inode->i_sb)->s_es->s_first_data_block);
+	bg_start = ext3_group_first_block_no(inode->i_sb, ei->i_block_group);
 	colour = (current->pid % 16) *
 			(EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16);
 	return bg_start + colour;
@@ -448,7 +447,7 @@
  *	stores it in *@goal and returns zero.
  */
 
-static unsigned long ext3_find_goal(struct inode *inode, long block,
+static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
 		Indirect chain[4], Indirect *partial)
 {
 	struct ext3_block_alloc_info *block_i;
@@ -516,13 +515,13 @@
  *		direct blocks
  */
 static int ext3_alloc_blocks(handle_t *handle, struct inode *inode,
-			unsigned long goal, int indirect_blks, int blks,
-			unsigned long long new_blocks[4], int *err)
+			ext3_fsblk_t goal, int indirect_blks, int blks,
+			ext3_fsblk_t new_blocks[4], int *err)
 {
 	int target, i;
 	unsigned long count = 0;
 	int index = 0;
-	unsigned long current_block = 0;
+	ext3_fsblk_t current_block = 0;
 	int ret = 0;
 
 	/*
@@ -592,7 +591,7 @@
  *	as described above and return 0.
  */
 static int ext3_alloc_branch(handle_t *handle, struct inode *inode,
-			int indirect_blks, int *blks, unsigned long goal,
+			int indirect_blks, int *blks, ext3_fsblk_t goal,
 			int *offsets, Indirect *branch)
 {
 	int blocksize = inode->i_sb->s_blocksize;
@@ -600,8 +599,8 @@
 	int err = 0;
 	struct buffer_head *bh;
 	int num;
-	unsigned long long new_blocks[4];
-	unsigned long long current_block;
+	ext3_fsblk_t new_blocks[4];
+	ext3_fsblk_t current_block;
 
 	num = ext3_alloc_blocks(handle, inode, goal, indirect_blks,
 				*blks, new_blocks, &err);
@@ -688,7 +687,7 @@
 	int i;
 	int err = 0;
 	struct ext3_block_alloc_info *block_i;
-	unsigned long current_block;
+	ext3_fsblk_t current_block;
 
 	block_i = EXT3_I(inode)->i_block_alloc_info;
 	/*
@@ -795,13 +794,13 @@
 	int offsets[4];
 	Indirect chain[4];
 	Indirect *partial;
-	unsigned long goal;
+	ext3_fsblk_t goal;
 	int indirect_blks;
 	int blocks_to_boundary = 0;
 	int depth;
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	int count = 0;
-	unsigned long first_block = 0;
+	ext3_fsblk_t first_block = 0;
 
 
 	J_ASSERT(handle != NULL || create == 0);
@@ -819,7 +818,7 @@
 		count++;
 		/*map more blocks*/
 		while (count < maxblocks && count <= blocks_to_boundary) {
-			unsigned long blk;
+			ext3_fsblk_t blk;
 
 			if (!verify_chain(chain, partial)) {
 				/*
@@ -1759,7 +1758,7 @@
 static int ext3_block_truncate_page(handle_t *handle, struct page *page,
 		struct address_space *mapping, loff_t from)
 {
-	unsigned long index = from >> PAGE_CACHE_SHIFT;
+	ext3_fsblk_t index = from >> PAGE_CACHE_SHIFT;
 	unsigned offset = from & (PAGE_CACHE_SIZE-1);
 	unsigned blocksize, iblock, length, pos;
 	struct inode *inode = mapping->host;
@@ -1960,7 +1959,7 @@
  * than `count' because there can be holes in there.
  */
 static void ext3_clear_blocks(handle_t *handle, struct inode *inode,
-		struct buffer_head *bh, unsigned long block_to_free,
+		struct buffer_head *bh, ext3_fsblk_t block_to_free,
 		unsigned long count, __le32 *first, __le32 *last)
 {
 	__le32 *p;
@@ -2022,12 +2021,12 @@
 			   struct buffer_head *this_bh,
 			   __le32 *first, __le32 *last)
 {
-	unsigned long block_to_free = 0;    /* Starting block # of a run */
+	ext3_fsblk_t block_to_free = 0;    /* Starting block # of a run */
 	unsigned long count = 0;	    /* Number of blocks in the run */ 
 	__le32 *block_to_free_p = NULL;	    /* Pointer into inode/ind
 					       corresponding to
 					       block_to_free */
-	unsigned long nr;		    /* Current block # */
+	ext3_fsblk_t nr;		    /* Current block # */
 	__le32 *p;			    /* Pointer into inode/ind
 					       for current block */
 	int err;
@@ -2089,7 +2088,7 @@
 			       struct buffer_head *parent_bh,
 			       __le32 *first, __le32 *last, int depth)
 {
-	unsigned long nr;
+	ext3_fsblk_t nr;
 	__le32 *p;
 
 	if (is_handle_aborted(handle))
@@ -2113,7 +2112,7 @@
 			 */
 			if (!bh) {
 				ext3_error(inode->i_sb, "ext3_free_branches",
-					   "Read failure, inode=%ld, block=%ld",
+					   "Read failure, inode=%ld, block="E3FSBLK,
 					   inode->i_ino, nr);
 				continue;
 			}
@@ -2394,11 +2393,12 @@
 	ext3_journal_stop(handle);
 }
 
-static unsigned long ext3_get_inode_block(struct super_block *sb,
+static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
 		unsigned long ino, struct ext3_iloc *iloc)
 {
 	unsigned long desc, group_desc, block_group;
-	unsigned long offset, block;
+	unsigned long offset;
+	ext3_fsblk_t block;
 	struct buffer_head *bh;
 	struct ext3_group_desc * gdp;
 
@@ -2448,7 +2448,7 @@
 static int __ext3_get_inode_loc(struct inode *inode,
 				struct ext3_iloc *iloc, int in_mem)
 {
-	unsigned long block;
+	ext3_fsblk_t block;
 	struct buffer_head *bh;
 
 	block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc);
@@ -2459,7 +2459,8 @@
 	if (!bh) {
 		ext3_error (inode->i_sb, "ext3_get_inode_loc",
 				"unable to read inode block - "
-				"inode=%lu, block=%lu", inode->i_ino, block);
+				"inode=%lu, block="E3FSBLK,
+				 inode->i_ino, block);
 		return -EIO;
 	}
 	if (!buffer_uptodate(bh)) {
@@ -2540,7 +2541,7 @@
 		if (!buffer_uptodate(bh)) {
 			ext3_error(inode->i_sb, "ext3_get_inode_loc",
 					"unable to read inode block - "
-					"inode=%lu, block=%lu",
+					"inode=%lu, block="E3FSBLK,
 					inode->i_ino, block);
 			brelse(bh);
 			return -EIO;
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 8c22aa9..3a6b012 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -204,7 +204,7 @@
 		return 0;
 	}
 	case EXT3_IOC_GROUP_EXTEND: {
-		unsigned long n_blocks_count;
+		ext3_fsblk_t n_blocks_count;
 		struct super_block *sb = inode->i_sb;
 		int err;
 
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index b8f5cd1..d9176db 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1379,7 +1379,6 @@
 	int	dx_fallback=0;
 #endif
 	unsigned blocksize;
-	unsigned nlen, rlen;
 	u32 block, blocks;
 
 	sb = dir->i_sb;
@@ -1417,8 +1416,7 @@
 		return retval;
 	de = (struct ext3_dir_entry_2 *) bh->b_data;
 	de->inode = 0;
-	de->rec_len = cpu_to_le16(rlen = blocksize);
-	nlen = 0;
+	de->rec_len = cpu_to_le16(blocksize);
 	return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
 
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 34b39e9..dfd8118 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -28,16 +28,16 @@
 {
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
 	struct ext3_super_block *es = sbi->s_es;
-	unsigned start = le32_to_cpu(es->s_blocks_count);
-	unsigned end = start + input->blocks_count;
+	ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count);
+	ext3_fsblk_t end = start + input->blocks_count;
 	unsigned group = input->group;
-	unsigned itend = input->inode_table + sbi->s_itb_per_group;
+	ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
 	unsigned overhead = ext3_bg_has_super(sb, group) ?
 		(1 + ext3_bg_num_gdb(sb, group) +
 		 le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
-	unsigned metaend = start + overhead;
+	ext3_fsblk_t metaend = start + overhead;
 	struct buffer_head *bh = NULL;
-	int free_blocks_count;
+	ext3_grpblk_t free_blocks_count;
 	int err = -EINVAL;
 
 	input->free_blocks_count = free_blocks_count =
@@ -64,7 +64,8 @@
 		ext3_warning(sb, __FUNCTION__, "Bad blocks count %u",
 			     input->blocks_count);
 	else if (!(bh = sb_bread(sb, end - 1)))
-		ext3_warning(sb, __FUNCTION__, "Cannot read last block (%u)",
+		ext3_warning(sb, __FUNCTION__,
+			     "Cannot read last block ("E3FSBLK")",
 			     end - 1);
 	else if (outside(input->block_bitmap, start, end))
 		ext3_warning(sb, __FUNCTION__,
@@ -77,7 +78,7 @@
 	else if (outside(input->inode_table, start, end) ||
 	         outside(itend - 1, start, end))
 		ext3_warning(sb, __FUNCTION__,
-			     "Inode table not in group (blocks %u-%u)",
+			     "Inode table not in group (blocks %u-"E3FSBLK")",
 			     input->inode_table, itend - 1);
 	else if (input->inode_bitmap == input->block_bitmap)
 		ext3_warning(sb, __FUNCTION__,
@@ -85,24 +86,27 @@
 			     input->block_bitmap);
 	else if (inside(input->block_bitmap, input->inode_table, itend))
 		ext3_warning(sb, __FUNCTION__,
-			     "Block bitmap (%u) in inode table (%u-%u)",
+			     "Block bitmap (%u) in inode table (%u-"E3FSBLK")",
 			     input->block_bitmap, input->inode_table, itend-1);
 	else if (inside(input->inode_bitmap, input->inode_table, itend))
 		ext3_warning(sb, __FUNCTION__,
-			     "Inode bitmap (%u) in inode table (%u-%u)",
+			     "Inode bitmap (%u) in inode table (%u-"E3FSBLK")",
 			     input->inode_bitmap, input->inode_table, itend-1);
 	else if (inside(input->block_bitmap, start, metaend))
 		ext3_warning(sb, __FUNCTION__,
-			     "Block bitmap (%u) in GDT table (%u-%u)",
+			     "Block bitmap (%u) in GDT table"
+			     " ("E3FSBLK"-"E3FSBLK")",
 			     input->block_bitmap, start, metaend - 1);
 	else if (inside(input->inode_bitmap, start, metaend))
 		ext3_warning(sb, __FUNCTION__,
-			     "Inode bitmap (%u) in GDT table (%u-%u)",
+			     "Inode bitmap (%u) in GDT table"
+			     " ("E3FSBLK"-"E3FSBLK")",
 			     input->inode_bitmap, start, metaend - 1);
 	else if (inside(input->inode_table, start, metaend) ||
 	         inside(itend - 1, start, metaend))
 		ext3_warning(sb, __FUNCTION__,
-			     "Inode table (%u-%u) overlaps GDT table (%u-%u)",
+			     "Inode table (%u-"E3FSBLK") overlaps"
+			     "GDT table ("E3FSBLK"-"E3FSBLK")",
 			     input->inode_table, itend - 1, start, metaend - 1);
 	else
 		err = 0;
@@ -112,7 +116,7 @@
 }
 
 static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
-				  unsigned long blk)
+				  ext3_fsblk_t blk)
 {
 	struct buffer_head *bh;
 	int err;
@@ -163,15 +167,14 @@
 				  struct ext3_new_group_data *input)
 {
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
-	unsigned long start = input->group * sbi->s_blocks_per_group +
-		le32_to_cpu(sbi->s_es->s_first_data_block);
+	ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group);
 	int reserved_gdb = ext3_bg_has_super(sb, input->group) ?
 		le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;
 	unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group);
 	struct buffer_head *bh;
 	handle_t *handle;
-	unsigned long block;
-	int bit;
+	ext3_fsblk_t block;
+	ext3_grpblk_t bit;
 	int i;
 	int err = 0, err2;
 
@@ -328,7 +331,7 @@
 static int verify_reserved_gdb(struct super_block *sb,
 			       struct buffer_head *primary)
 {
-	const unsigned long blk = primary->b_blocknr;
+	const ext3_fsblk_t blk = primary->b_blocknr;
 	const unsigned long end = EXT3_SB(sb)->s_groups_count;
 	unsigned three = 1;
 	unsigned five = 5;
@@ -340,7 +343,8 @@
 	while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
 		if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){
 			ext3_warning(sb, __FUNCTION__,
-				     "reserved GDT %ld missing grp %d (%ld)",
+				     "reserved GDT "E3FSBLK
+				     " missing grp %d ("E3FSBLK")",
 				     blk, grp,
 				     grp * EXT3_BLOCKS_PER_GROUP(sb) + blk);
 			return -EINVAL;
@@ -372,7 +376,7 @@
 	struct super_block *sb = inode->i_sb;
 	struct ext3_super_block *es = EXT3_SB(sb)->s_es;
 	unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb);
-	unsigned long gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
+	ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
 	struct buffer_head **o_group_desc, **n_group_desc;
 	struct buffer_head *dind;
 	int gdbackups;
@@ -417,7 +421,7 @@
 	data = (__u32 *)dind->b_data;
 	if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
 		ext3_warning(sb, __FUNCTION__,
-			     "new group %u GDT block %lu not reserved",
+			     "new group %u GDT block "E3FSBLK" not reserved",
 			     input->group, gdblock);
 		err = -EINVAL;
 		goto exit_dind;
@@ -515,7 +519,7 @@
 	struct buffer_head **primary;
 	struct buffer_head *dind;
 	struct ext3_iloc iloc;
-	unsigned long blk;
+	ext3_fsblk_t blk;
 	__u32 *data, *end;
 	int gdbackups = 0;
 	int res, i;
@@ -540,7 +544,8 @@
 	for (res = 0; res < reserved_gdb; res++, blk++) {
 		if (le32_to_cpu(*data) != blk) {
 			ext3_warning(sb, __FUNCTION__,
-				     "reserved block %lu not at offset %ld",
+				     "reserved block "E3FSBLK
+				     " not at offset %ld",
 				     blk, (long)(data - (__u32 *)dind->b_data));
 			err = -EINVAL;
 			goto exit_bh;
@@ -902,15 +907,16 @@
  * GDT blocks are reserved to grow to the desired size.
  */
 int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
-		      unsigned long n_blocks_count)
+		      ext3_fsblk_t n_blocks_count)
 {
-	unsigned long o_blocks_count;
+	ext3_fsblk_t o_blocks_count;
 	unsigned long o_groups_count;
-	unsigned long last;
-	int add;
+	ext3_grpblk_t last;
+	ext3_grpblk_t add;
 	struct buffer_head * bh;
 	handle_t *handle;
-	int err, freed_blocks;
+	int err;
+	unsigned long freed_blocks;
 
 	/* We don't need to worry about locking wrt other resizers just
 	 * yet: we're going to revalidate es->s_blocks_count after
@@ -919,12 +925,22 @@
 	o_groups_count = EXT3_SB(sb)->s_groups_count;
 
 	if (test_opt(sb, DEBUG))
-		printk(KERN_DEBUG "EXT3-fs: extending last group from %lu to %lu blocks\n",
+		printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK" uto "E3FSBLK" blocks\n",
 		       o_blocks_count, n_blocks_count);
 
 	if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
 		return 0;
 
+	if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+		printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+			" too large to resize to %lu blocks safely\n",
+			sb->s_id, n_blocks_count);
+		if (sizeof(sector_t) < 8)
+			ext3_warning(sb, __FUNCTION__,
+			"CONFIG_LBD not enabled\n");
+		return -EINVAL;
+	}
+
 	if (n_blocks_count < o_blocks_count) {
 		ext3_warning(sb, __FUNCTION__,
 			     "can't shrink FS - resize aborted");
@@ -948,7 +964,8 @@
 
 	if (o_blocks_count + add < n_blocks_count)
 		ext3_warning(sb, __FUNCTION__,
-			     "will only finish group (%lu blocks, %u new)",
+			     "will only finish group ("E3FSBLK
+			     " blocks, %u new)",
 			     o_blocks_count + add, add);
 
 	/* See if the device is actually as big as what was requested */
@@ -991,10 +1008,10 @@
 	ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
 	sb->s_dirt = 1;
 	unlock_super(sb);
-	ext3_debug("freeing blocks %ld through %ld\n", o_blocks_count,
+	ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count,
 		   o_blocks_count + add);
 	ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
-	ext3_debug("freed blocks %ld through %ld\n", o_blocks_count,
+	ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", o_blocks_count,
 		   o_blocks_count + add);
 	if ((err = ext3_journal_stop(handle)))
 		goto exit_put;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index a60cc6e..b748336 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -630,7 +630,7 @@
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
 	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_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
 	Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -666,6 +666,7 @@
 	{Opt_noreservation, "noreservation"},
 	{Opt_noload, "noload"},
 	{Opt_nobh, "nobh"},
+	{Opt_bh, "bh"},
 	{Opt_commit, "commit=%u"},
 	{Opt_journal_update, "journal=update"},
 	{Opt_journal_inum, "journal=%u"},
@@ -689,14 +690,15 @@
 	{Opt_resize, "resize"},
 };
 
-static unsigned long get_sb_block(void **data)
+static ext3_fsblk_t get_sb_block(void **data)
 {
-	unsigned long 	sb_block;
+	ext3_fsblk_t 	sb_block;
 	char 		*options = (char *) *data;
 
 	if (!options || strncmp(options, "sb=", 3) != 0)
 		return 1;	/* Default location */
 	options += 3;
+	/*todo: use simple_strtoll with >32bit ext3 */
 	sb_block = simple_strtoul(options, &options, 0);
 	if (*options && *options != ',') {
 		printk("EXT3-fs: Invalid sb specification: %s\n",
@@ -711,7 +713,7 @@
 
 static int parse_options (char *options, struct super_block *sb,
 			  unsigned long *inum, unsigned long *journal_devnum,
-			  unsigned long *n_blocks_count, int is_remount)
+			  ext3_fsblk_t *n_blocks_count, int is_remount)
 {
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
 	char * p;
@@ -1013,6 +1015,9 @@
 		case Opt_nobh:
 			set_opt(sbi->s_mount_opt, NOBH);
 			break;
+		case Opt_bh:
+			clear_opt(sbi->s_mount_opt, NOBH);
+			break;
 		default:
 			printk (KERN_ERR
 				"EXT3-fs: Unrecognized mount option \"%s\" "
@@ -1128,7 +1133,7 @@
 static int ext3_check_descriptors (struct super_block * sb)
 {
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
-	unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
+	ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block);
 	struct ext3_group_desc * gdp = NULL;
 	int desc_block = 0;
 	int i;
@@ -1315,15 +1320,14 @@
 	return res;
 }
 
-static unsigned long descriptor_loc(struct super_block *sb,
-				    unsigned long logic_sb_block,
+static ext3_fsblk_t descriptor_loc(struct super_block *sb,
+				    ext3_fsblk_t logic_sb_block,
 				    int nr)
 {
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
-	unsigned long bg, first_data_block, first_meta_bg;
+	unsigned long bg, first_meta_bg;
 	int has_super = 0;
 
-	first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
 	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
 
 	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
@@ -1332,7 +1336,7 @@
 	bg = sbi->s_desc_per_block * nr;
 	if (ext3_bg_has_super(sb, bg))
 		has_super = 1;
-	return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
+	return (has_super + ext3_group_first_block_no(sb, bg));
 }
 
 
@@ -1341,9 +1345,9 @@
 	struct buffer_head * bh;
 	struct ext3_super_block *es = NULL;
 	struct ext3_sb_info *sbi;
-	unsigned long block;
-	unsigned long sb_block = get_sb_block(&data);
-	unsigned long logic_sb_block;
+	ext3_fsblk_t block;
+	ext3_fsblk_t sb_block = get_sb_block(&data);
+	ext3_fsblk_t logic_sb_block;
 	unsigned long offset = 0;
 	unsigned long journal_inum = 0;
 	unsigned long journal_devnum = 0;
@@ -1565,6 +1569,16 @@
 		goto failed_mount;
 	}
 
+	if (le32_to_cpu(es->s_blocks_count) >
+		    (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+		printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+			" too large to mount safely\n", sb->s_id);
+		if (sizeof(sector_t) < 8)
+			printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not "
+					"enabled\n");
+		goto failed_mount;
+	}
+
 	if (EXT3_BLOCKS_PER_GROUP(sb) == 0)
 		goto cantfind_ext3;
 	sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
@@ -1593,7 +1607,7 @@
 		}
 	}
 	if (!ext3_check_descriptors (sb)) {
-		printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n");
+		printk(KERN_ERR "EXT3-fs: group descriptors corrupted!\n");
 		goto failed_mount2;
 	}
 	sbi->s_gdb_count = db_count;
@@ -1830,10 +1844,10 @@
 {
 	struct buffer_head * bh;
 	journal_t *journal;
-	int start;
-	int len;
+	ext3_fsblk_t start;
+	ext3_fsblk_t len;
 	int hblock, blocksize;
-	unsigned long sb_block;
+	ext3_fsblk_t sb_block;
 	unsigned long offset;
 	struct ext3_super_block * es;
 	struct block_device *bdev;
@@ -2206,7 +2220,7 @@
 {
 	struct ext3_super_block * es;
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
-	unsigned long n_blocks_count = 0;
+	ext3_fsblk_t n_blocks_count = 0;
 	unsigned long old_sb_flags;
 	struct ext3_mount_options old_opts;
 	int err;
@@ -2326,7 +2340,7 @@
 	struct super_block *sb = dentry->d_sb;
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
 	struct ext3_super_block *es = sbi->s_es;
-	unsigned long overhead;
+	ext3_fsblk_t overhead;
 	int i;
 
 	if (test_opt (sb, MINIX_DF))
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index e8d60bf..a44a056 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -225,7 +225,7 @@
 	error = -ENODATA;
 	if (!EXT3_I(inode)->i_file_acl)
 		goto cleanup;
-	ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
+	ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
 	if (!bh)
 		goto cleanup;
@@ -233,7 +233,7 @@
 		atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
 	if (ext3_xattr_check_block(bh)) {
 bad_block:	ext3_error(inode->i_sb, __FUNCTION__,
-			   "inode %ld: bad block %d", inode->i_ino,
+			   "inode %ld: bad block "E3FSBLK, inode->i_ino,
 			   EXT3_I(inode)->i_file_acl);
 		error = -EIO;
 		goto cleanup;
@@ -366,7 +366,7 @@
 	error = 0;
 	if (!EXT3_I(inode)->i_file_acl)
 		goto cleanup;
-	ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
+	ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);
 	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
 	error = -EIO;
 	if (!bh)
@@ -375,7 +375,7 @@
 		atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
 	if (ext3_xattr_check_block(bh)) {
 		ext3_error(inode->i_sb, __FUNCTION__,
-			   "inode %ld: bad block %d", inode->i_ino,
+			   "inode %ld: bad block "E3FSBLK, inode->i_ino,
 			   EXT3_I(inode)->i_file_acl);
 		error = -EIO;
 		goto cleanup;
@@ -647,7 +647,7 @@
 			le32_to_cpu(BHDR(bs->bh)->h_refcount));
 		if (ext3_xattr_check_block(bs->bh)) {
 			ext3_error(sb, __FUNCTION__,
-				"inode %ld: bad block %d", inode->i_ino,
+				"inode %ld: bad block "E3FSBLK, inode->i_ino,
 				EXT3_I(inode)->i_file_acl);
 			error = -EIO;
 			goto cleanup;
@@ -792,11 +792,12 @@
 			get_bh(new_bh);
 		} else {
 			/* We need to allocate a new block */
-			int goal = le32_to_cpu(
+			ext3_fsblk_t goal = le32_to_cpu(
 					EXT3_SB(sb)->s_es->s_first_data_block) +
-				EXT3_I(inode)->i_block_group *
+				(ext3_fsblk_t)EXT3_I(inode)->i_block_group *
 				EXT3_BLOCKS_PER_GROUP(sb);
-			int block = ext3_new_block(handle, inode, goal, &error);
+			ext3_fsblk_t block = ext3_new_block(handle, inode,
+							goal, &error);
 			if (error)
 				goto cleanup;
 			ea_idebug(inode, "creating block %d", block);
@@ -847,7 +848,7 @@
 
 bad_block:
 	ext3_error(inode->i_sb, __FUNCTION__,
-		   "inode %ld: bad block %d", inode->i_ino,
+		   "inode %ld: bad block "E3FSBLK, inode->i_ino,
 		   EXT3_I(inode)->i_file_acl);
 	goto cleanup;
 
@@ -1076,14 +1077,14 @@
 	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
 	if (!bh) {
 		ext3_error(inode->i_sb, __FUNCTION__,
-			"inode %ld: block %d read error", inode->i_ino,
+			"inode %ld: block "E3FSBLK" read error", inode->i_ino,
 			EXT3_I(inode)->i_file_acl);
 		goto cleanup;
 	}
 	if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
 	    BHDR(bh)->h_blocks != cpu_to_le32(1)) {
 		ext3_error(inode->i_sb, __FUNCTION__,
-			"inode %ld: bad block %d", inode->i_ino,
+			"inode %ld: bad block "E3FSBLK, inode->i_ino,
 			EXT3_I(inode)->i_file_acl);
 		goto cleanup;
 	}
@@ -1210,11 +1211,11 @@
 		bh = sb_bread(inode->i_sb, ce->e_block);
 		if (!bh) {
 			ext3_error(inode->i_sb, __FUNCTION__,
-				"inode %ld: block %ld read error",
+				"inode %ld: block %lu read error",
 				inode->i_ino, (unsigned long) ce->e_block);
 		} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
 				EXT3_XATTR_REFCOUNT_MAX) {
-			ea_idebug(inode, "block %ld refcount %d>=%d",
+			ea_idebug(inode, "block %lu refcount %d>=%d",
 				  (unsigned long) ce->e_block,
 				  le32_to_cpu(BHDR(bh)->h_refcount),
 					  EXT3_XATTR_REFCOUNT_MAX);
diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
index 583bd78..d35979a 100644
--- a/fs/freevxfs/vxfs.h
+++ b/fs/freevxfs/vxfs.h
@@ -159,11 +159,11 @@
  * In core superblock filesystem private data for VxFS.
  */
 struct vxfs_sb_info {
-	struct vxfs_sb		*vsi_raw;	/* raw (on disk) supeblock */
+	struct vxfs_sb		*vsi_raw;	/* raw (on disk) superblock */
 	struct buffer_head	*vsi_bp;	/* buffer for raw superblock*/
 	struct inode		*vsi_fship;	/* fileset header inode */
 	struct inode		*vsi_ilist;	/* inode list inode */
-	struct inode		*vsi_stilist;	/* structual inode list inode */
+	struct inode		*vsi_stilist;	/* structural inode list inode */
 	u_long			vsi_iext;	/* initial inode list */
 	ino_t			vsi_fshino;	/* fileset header inode */
 	daddr_t			vsi_oltext;	/* OLT extent */
diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c
index 6dee109..78948b4 100644
--- a/fs/freevxfs/vxfs_fshead.c
+++ b/fs/freevxfs/vxfs_fshead.c
@@ -112,7 +112,7 @@
 
 	vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
 	if (!vip) {
-		printk(KERN_ERR "vxfs: unabled to read fsh inode\n");
+		printk(KERN_ERR "vxfs: unable to read fsh inode\n");
 		return -EINVAL;
 	}
 	if (!VXFS_ISFSH(vip)) {
@@ -129,13 +129,13 @@
 
 	infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
 	if (!infp->vsi_fship) {
-		printk(KERN_ERR "vxfs: unabled to get fsh inode\n");
+		printk(KERN_ERR "vxfs: unable to get fsh inode\n");
 		goto out_free_fship;
 	}
 
 	sfp = vxfs_getfsh(infp->vsi_fship, 0);
 	if (!sfp) {
-		printk(KERN_ERR "vxfs: unabled to get structural fsh\n");
+		printk(KERN_ERR "vxfs: unable to get structural fsh\n");
 		goto out_iput_fship;
 	} 
 
@@ -145,7 +145,7 @@
 
 	pfp = vxfs_getfsh(infp->vsi_fship, 1);
 	if (!pfp) {
-		printk(KERN_ERR "vxfs: unabled to get primary fsh\n");
+		printk(KERN_ERR "vxfs: unable to get primary fsh\n");
 		goto out_free_sfp;
 	}
 
@@ -159,7 +159,7 @@
 
 	infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
 	if (!infp->vsi_stilist) {
-		printk(KERN_ERR "vxfs: unabled to get structual list inode\n");
+		printk(KERN_ERR "vxfs: unable to get structural list inode\n");
 		kfree(tip);
 		goto out_free_pfp;
 	}
@@ -174,7 +174,7 @@
 		goto out_iput_stilist;
 	infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
 	if (!infp->vsi_ilist) {
-		printk(KERN_ERR "vxfs: unabled to get inode list inode\n");
+		printk(KERN_ERR "vxfs: unable to get inode list inode\n");
 		kfree(tip);
 		goto out_iput_stilist;
 	}
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index c3e1f76..7243706 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_FUSE_FS) += fuse.o
 
-fuse-objs := dev.o dir.o file.o inode.o
+fuse-objs := dev.o dir.o file.o inode.o control.o
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
new file mode 100644
index 0000000..a3bce3a
--- /dev/null
+++ b/fs/fuse/control.c
@@ -0,0 +1,218 @@
+/*
+  FUSE: Filesystem in Userspace
+  Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU GPL.
+  See the file COPYING.
+*/
+
+#include "fuse_i.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#define FUSE_CTL_SUPER_MAGIC 0x65735543
+
+/*
+ * This is non-NULL when the single instance of the control filesystem
+ * exists.  Protected by fuse_mutex
+ */
+static struct super_block *fuse_control_sb;
+
+static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
+{
+	struct fuse_conn *fc;
+	mutex_lock(&fuse_mutex);
+	fc = file->f_dentry->d_inode->u.generic_ip;
+	if (fc)
+		fc = fuse_conn_get(fc);
+	mutex_unlock(&fuse_mutex);
+	return fc;
+}
+
+static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
+				     size_t count, loff_t *ppos)
+{
+	struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
+	if (fc) {
+		fuse_abort_conn(fc);
+		fuse_conn_put(fc);
+	}
+	return count;
+}
+
+static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
+				      size_t len, loff_t *ppos)
+{
+	char tmp[32];
+	size_t size;
+
+	if (!*ppos) {
+		struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
+		if (!fc)
+			return 0;
+
+		file->private_data=(void *)(long)atomic_read(&fc->num_waiting);
+		fuse_conn_put(fc);
+	}
+	size = sprintf(tmp, "%ld\n", (long)file->private_data);
+	return simple_read_from_buffer(buf, len, ppos, tmp, size);
+}
+
+static const struct file_operations fuse_ctl_abort_ops = {
+	.open = nonseekable_open,
+	.write = fuse_conn_abort_write,
+};
+
+static const struct file_operations fuse_ctl_waiting_ops = {
+	.open = nonseekable_open,
+	.read = fuse_conn_waiting_read,
+};
+
+static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
+					  struct fuse_conn *fc,
+					  const char *name,
+					  int mode, int nlink,
+					  struct inode_operations *iop,
+					  const struct file_operations *fop)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+
+	BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES);
+	dentry = d_alloc_name(parent, name);
+	if (!dentry)
+		return NULL;
+
+	fc->ctl_dentry[fc->ctl_ndents++] = dentry;
+	inode = new_inode(fuse_control_sb);
+	if (!inode)
+		return NULL;
+
+	inode->i_mode = mode;
+	inode->i_uid = fc->user_id;
+	inode->i_gid = fc->group_id;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	/* setting ->i_op to NULL is not allowed */
+	if (iop)
+		inode->i_op = iop;
+	inode->i_fop = fop;
+	inode->i_nlink = nlink;
+	inode->u.generic_ip = fc;
+	d_add(dentry, inode);
+	return dentry;
+}
+
+/*
+ * Add a connection to the control filesystem (if it exists).  Caller
+ * must host fuse_mutex
+ */
+int fuse_ctl_add_conn(struct fuse_conn *fc)
+{
+	struct dentry *parent;
+	char name[32];
+
+	if (!fuse_control_sb)
+		return 0;
+
+	parent = fuse_control_sb->s_root;
+	parent->d_inode->i_nlink++;
+	sprintf(name, "%llu", (unsigned long long) fc->id);
+	parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
+				     &simple_dir_inode_operations,
+				     &simple_dir_operations);
+	if (!parent)
+		goto err;
+
+	if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1,
+				NULL, &fuse_ctl_waiting_ops) ||
+	    !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1,
+				 NULL, &fuse_ctl_abort_ops))
+		goto err;
+
+	return 0;
+
+ err:
+	fuse_ctl_remove_conn(fc);
+	return -ENOMEM;
+}
+
+/*
+ * Remove a connection from the control filesystem (if it exists).
+ * Caller must host fuse_mutex
+ */
+void fuse_ctl_remove_conn(struct fuse_conn *fc)
+{
+	int i;
+
+	if (!fuse_control_sb)
+		return;
+
+	for (i = fc->ctl_ndents - 1; i >= 0; i--) {
+		struct dentry *dentry = fc->ctl_dentry[i];
+		dentry->d_inode->u.generic_ip = NULL;
+		d_drop(dentry);
+		dput(dentry);
+	}
+	fuse_control_sb->s_root->d_inode->i_nlink--;
+}
+
+static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct tree_descr empty_descr = {""};
+	struct fuse_conn *fc;
+	int err;
+
+	err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr);
+	if (err)
+		return err;
+
+	mutex_lock(&fuse_mutex);
+	BUG_ON(fuse_control_sb);
+	fuse_control_sb = sb;
+	list_for_each_entry(fc, &fuse_conn_list, entry) {
+		err = fuse_ctl_add_conn(fc);
+		if (err) {
+			fuse_control_sb = NULL;
+			mutex_unlock(&fuse_mutex);
+			return err;
+		}
+	}
+	mutex_unlock(&fuse_mutex);
+
+	return 0;
+}
+
+static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags,
+			const char *dev_name, void *raw_data,
+			struct vfsmount *mnt)
+{
+	return get_sb_single(fs_type, flags, raw_data,
+				fuse_ctl_fill_super, mnt);
+}
+
+static void fuse_ctl_kill_sb(struct super_block *sb)
+{
+	mutex_lock(&fuse_mutex);
+	fuse_control_sb = NULL;
+	mutex_unlock(&fuse_mutex);
+
+	kill_litter_super(sb);
+}
+
+static struct file_system_type fuse_ctl_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "fusectl",
+	.get_sb		= fuse_ctl_get_sb,
+	.kill_sb	= fuse_ctl_kill_sb,
+};
+
+int __init fuse_ctl_init(void)
+{
+	return register_filesystem(&fuse_ctl_fs_type);
+}
+
+void fuse_ctl_cleanup(void)
+{
+	unregister_filesystem(&fuse_ctl_fs_type);
+}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 104a62d..1e2006c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -34,6 +34,7 @@
 {
 	memset(req, 0, sizeof(*req));
 	INIT_LIST_HEAD(&req->list);
+	INIT_LIST_HEAD(&req->intr_entry);
 	init_waitqueue_head(&req->waitq);
 	atomic_set(&req->count, 1);
 }
@@ -64,18 +65,6 @@
 	sigprocmask(SIG_SETMASK, oldset, NULL);
 }
 
-/*
- * Reset request, so that it can be reused
- *
- * The caller must be _very_ careful to make sure, that it is holding
- * the only reference to req
- */
-void fuse_reset_request(struct fuse_req *req)
-{
-	BUG_ON(atomic_read(&req->count) != 1);
-	fuse_request_init(req);
-}
-
 static void __fuse_get_request(struct fuse_req *req)
 {
 	atomic_inc(&req->count);
@@ -88,6 +77,13 @@
 	atomic_dec(&req->count);
 }
 
+static void fuse_req_init_context(struct fuse_req *req)
+{
+	req->in.h.uid = current->fsuid;
+	req->in.h.gid = current->fsgid;
+	req->in.h.pid = current->pid;
+}
+
 struct fuse_req *fuse_get_req(struct fuse_conn *fc)
 {
 	struct fuse_req *req;
@@ -103,14 +99,16 @@
 	if (intr)
 		goto out;
 
+	err = -ENOTCONN;
+	if (!fc->connected)
+		goto out;
+
 	req = fuse_request_alloc();
 	err = -ENOMEM;
 	if (!req)
 		goto out;
 
-	req->in.h.uid = current->fsuid;
-	req->in.h.gid = current->fsgid;
-	req->in.h.pid = current->pid;
+	fuse_req_init_context(req);
 	req->waiting = 1;
 	return req;
 
@@ -119,142 +117,183 @@
 	return ERR_PTR(err);
 }
 
+/*
+ * Return request in fuse_file->reserved_req.  However that may
+ * currently be in use.  If that is the case, wait for it to become
+ * available.
+ */
+static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
+					 struct file *file)
+{
+	struct fuse_req *req = NULL;
+	struct fuse_file *ff = file->private_data;
+
+	do {
+		wait_event(fc->blocked_waitq, ff->reserved_req);
+		spin_lock(&fc->lock);
+		if (ff->reserved_req) {
+			req = ff->reserved_req;
+			ff->reserved_req = NULL;
+			get_file(file);
+			req->stolen_file = file;
+		}
+		spin_unlock(&fc->lock);
+	} while (!req);
+
+	return req;
+}
+
+/*
+ * Put stolen request back into fuse_file->reserved_req
+ */
+static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
+{
+	struct file *file = req->stolen_file;
+	struct fuse_file *ff = file->private_data;
+
+	spin_lock(&fc->lock);
+	fuse_request_init(req);
+	BUG_ON(ff->reserved_req);
+	ff->reserved_req = req;
+	wake_up(&fc->blocked_waitq);
+	spin_unlock(&fc->lock);
+	fput(file);
+}
+
+/*
+ * Gets a requests for a file operation, always succeeds
+ *
+ * This is used for sending the FLUSH request, which must get to
+ * userspace, due to POSIX locks which may need to be unlocked.
+ *
+ * If allocation fails due to OOM, use the reserved request in
+ * fuse_file.
+ *
+ * This is very unlikely to deadlock accidentally, since the
+ * filesystem should not have it's own file open.  If deadlock is
+ * intentional, it can still be broken by "aborting" the filesystem.
+ */
+struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file)
+{
+	struct fuse_req *req;
+
+	atomic_inc(&fc->num_waiting);
+	wait_event(fc->blocked_waitq, !fc->blocked);
+	req = fuse_request_alloc();
+	if (!req)
+		req = get_reserved_req(fc, file);
+
+	fuse_req_init_context(req);
+	req->waiting = 1;
+	return req;
+}
+
 void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
 {
 	if (atomic_dec_and_test(&req->count)) {
 		if (req->waiting)
 			atomic_dec(&fc->num_waiting);
-		fuse_request_free(req);
-	}
-}
 
-/*
- * Called with sbput_sem held for read (request_end) or write
- * (fuse_put_super).  By the time fuse_put_super() is finished, all
- * inodes belonging to background requests must be released, so the
- * iputs have to be done within the locked region.
- */
-void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
-{
-	iput(req->inode);
-	iput(req->inode2);
-	spin_lock(&fc->lock);
-	list_del(&req->bg_entry);
-	if (fc->num_background == FUSE_MAX_BACKGROUND) {
-		fc->blocked = 0;
-		wake_up_all(&fc->blocked_waitq);
+		if (req->stolen_file)
+			put_reserved_req(fc, req);
+		else
+			fuse_request_free(req);
 	}
-	fc->num_background--;
-	spin_unlock(&fc->lock);
 }
 
 /*
  * This function is called when a request is finished.  Either a reply
- * has arrived or it was interrupted (and not yet sent) or some error
+ * has arrived or it was aborted (and not yet sent) or some error
  * occurred during communication with userspace, or the device file
- * was closed.  In case of a background request the reference to the
- * stored objects are released.  The requester thread is woken up (if
- * still waiting), the 'end' callback is called if given, else the
- * reference to the request is released
- *
- * Releasing extra reference for foreground requests must be done
- * within the same locked region as setting state to finished.  This
- * is because fuse_reset_request() may be called after request is
- * finished and it must be the sole possessor.  If request is
- * interrupted and put in the background, it will return with an error
- * and hence never be reset and reused.
+ * was closed.  The requester thread is woken up (if still waiting),
+ * the 'end' callback is called if given, else the reference to the
+ * request is released
  *
  * Called with fc->lock, unlocks it
  */
 static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 {
+	void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+	req->end = NULL;
 	list_del(&req->list);
+	list_del(&req->intr_entry);
 	req->state = FUSE_REQ_FINISHED;
-	if (!req->background) {
-		spin_unlock(&fc->lock);
-		wake_up(&req->waitq);
-		fuse_put_request(fc, req);
-	} else {
-		void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
-		req->end = NULL;
-		spin_unlock(&fc->lock);
-		down_read(&fc->sbput_sem);
-		if (fc->mounted)
-			fuse_release_background(fc, req);
-		up_read(&fc->sbput_sem);
-
-		/* fput must go outside sbput_sem, otherwise it can deadlock */
-		if (req->file)
-			fput(req->file);
-
-		if (end)
-			end(fc, req);
-		else
-			fuse_put_request(fc, req);
+	if (req->background) {
+		if (fc->num_background == FUSE_MAX_BACKGROUND) {
+			fc->blocked = 0;
+			wake_up_all(&fc->blocked_waitq);
+		}
+		fc->num_background--;
 	}
+	spin_unlock(&fc->lock);
+	dput(req->dentry);
+	mntput(req->vfsmount);
+	if (req->file)
+		fput(req->file);
+	wake_up(&req->waitq);
+	if (end)
+		end(fc, req);
+	else
+		fuse_put_request(fc, req);
 }
 
-/*
- * Unfortunately request interruption not just solves the deadlock
- * problem, it causes problems too.  These stem from the fact, that an
- * interrupted request is continued to be processed in userspace,
- * while all the locks and object references (inode and file) held
- * during the operation are released.
- *
- * To release the locks is exactly why there's a need to interrupt the
- * request, so there's not a lot that can be done about this, except
- * introduce additional locking in userspace.
- *
- * More important is to keep inode and file references until userspace
- * has replied, otherwise FORGET and RELEASE could be sent while the
- * inode/file is still used by the filesystem.
- *
- * For this reason the concept of "background" request is introduced.
- * An interrupted request is backgrounded if it has been already sent
- * to userspace.  Backgrounding involves getting an extra reference to
- * inode(s) or file used in the request, and adding the request to
- * fc->background list.  When a reply is received for a background
- * request, the object references are released, and the request is
- * removed from the list.  If the filesystem is unmounted while there
- * are still background requests, the list is walked and references
- * are released as if a reply was received.
- *
- * There's one more use for a background request.  The RELEASE message is
- * always sent as background, since it doesn't return an error or
- * data.
- */
-static void background_request(struct fuse_conn *fc, struct fuse_req *req)
+static void wait_answer_interruptible(struct fuse_conn *fc,
+				      struct fuse_req *req)
 {
-	req->background = 1;
-	list_add(&req->bg_entry, &fc->background);
-	fc->num_background++;
-	if (fc->num_background == FUSE_MAX_BACKGROUND)
-		fc->blocked = 1;
-	if (req->inode)
-		req->inode = igrab(req->inode);
-	if (req->inode2)
-		req->inode2 = igrab(req->inode2);
-	if (req->file)
-		get_file(req->file);
+	if (signal_pending(current))
+		return;
+
+	spin_unlock(&fc->lock);
+	wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
+	spin_lock(&fc->lock);
+}
+
+static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req)
+{
+	list_add_tail(&req->intr_entry, &fc->interrupts);
+	wake_up(&fc->waitq);
+	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 }
 
 /* Called with fc->lock held.  Releases, and then reacquires it. */
 static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
 {
-	sigset_t oldset;
+	if (!fc->no_interrupt) {
+		/* Any signal may interrupt this */
+		wait_answer_interruptible(fc, req);
 
-	spin_unlock(&fc->lock);
-	block_sigs(&oldset);
-	wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
-	restore_sigs(&oldset);
-	spin_lock(&fc->lock);
-	if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
-		return;
+		if (req->aborted)
+			goto aborted;
+		if (req->state == FUSE_REQ_FINISHED)
+			return;
 
-	if (!req->interrupted) {
-		req->out.h.error = -EINTR;
 		req->interrupted = 1;
+		if (req->state == FUSE_REQ_SENT)
+			queue_interrupt(fc, req);
 	}
+
+	if (req->force) {
+		spin_unlock(&fc->lock);
+		wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+		spin_lock(&fc->lock);
+	} else {
+		sigset_t oldset;
+
+		/* Only fatal signals may interrupt this */
+		block_sigs(&oldset);
+		wait_answer_interruptible(fc, req);
+		restore_sigs(&oldset);
+	}
+
+	if (req->aborted)
+		goto aborted;
+	if (req->state == FUSE_REQ_FINISHED)
+ 		return;
+
+	req->out.h.error = -EINTR;
+	req->aborted = 1;
+
+ aborted:
 	if (req->locked) {
 		/* This is uninterruptible sleep, because data is
 		   being copied to/from the buffers of req.  During
@@ -268,8 +307,11 @@
 	if (req->state == FUSE_REQ_PENDING) {
 		list_del(&req->list);
 		__fuse_put_request(req);
-	} else if (req->state == FUSE_REQ_SENT)
-		background_request(fc, req);
+	} else if (req->state == FUSE_REQ_SENT) {
+		spin_unlock(&fc->lock);
+		wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+		spin_lock(&fc->lock);
+	}
 }
 
 static unsigned len_args(unsigned numargs, struct fuse_arg *args)
@@ -283,13 +325,19 @@
 	return nbytes;
 }
 
+static u64 fuse_get_unique(struct fuse_conn *fc)
+ {
+ 	fc->reqctr++;
+ 	/* zero is special */
+ 	if (fc->reqctr == 0)
+ 		fc->reqctr = 1;
+
+	return fc->reqctr;
+}
+
 static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
 {
-	fc->reqctr++;
-	/* zero is special */
-	if (fc->reqctr == 0)
-		fc->reqctr = 1;
-	req->in.h.unique = fc->reqctr;
+	req->in.h.unique = fuse_get_unique(fc);
 	req->in.h.len = sizeof(struct fuse_in_header) +
 		len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
 	list_add_tail(&req->list, &fc->pending);
@@ -302,9 +350,6 @@
 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 }
 
-/*
- * This can only be interrupted by a SIGKILL
- */
 void request_send(struct fuse_conn *fc, struct fuse_req *req)
 {
 	req->isreply = 1;
@@ -327,8 +372,12 @@
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
 	spin_lock(&fc->lock);
-	background_request(fc, req);
 	if (fc->connected) {
+		req->background = 1;
+		fc->num_background++;
+		if (fc->num_background == FUSE_MAX_BACKGROUND)
+			fc->blocked = 1;
+
 		queue_request(fc, req);
 		spin_unlock(&fc->lock);
 	} else {
@@ -352,14 +401,14 @@
 /*
  * Lock the request.  Up to the next unlock_request() there mustn't be
  * anything that could cause a page-fault.  If the request was already
- * interrupted bail out.
+ * aborted bail out.
  */
 static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
 {
 	int err = 0;
 	if (req) {
 		spin_lock(&fc->lock);
-		if (req->interrupted)
+		if (req->aborted)
 			err = -ENOENT;
 		else
 			req->locked = 1;
@@ -369,7 +418,7 @@
 }
 
 /*
- * Unlock request.  If it was interrupted during being locked, the
+ * Unlock request.  If it was aborted during being locked, the
  * requester thread is currently waiting for it to be unlocked, so
  * wake it up.
  */
@@ -378,7 +427,7 @@
 	if (req) {
 		spin_lock(&fc->lock);
 		req->locked = 0;
-		if (req->interrupted)
+		if (req->aborted)
 			wake_up(&req->waitq);
 		spin_unlock(&fc->lock);
 	}
@@ -557,13 +606,18 @@
 	return err;
 }
 
+static int request_pending(struct fuse_conn *fc)
+{
+	return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);
+}
+
 /* Wait until a request is available on the pending list */
 static void request_wait(struct fuse_conn *fc)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
 	add_wait_queue_exclusive(&fc->waitq, &wait);
-	while (fc->connected && list_empty(&fc->pending)) {
+	while (fc->connected && !request_pending(fc)) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (signal_pending(current))
 			break;
@@ -577,11 +631,50 @@
 }
 
 /*
+ * Transfer an interrupt request to userspace
+ *
+ * Unlike other requests this is assembled on demand, without a need
+ * to allocate a separate fuse_req structure.
+ *
+ * Called with fc->lock held, releases it
+ */
+static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
+			       const struct iovec *iov, unsigned long nr_segs)
+{
+	struct fuse_copy_state cs;
+	struct fuse_in_header ih;
+	struct fuse_interrupt_in arg;
+	unsigned reqsize = sizeof(ih) + sizeof(arg);
+	int err;
+
+	list_del_init(&req->intr_entry);
+	req->intr_unique = fuse_get_unique(fc);
+	memset(&ih, 0, sizeof(ih));
+	memset(&arg, 0, sizeof(arg));
+	ih.len = reqsize;
+	ih.opcode = FUSE_INTERRUPT;
+	ih.unique = req->intr_unique;
+	arg.unique = req->in.h.unique;
+
+	spin_unlock(&fc->lock);
+	if (iov_length(iov, nr_segs) < reqsize)
+		return -EINVAL;
+
+	fuse_copy_init(&cs, fc, 1, NULL, iov, nr_segs);
+	err = fuse_copy_one(&cs, &ih, sizeof(ih));
+	if (!err)
+		err = fuse_copy_one(&cs, &arg, sizeof(arg));
+	fuse_copy_finish(&cs);
+
+	return err ? err : reqsize;
+}
+
+/*
  * Read a single request into the userspace filesystem's buffer.  This
  * function waits until a request is available, then removes it from
  * the pending list and copies request data to userspace buffer.  If
- * no reply is needed (FORGET) or request has been interrupted or
- * there was an error during the copying then it's finished by calling
+ * no reply is needed (FORGET) or request has been aborted or there
+ * was an error during the copying then it's finished by calling
  * request_end().  Otherwise add it to the processing list, and set
  * the 'sent' flag.
  */
@@ -601,7 +694,7 @@
 	spin_lock(&fc->lock);
 	err = -EAGAIN;
 	if ((file->f_flags & O_NONBLOCK) && fc->connected &&
-	    list_empty(&fc->pending))
+	    !request_pending(fc))
 		goto err_unlock;
 
 	request_wait(fc);
@@ -609,9 +702,15 @@
 	if (!fc->connected)
 		goto err_unlock;
 	err = -ERESTARTSYS;
-	if (list_empty(&fc->pending))
+	if (!request_pending(fc))
 		goto err_unlock;
 
+	if (!list_empty(&fc->interrupts)) {
+		req = list_entry(fc->interrupts.next, struct fuse_req,
+				 intr_entry);
+		return fuse_read_interrupt(fc, req, iov, nr_segs);
+	}
+
 	req = list_entry(fc->pending.next, struct fuse_req, list);
 	req->state = FUSE_REQ_READING;
 	list_move(&req->list, &fc->io);
@@ -636,10 +735,10 @@
 	fuse_copy_finish(&cs);
 	spin_lock(&fc->lock);
 	req->locked = 0;
-	if (!err && req->interrupted)
+	if (!err && req->aborted)
 		err = -ENOENT;
 	if (err) {
-		if (!req->interrupted)
+		if (!req->aborted)
 			req->out.h.error = -EIO;
 		request_end(fc, req);
 		return err;
@@ -649,6 +748,8 @@
 	else {
 		req->state = FUSE_REQ_SENT;
 		list_move_tail(&req->list, &fc->processing);
+		if (req->interrupted)
+			queue_interrupt(fc, req);
 		spin_unlock(&fc->lock);
 	}
 	return reqsize;
@@ -675,7 +776,7 @@
 	list_for_each(entry, &fc->processing) {
 		struct fuse_req *req;
 		req = list_entry(entry, struct fuse_req, list);
-		if (req->in.h.unique == unique)
+		if (req->in.h.unique == unique || req->intr_unique == unique)
 			return req;
 	}
 	return NULL;
@@ -741,17 +842,33 @@
 		goto err_unlock;
 
 	req = request_find(fc, oh.unique);
-	err = -EINVAL;
 	if (!req)
 		goto err_unlock;
 
-	if (req->interrupted) {
+	if (req->aborted) {
 		spin_unlock(&fc->lock);
 		fuse_copy_finish(&cs);
 		spin_lock(&fc->lock);
 		request_end(fc, req);
 		return -ENOENT;
 	}
+	/* Is it an interrupt reply? */
+	if (req->intr_unique == oh.unique) {
+		err = -EINVAL;
+		if (nbytes != sizeof(struct fuse_out_header))
+			goto err_unlock;
+
+		if (oh.error == -ENOSYS)
+			fc->no_interrupt = 1;
+		else if (oh.error == -EAGAIN)
+			queue_interrupt(fc, req);
+
+		spin_unlock(&fc->lock);
+		fuse_copy_finish(&cs);
+		return nbytes;
+	}
+
+	req->state = FUSE_REQ_WRITING;
 	list_move(&req->list, &fc->io);
 	req->out.h = oh;
 	req->locked = 1;
@@ -764,9 +881,9 @@
 	spin_lock(&fc->lock);
 	req->locked = 0;
 	if (!err) {
-		if (req->interrupted)
+		if (req->aborted)
 			err = -ENOENT;
-	} else if (!req->interrupted)
+	} else if (!req->aborted)
 		req->out.h.error = -EIO;
 	request_end(fc, req);
 
@@ -800,7 +917,7 @@
 	spin_lock(&fc->lock);
 	if (!fc->connected)
 		mask = POLLERR;
-	else if (!list_empty(&fc->pending))
+	else if (request_pending(fc))
 		mask |= POLLIN | POLLRDNORM;
 	spin_unlock(&fc->lock);
 
@@ -826,7 +943,7 @@
 /*
  * Abort requests under I/O
  *
- * The requests are set to interrupted and finished, and the request
+ * The requests are set to aborted and finished, and the request
  * waiter is woken up.  This will make request_wait_answer() wait
  * until the request is unlocked and then return.
  *
@@ -841,7 +958,7 @@
 			list_entry(fc->io.next, struct fuse_req, list);
 		void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
 
-		req->interrupted = 1;
+		req->aborted = 1;
 		req->out.h.error = -ECONNABORTED;
 		req->state = FUSE_REQ_FINISHED;
 		list_del_init(&req->list);
@@ -874,19 +991,20 @@
  * onto the pending list is prevented by req->connected being false.
  *
  * Progression of requests under I/O to the processing list is
- * prevented by the req->interrupted flag being true for these
- * requests.  For this reason requests on the io list must be aborted
- * first.
+ * prevented by the req->aborted flag being true for these requests.
+ * For this reason requests on the io list must be aborted first.
  */
 void fuse_abort_conn(struct fuse_conn *fc)
 {
 	spin_lock(&fc->lock);
 	if (fc->connected) {
 		fc->connected = 0;
+		fc->blocked = 0;
 		end_io_requests(fc);
 		end_requests(fc, &fc->pending);
 		end_requests(fc, &fc->processing);
 		wake_up_all(&fc->waitq);
+		wake_up_all(&fc->blocked_waitq);
 		kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 	}
 	spin_unlock(&fc->lock);
@@ -902,7 +1020,7 @@
 		end_requests(fc, &fc->processing);
 		spin_unlock(&fc->lock);
 		fasync_helper(-1, file, 0, &fc->fasync);
-		kobject_put(&fc->kobj);
+		fuse_conn_put(fc);
 	}
 
 	return 0;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 8d7546e..72a74cd 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1,6 +1,6 @@
 /*
   FUSE: Filesystem in Userspace
-  Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
+  Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
 
   This program can be distributed under the terms of the GNU GPL.
   See the file COPYING.
@@ -79,7 +79,6 @@
 {
 	req->in.h.opcode = FUSE_LOOKUP;
 	req->in.h.nodeid = get_node_id(dir);
-	req->inode = dir;
 	req->in.numargs = 1;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -225,6 +224,20 @@
 }
 
 /*
+ * Synchronous release for the case when something goes wrong in CREATE_OPEN
+ */
+static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
+			      u64 nodeid, int flags)
+{
+	struct fuse_req *req;
+
+	req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
+	req->force = 1;
+	request_send(fc, req);
+	fuse_put_request(fc, req);
+}
+
+/*
  * Atomic create+open operation
  *
  * If the filesystem doesn't support this, then fall back to separate
@@ -237,6 +250,7 @@
 	struct inode *inode;
 	struct fuse_conn *fc = get_fuse_conn(dir);
 	struct fuse_req *req;
+	struct fuse_req *forget_req;
 	struct fuse_open_in inarg;
 	struct fuse_open_out outopen;
 	struct fuse_entry_out outentry;
@@ -247,9 +261,14 @@
 	if (fc->no_create)
 		return -ENOSYS;
 
+	forget_req = fuse_get_req(fc);
+	if (IS_ERR(forget_req))
+		return PTR_ERR(forget_req);
+
 	req = fuse_get_req(fc);
+	err = PTR_ERR(req);
 	if (IS_ERR(req))
-		return PTR_ERR(req);
+		goto out_put_forget_req;
 
 	err = -ENOMEM;
 	ff = fuse_file_alloc();
@@ -262,7 +281,6 @@
 	inarg.mode = mode;
 	req->in.h.opcode = FUSE_CREATE;
 	req->in.h.nodeid = get_node_id(dir);
-	req->inode = dir;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -285,25 +303,23 @@
 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
 		goto out_free_ff;
 
+	fuse_put_request(fc, req);
 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
 			  &outentry.attr);
-	err = -ENOMEM;
 	if (!inode) {
 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
 		ff->fh = outopen.fh;
-		/* Special release, with inode = NULL, this will
-		   trigger a 'forget' request when the release is
-		   complete */
-		fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
-		goto out_put_request;
+		fuse_sync_release(fc, ff, outentry.nodeid, flags);
+		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
+		return -ENOMEM;
 	}
-	fuse_put_request(fc, req);
+	fuse_put_request(fc, forget_req);
 	d_instantiate(entry, inode);
 	fuse_change_timeout(entry, &outentry);
 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
 	if (IS_ERR(file)) {
 		ff->fh = outopen.fh;
-		fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
+		fuse_sync_release(fc, ff, outentry.nodeid, flags);
 		return PTR_ERR(file);
 	}
 	fuse_finish_open(inode, file, ff, &outopen);
@@ -313,6 +329,8 @@
 	fuse_file_free(ff);
  out_put_request:
 	fuse_put_request(fc, req);
+ out_put_forget_req:
+	fuse_put_request(fc, forget_req);
 	return err;
 }
 
@@ -328,7 +346,6 @@
 	int err;
 
 	req->in.h.nodeid = get_node_id(dir);
-	req->inode = dir;
 	req->out.numargs = 1;
 	req->out.args[0].size = sizeof(outarg);
 	req->out.args[0].value = &outarg;
@@ -448,7 +465,6 @@
 
 	req->in.h.opcode = FUSE_UNLINK;
 	req->in.h.nodeid = get_node_id(dir);
-	req->inode = dir;
 	req->in.numargs = 1;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -480,7 +496,6 @@
 
 	req->in.h.opcode = FUSE_RMDIR;
 	req->in.h.nodeid = get_node_id(dir);
-	req->inode = dir;
 	req->in.numargs = 1;
 	req->in.args[0].size = entry->d_name.len + 1;
 	req->in.args[0].value = entry->d_name.name;
@@ -510,8 +525,6 @@
 	inarg.newdir = get_node_id(newdir);
 	req->in.h.opcode = FUSE_RENAME;
 	req->in.h.nodeid = get_node_id(olddir);
-	req->inode = olddir;
-	req->inode2 = newdir;
 	req->in.numargs = 3;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -558,7 +571,6 @@
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.oldnodeid = get_node_id(inode);
 	req->in.h.opcode = FUSE_LINK;
-	req->inode2 = inode;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -587,7 +599,6 @@
 
 	req->in.h.opcode = FUSE_GETATTR;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->out.numargs = 1;
 	req->out.args[0].size = sizeof(arg);
 	req->out.args[0].value = &arg;
@@ -679,7 +690,6 @@
 	inarg.mask = mask;
 	req->in.h.opcode = FUSE_ACCESS;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -820,7 +830,6 @@
 	}
 	req->in.h.opcode = FUSE_READLINK;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->out.argvar = 1;
 	req->out.numargs = 1;
 	req->out.args[0].size = PAGE_SIZE - 1;
@@ -939,7 +948,6 @@
 	iattr_to_fattr(attr, &inarg);
 	req->in.h.opcode = FUSE_SETATTR;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1002,7 +1010,6 @@
 	inarg.flags = flags;
 	req->in.h.opcode = FUSE_SETXATTR;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 3;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1041,7 +1048,6 @@
 	inarg.size = size;
 	req->in.h.opcode = FUSE_GETXATTR;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1091,7 +1097,6 @@
 	inarg.size = size;
 	req->in.h.opcode = FUSE_LISTXATTR;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -1135,7 +1140,6 @@
 
 	req->in.h.opcode = FUSE_REMOVEXATTR;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 1;
 	req->in.args[0].size = strlen(name) + 1;
 	req->in.args[0].value = name;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 087f3b7..28aa81e 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -30,7 +30,6 @@
 	inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 	req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -49,8 +48,8 @@
 	struct fuse_file *ff;
 	ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
 	if (ff) {
-		ff->release_req = fuse_request_alloc();
-		if (!ff->release_req) {
+		ff->reserved_req = fuse_request_alloc();
+		if (!ff->reserved_req) {
 			kfree(ff);
 			ff = NULL;
 		}
@@ -60,7 +59,7 @@
 
 void fuse_file_free(struct fuse_file *ff)
 {
-	fuse_request_free(ff->release_req);
+	fuse_request_free(ff->reserved_req);
 	kfree(ff);
 }
 
@@ -113,37 +112,22 @@
 	return err;
 }
 
-/* Special case for failed iget in CREATE */
-static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
+struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
+				   int opcode)
 {
-	/* If called from end_io_requests(), req has more than one
-	   reference and fuse_reset_request() cannot work */
-	if (fc->connected) {
-		u64 nodeid = req->in.h.nodeid;
-		fuse_reset_request(req);
-		fuse_send_forget(fc, req, nodeid, 1);
-	} else
-		fuse_put_request(fc, req);
-}
-
-void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
-		       u64 nodeid, struct inode *inode, int flags, int isdir)
-{
-	struct fuse_req * req = ff->release_req;
+	struct fuse_req *req = ff->reserved_req;
 	struct fuse_release_in *inarg = &req->misc.release_in;
 
 	inarg->fh = ff->fh;
 	inarg->flags = flags;
-	req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
+	req->in.h.opcode = opcode;
 	req->in.h.nodeid = nodeid;
-	req->inode = inode;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_release_in);
 	req->in.args[0].value = inarg;
-	request_send_background(fc, req);
-	if (!inode)
-		req->end = fuse_release_end;
 	kfree(ff);
+
+	return req;
 }
 
 int fuse_release_common(struct inode *inode, struct file *file, int isdir)
@@ -151,8 +135,15 @@
 	struct fuse_file *ff = file->private_data;
 	if (ff) {
 		struct fuse_conn *fc = get_fuse_conn(inode);
-		u64 nodeid = get_node_id(inode);
-		fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir);
+		struct fuse_req *req;
+
+		req = fuse_release_fill(ff, get_node_id(inode), file->f_flags,
+					isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
+
+		/* Hold vfsmount and dentry until release is finished */
+		req->vfsmount = mntget(file->f_vfsmnt);
+		req->dentry = dget(file->f_dentry);
+		request_send_background(fc, req);
 	}
 
 	/* Return value is ignored by VFS */
@@ -169,6 +160,28 @@
 	return fuse_release_common(inode, file, 0);
 }
 
+/*
+ * Scramble the ID space with XTEA, so that the value of the files_struct
+ * pointer is not exposed to userspace.
+ */
+static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
+{
+	u32 *k = fc->scramble_key;
+	u64 v = (unsigned long) id;
+	u32 v0 = v;
+	u32 v1 = v >> 32;
+	u32 sum = 0;
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
+		sum += 0x9E3779B9;
+		v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]);
+	}
+
+	return (u64) v0 + ((u64) v1 << 32);
+}
+
 static int fuse_flush(struct file *file, fl_owner_t id)
 {
 	struct inode *inode = file->f_dentry->d_inode;
@@ -184,19 +197,16 @@
 	if (fc->no_flush)
 		return 0;
 
-	req = fuse_get_req(fc);
-	if (IS_ERR(req))
-		return PTR_ERR(req);
-
+	req = fuse_get_req_nofail(fc, file);
 	memset(&inarg, 0, sizeof(inarg));
 	inarg.fh = ff->fh;
+	inarg.lock_owner = fuse_lock_owner_id(fc, id);
 	req->in.h.opcode = FUSE_FLUSH;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
-	req->file = file;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
+	req->force = 1;
 	request_send(fc, req);
 	err = req->out.h.error;
 	fuse_put_request(fc, req);
@@ -232,8 +242,6 @@
 	inarg.fsync_flags = datasync ? 1 : 0;
 	req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
-	req->file = file;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(inarg);
 	req->in.args[0].value = &inarg;
@@ -266,8 +274,6 @@
 	inarg->size = count;
 	req->in.h.opcode = opcode;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
-	req->file = file;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_read_in);
 	req->in.args[0].value = inarg;
@@ -342,6 +348,8 @@
 	req->out.page_zeroing = 1;
 	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
 	if (fc->async_read) {
+		get_file(file);
+		req->file = file;
 		req->end = fuse_readpages_end;
 		request_send_background(fc, req);
 	} else {
@@ -420,8 +428,6 @@
 	inarg.size = count;
 	req->in.h.opcode = FUSE_WRITE;
 	req->in.h.nodeid = get_node_id(inode);
-	req->inode = inode;
-	req->file = file;
 	req->in.argpages = 1;
 	req->in.numargs = 2;
 	req->in.args[0].size = sizeof(struct fuse_write_in);
@@ -619,6 +625,126 @@
 	return 0;
 }
 
+static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
+				  struct file_lock *fl)
+{
+	switch (ffl->type) {
+	case F_UNLCK:
+		break;
+
+	case F_RDLCK:
+	case F_WRLCK:
+		if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
+		    ffl->end < ffl->start)
+			return -EIO;
+
+		fl->fl_start = ffl->start;
+		fl->fl_end = ffl->end;
+		fl->fl_pid = ffl->pid;
+		break;
+
+	default:
+		return -EIO;
+	}
+	fl->fl_type = ffl->type;
+	return 0;
+}
+
+static void fuse_lk_fill(struct fuse_req *req, struct file *file,
+			 const struct file_lock *fl, int opcode, pid_t pid)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_file *ff = file->private_data;
+	struct fuse_lk_in *arg = &req->misc.lk_in;
+
+	arg->fh = ff->fh;
+	arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
+	arg->lk.start = fl->fl_start;
+	arg->lk.end = fl->fl_end;
+	arg->lk.type = fl->fl_type;
+	arg->lk.pid = pid;
+	req->in.h.opcode = opcode;
+	req->in.h.nodeid = get_node_id(inode);
+	req->in.numargs = 1;
+	req->in.args[0].size = sizeof(*arg);
+	req->in.args[0].value = arg;
+}
+
+static int fuse_getlk(struct file *file, struct file_lock *fl)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_req *req;
+	struct fuse_lk_out outarg;
+	int err;
+
+	req = fuse_get_req(fc);
+	if (IS_ERR(req))
+		return PTR_ERR(req);
+
+	fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
+	req->out.numargs = 1;
+	req->out.args[0].size = sizeof(outarg);
+	req->out.args[0].value = &outarg;
+	request_send(fc, req);
+	err = req->out.h.error;
+	fuse_put_request(fc, req);
+	if (!err)
+		err = convert_fuse_file_lock(&outarg.lk, fl);
+
+	return err;
+}
+
+static int fuse_setlk(struct file *file, struct file_lock *fl)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_req *req;
+	int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
+	pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
+	int err;
+
+	/* Unlock on close is handled by the flush method */
+	if (fl->fl_flags & FL_CLOSE)
+		return 0;
+
+	req = fuse_get_req(fc);
+	if (IS_ERR(req))
+		return PTR_ERR(req);
+
+	fuse_lk_fill(req, file, fl, opcode, pid);
+	request_send(fc, req);
+	err = req->out.h.error;
+	/* locking is restartable */
+	if (err == -EINTR)
+		err = -ERESTARTSYS;
+	fuse_put_request(fc, req);
+	return err;
+}
+
+static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	int err;
+
+	if (cmd == F_GETLK) {
+		if (fc->no_lock) {
+			if (!posix_test_lock(file, fl, fl))
+				fl->fl_type = F_UNLCK;
+			err = 0;
+		} else
+			err = fuse_getlk(file, fl);
+	} else {
+		if (fc->no_lock)
+			err = posix_lock_file_wait(file, fl);
+		else
+			err = fuse_setlk(file, fl);
+	}
+	return err;
+}
+
 static const struct file_operations fuse_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
@@ -628,6 +754,7 @@
 	.flush		= fuse_flush,
 	.release	= fuse_release,
 	.fsync		= fuse_fsync,
+	.lock		= fuse_file_lock,
 	.sendfile	= generic_file_sendfile,
 };
 
@@ -639,6 +766,7 @@
 	.flush		= fuse_flush,
 	.release	= fuse_release,
 	.fsync		= fuse_fsync,
+	.lock		= fuse_file_lock,
 	/* no mmap and sendfile */
 };
 
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 0474202..0dbf966 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -8,12 +8,13 @@
 
 #include <linux/fuse.h>
 #include <linux/fs.h>
+#include <linux/mount.h>
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/backing-dev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -24,6 +25,9 @@
 /** It could be as large as PATH_MAX, but would that have any uses? */
 #define FUSE_NAME_MAX 1024
 
+/** Number of dentries for each connection in the control filesystem */
+#define FUSE_CTL_NUM_DENTRIES 3
+
 /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
     module will check permissions based on the file mode.  Otherwise no
     permission checking is done in the kernel */
@@ -33,6 +37,11 @@
     doing the mount will be allowed to access the filesystem */
 #define FUSE_ALLOW_OTHER         (1 << 1)
 
+/** List of active connections */
+extern struct list_head fuse_conn_list;
+
+/** Global mutex protecting fuse_conn_list and the control filesystem */
+extern struct mutex fuse_mutex;
 
 /** FUSE inode */
 struct fuse_inode {
@@ -56,7 +65,7 @@
 /** FUSE specific file data */
 struct fuse_file {
 	/** Request reserved for flush and release */
-	struct fuse_req *release_req;
+	struct fuse_req *reserved_req;
 
 	/** File handle used by userspace */
 	u64 fh;
@@ -122,6 +131,7 @@
 	FUSE_REQ_PENDING,
 	FUSE_REQ_READING,
 	FUSE_REQ_SENT,
+	FUSE_REQ_WRITING,
 	FUSE_REQ_FINISHED
 };
 
@@ -135,12 +145,15 @@
 	    fuse_conn */
 	struct list_head list;
 
-	/** Entry on the background list */
-	struct list_head bg_entry;
+	/** Entry on the interrupts list  */
+	struct list_head intr_entry;
 
 	/** refcount */
 	atomic_t count;
 
+	/** Unique ID for the interrupt request */
+	u64 intr_unique;
+
 	/*
 	 * The following bitfields are either set once before the
 	 * request is queued or setting/clearing them is protected by
@@ -150,12 +163,18 @@
 	/** True if the request has reply */
 	unsigned isreply:1;
 
-	/** The request was interrupted */
-	unsigned interrupted:1;
+	/** Force sending of the request even if interrupted */
+	unsigned force:1;
+
+	/** The request was aborted */
+	unsigned aborted:1;
 
 	/** Request is sent in the background */
 	unsigned background:1;
 
+	/** The request has been interrupted */
+	unsigned interrupted:1;
+
 	/** Data is being copied to/from the request */
 	unsigned locked:1;
 
@@ -181,6 +200,7 @@
 		struct fuse_init_in init_in;
 		struct fuse_init_out init_out;
 		struct fuse_read_in read_in;
+		struct fuse_lk_in lk_in;
 	} misc;
 
 	/** page vector */
@@ -192,17 +212,20 @@
 	/** offset of data on first page */
 	unsigned page_offset;
 
-	/** Inode used in the request */
-	struct inode *inode;
-
-	/** Second inode used in the request (or NULL) */
-	struct inode *inode2;
-
 	/** File used in the request (or NULL) */
 	struct file *file;
 
+	/** vfsmount used in release */
+	struct vfsmount *vfsmount;
+
+	/** dentry used in release */
+	struct dentry *dentry;
+
 	/** Request completion callback */
 	void (*end)(struct fuse_conn *, struct fuse_req *);
+
+	/** Request is stolen from fuse_file->reserved_req */
+	struct file *stolen_file;
 };
 
 /**
@@ -216,6 +239,9 @@
 	/** Lock protecting accessess to  members of this structure */
 	spinlock_t lock;
 
+	/** Refcount */
+	atomic_t count;
+
 	/** The user id for this mount */
 	uid_t user_id;
 
@@ -243,13 +269,12 @@
 	/** The list of requests under I/O */
 	struct list_head io;
 
-	/** Requests put in the background (RELEASE or any other
-	    interrupted request) */
-	struct list_head background;
-
 	/** Number of requests currently in the background */
 	unsigned num_background;
 
+	/** Pending interrupts */
+	struct list_head interrupts;
+
 	/** Flag indicating if connection is blocked.  This will be
 	    the case before the INIT reply is received, and if there
 	    are too many outstading backgrounds requests */
@@ -258,15 +283,9 @@
 	/** waitq for blocked connection */
 	wait_queue_head_t blocked_waitq;
 
-	/** RW semaphore for exclusion with fuse_put_super() */
-	struct rw_semaphore sbput_sem;
-
 	/** The next unique request id */
 	u64 reqctr;
 
-	/** Mount is active */
-	unsigned mounted;
-
 	/** Connection established, cleared on umount, connection
 	    abort and device release */
 	unsigned connected;
@@ -305,12 +324,18 @@
 	/** Is removexattr not implemented by fs? */
 	unsigned no_removexattr : 1;
 
+	/** Are file locking primitives not implemented by fs? */
+	unsigned no_lock : 1;
+
 	/** Is access not implemented by fs? */
 	unsigned no_access : 1;
 
 	/** Is create not implemented by fs? */
 	unsigned no_create : 1;
 
+	/** Is interrupt not implemented by fs? */
+	unsigned no_interrupt : 1;
+
 	/** The number of requests waiting for completion */
 	atomic_t num_waiting;
 
@@ -320,11 +345,23 @@
 	/** Backing dev info */
 	struct backing_dev_info bdi;
 
-	/** kobject */
-	struct kobject kobj;
+	/** Entry on the fuse_conn_list */
+	struct list_head entry;
+
+	/** Unique ID */
+	u64 id;
+
+	/** Dentries in the control filesystem */
+	struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES];
+
+	/** number of dentries used in the above array */
+	int ctl_ndents;
 
 	/** O_ASYNC requests */
 	struct fasync_struct *fasync;
+
+	/** Key for lock owner ID scrambling */
+	u32 scramble_key[4];
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -337,11 +374,6 @@
 	return get_fuse_conn_super(inode->i_sb);
 }
 
-static inline struct fuse_conn *get_fuse_conn_kobj(struct kobject *obj)
-{
-	return container_of(obj, struct fuse_conn, kobj);
-}
-
 static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
 {
 	return container_of(inode, struct fuse_inode, inode);
@@ -383,12 +415,9 @@
 void fuse_finish_open(struct inode *inode, struct file *file,
 		      struct fuse_file *ff, struct fuse_open_out *outarg);
 
-/**
- * Send a RELEASE request
- */
-void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
-		       u64 nodeid, struct inode *inode, int flags, int isdir);
-
+/** */
+struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
+				   int opcode);
 /**
  * Send RELEASE or RELEASEDIR request
  */
@@ -435,6 +464,9 @@
  */
 void fuse_dev_cleanup(void);
 
+int fuse_ctl_init(void);
+void fuse_ctl_cleanup(void);
+
 /**
  * Allocate a request
  */
@@ -446,16 +478,16 @@
 void fuse_request_free(struct fuse_req *req);
 
 /**
- * Reinitialize a request, the preallocated flag is left unmodified
- */
-void fuse_reset_request(struct fuse_req *req);
-
-/**
- * Reserve a preallocated request
+ * Get a request, may fail with -ENOMEM
  */
 struct fuse_req *fuse_get_req(struct fuse_conn *fc);
 
 /**
+ * Gets a requests for a file operation, always succeeds
+ */
+struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file);
+
+/**
  * Decrement reference count of a request.  If count goes to zero free
  * the request.
  */
@@ -476,11 +508,6 @@
  */
 void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
 
-/**
- * Release inodes and file associated with background request
- */
-void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);
-
 /* Abort all requests */
 void fuse_abort_conn(struct fuse_conn *fc);
 
@@ -493,3 +520,23 @@
  * Invalidate inode attributes
  */
 void fuse_invalidate_attr(struct inode *inode);
+
+/**
+ * Acquire reference to fuse_conn
+ */
+struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
+
+/**
+ * Release reference to fuse_conn
+ */
+void fuse_conn_put(struct fuse_conn *fc);
+
+/**
+ * Add connection to control filesystem
+ */
+int fuse_ctl_add_conn(struct fuse_conn *fc);
+
+/**
+ * Remove connection from control filesystem
+ */
+void fuse_ctl_remove_conn(struct fuse_conn *fc);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index a13c0f5..dcaaabd 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -11,25 +11,20 @@
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/file.h>
-#include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/parser.h>
 #include <linux/statfs.h>
+#include <linux/random.h>
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
 MODULE_LICENSE("GPL");
 
 static kmem_cache_t *fuse_inode_cachep;
-static struct subsystem connections_subsys;
-
-struct fuse_conn_attr {
-	struct attribute attr;
-	ssize_t (*show)(struct fuse_conn *, char *);
-	ssize_t (*store)(struct fuse_conn *, const char *, size_t);
-};
+struct list_head fuse_conn_list;
+DEFINE_MUTEX(fuse_mutex);
 
 #define FUSE_SUPER_MAGIC 0x65735546
 
@@ -104,6 +99,14 @@
 	}
 }
 
+static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	if (*flags & MS_MANDLOCK)
+		return -EINVAL;
+
+	return 0;
+}
+
 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
 {
 	if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
@@ -195,31 +198,29 @@
 	return inode;
 }
 
-static void fuse_umount_begin(struct super_block *sb)
+static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
 {
-	fuse_abort_conn(get_fuse_conn_super(sb));
+	if (flags & MNT_FORCE)
+		fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
 }
 
 static void fuse_put_super(struct super_block *sb)
 {
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
-	down_write(&fc->sbput_sem);
-	while (!list_empty(&fc->background))
-		fuse_release_background(fc,
-					list_entry(fc->background.next,
-						   struct fuse_req, bg_entry));
-
 	spin_lock(&fc->lock);
-	fc->mounted = 0;
 	fc->connected = 0;
+	fc->blocked = 0;
 	spin_unlock(&fc->lock);
-	up_write(&fc->sbput_sem);
 	/* Flush all readers on this fs */
 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 	wake_up_all(&fc->waitq);
-	kobject_del(&fc->kobj);
-	kobject_put(&fc->kobj);
+	wake_up_all(&fc->blocked_waitq);
+	mutex_lock(&fuse_mutex);
+	list_del(&fc->entry);
+	fuse_ctl_remove_conn(fc);
+	mutex_unlock(&fuse_mutex);
+	fuse_conn_put(fc);
 }
 
 static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
@@ -369,11 +370,6 @@
 	return 0;
 }
 
-static void fuse_conn_release(struct kobject *kobj)
-{
-	kfree(get_fuse_conn_kobj(kobj));
-}
-
 static struct fuse_conn *new_conn(void)
 {
 	struct fuse_conn *fc;
@@ -381,24 +377,35 @@
 	fc = kzalloc(sizeof(*fc), GFP_KERNEL);
 	if (fc) {
 		spin_lock_init(&fc->lock);
+		atomic_set(&fc->count, 1);
 		init_waitqueue_head(&fc->waitq);
 		init_waitqueue_head(&fc->blocked_waitq);
 		INIT_LIST_HEAD(&fc->pending);
 		INIT_LIST_HEAD(&fc->processing);
 		INIT_LIST_HEAD(&fc->io);
-		INIT_LIST_HEAD(&fc->background);
-		init_rwsem(&fc->sbput_sem);
-		kobj_set_kset_s(fc, connections_subsys);
-		kobject_init(&fc->kobj);
+		INIT_LIST_HEAD(&fc->interrupts);
 		atomic_set(&fc->num_waiting, 0);
 		fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 		fc->bdi.unplug_io_fn = default_unplug_io_fn;
 		fc->reqctr = 0;
 		fc->blocked = 1;
+		get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
 	}
 	return fc;
 }
 
+void fuse_conn_put(struct fuse_conn *fc)
+{
+	if (atomic_dec_and_test(&fc->count))
+		kfree(fc);
+}
+
+struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
+{
+	atomic_inc(&fc->count);
+	return fc;
+}
+
 static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
 {
 	struct fuse_attr attr;
@@ -414,6 +421,7 @@
 	.destroy_inode  = fuse_destroy_inode,
 	.read_inode	= fuse_read_inode,
 	.clear_inode	= fuse_clear_inode,
+	.remount_fs	= fuse_remount_fs,
 	.put_super	= fuse_put_super,
 	.umount_begin	= fuse_umount_begin,
 	.statfs		= fuse_statfs,
@@ -433,8 +441,12 @@
 			ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
 			if (arg->flags & FUSE_ASYNC_READ)
 				fc->async_read = 1;
-		} else
+			if (!(arg->flags & FUSE_POSIX_LOCKS))
+				fc->no_lock = 1;
+		} else {
 			ra_pages = fc->max_read / PAGE_CACHE_SIZE;
+			fc->no_lock = 1;
+		}
 
 		fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
 		fc->minor = arg->minor;
@@ -452,7 +464,7 @@
 	arg->major = FUSE_KERNEL_VERSION;
 	arg->minor = FUSE_KERNEL_MINOR_VERSION;
 	arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
-	arg->flags |= FUSE_ASYNC_READ;
+	arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
 	req->in.h.opcode = FUSE_INIT;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(*arg);
@@ -468,10 +480,9 @@
 	request_send_background(fc, req);
 }
 
-static unsigned long long conn_id(void)
+static u64 conn_id(void)
 {
-	/* BKL is held for ->get_sb() */
-	static unsigned long long ctr = 1;
+	static u64 ctr = 1;
 	return ctr++;
 }
 
@@ -485,6 +496,9 @@
 	struct fuse_req *init_req;
 	int err;
 
+	if (sb->s_flags & MS_MANDLOCK)
+		return -EINVAL;
+
 	if (!parse_fuse_opt((char *) data, &d))
 		return -EINVAL;
 
@@ -528,25 +542,21 @@
 	if (!init_req)
 		goto err_put_root;
 
-	err = kobject_set_name(&fc->kobj, "%llu", conn_id());
-	if (err)
-		goto err_free_req;
-
-	err = kobject_add(&fc->kobj);
-	if (err)
-		goto err_free_req;
-
-	/* Setting file->private_data can't race with other mount()
-	   instances, since BKL is held for ->get_sb() */
+	mutex_lock(&fuse_mutex);
 	err = -EINVAL;
 	if (file->private_data)
-		goto err_kobject_del;
+		goto err_unlock;
 
+	fc->id = conn_id();
+	err = fuse_ctl_add_conn(fc);
+	if (err)
+		goto err_unlock;
+
+	list_add_tail(&fc->entry, &fuse_conn_list);
 	sb->s_root = root_dentry;
-	fc->mounted = 1;
 	fc->connected = 1;
-	kobject_get(&fc->kobj);
-	file->private_data = fc;
+	file->private_data = fuse_conn_get(fc);
+	mutex_unlock(&fuse_mutex);
 	/*
 	 * atomic_dec_and_test() in fput() provides the necessary
 	 * memory barrier for file->private_data to be visible on all
@@ -558,15 +568,14 @@
 
 	return 0;
 
- err_kobject_del:
-	kobject_del(&fc->kobj);
- err_free_req:
+ err_unlock:
+	mutex_unlock(&fuse_mutex);
 	fuse_request_free(init_req);
  err_put_root:
 	dput(root_dentry);
  err:
 	fput(file);
-	kobject_put(&fc->kobj);
+	fuse_conn_put(fc);
 	return err;
 }
 
@@ -584,68 +593,8 @@
 	.kill_sb	= kill_anon_super,
 };
 
-static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page)
-{
-	return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
-}
-
-static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page,
-				     size_t count)
-{
-	fuse_abort_conn(fc);
-	return count;
-}
-
-static struct fuse_conn_attr fuse_conn_waiting =
-	__ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
-static struct fuse_conn_attr fuse_conn_abort =
-	__ATTR(abort, 0600, NULL, fuse_conn_abort_store);
-
-static struct attribute *fuse_conn_attrs[] = {
-	&fuse_conn_waiting.attr,
-	&fuse_conn_abort.attr,
-	NULL,
-};
-
-static ssize_t fuse_conn_attr_show(struct kobject *kobj,
-				   struct attribute *attr,
-				   char *page)
-{
-	struct fuse_conn_attr *fca =
-		container_of(attr, struct fuse_conn_attr, attr);
-
-	if (fca->show)
-		return fca->show(get_fuse_conn_kobj(kobj), page);
-	else
-		return -EACCES;
-}
-
-static ssize_t fuse_conn_attr_store(struct kobject *kobj,
-				    struct attribute *attr,
-				    const char *page, size_t count)
-{
-	struct fuse_conn_attr *fca =
-		container_of(attr, struct fuse_conn_attr, attr);
-
-	if (fca->store)
-		return fca->store(get_fuse_conn_kobj(kobj), page, count);
-	else
-		return -EACCES;
-}
-
-static struct sysfs_ops fuse_conn_sysfs_ops = {
-	.show	= &fuse_conn_attr_show,
-	.store	= &fuse_conn_attr_store,
-};
-
-static struct kobj_type ktype_fuse_conn = {
-	.release	= fuse_conn_release,
-	.sysfs_ops	= &fuse_conn_sysfs_ops,
-	.default_attrs	= fuse_conn_attrs,
-};
-
 static decl_subsys(fuse, NULL, NULL);
-static decl_subsys(connections, &ktype_fuse_conn, NULL);
+static decl_subsys(connections, NULL, NULL);
 
 static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
 				 unsigned long flags)
@@ -719,6 +668,7 @@
 	printk("fuse init (API version %i.%i)\n",
 	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
 
+	INIT_LIST_HEAD(&fuse_conn_list);
 	res = fuse_fs_init();
 	if (res)
 		goto err;
@@ -731,8 +681,14 @@
 	if (res)
 		goto err_dev_cleanup;
 
+	res = fuse_ctl_init();
+	if (res)
+		goto err_sysfs_cleanup;
+
 	return 0;
 
+ err_sysfs_cleanup:
+	fuse_sysfs_cleanup();
  err_dev_cleanup:
 	fuse_dev_cleanup();
  err_fs_cleanup:
@@ -745,6 +701,7 @@
 {
 	printk(KERN_DEBUG "fuse exit\n");
 
+	fuse_ctl_cleanup();
 	fuse_sysfs_cleanup();
 	fuse_fs_cleanup();
 	fuse_dev_cleanup();
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index 80d7f53..de5bafb 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -531,6 +531,7 @@
 		default:
 			jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
 				  blocktype);
+			brelse(bh);
 			goto done;
 		}
 	}
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 1862e8b..b8886f0 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -53,8 +53,7 @@
 	if (!instr) {
 		printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
 		spin_lock(&c->erase_completion_lock);
-		list_del(&jeb->list);
-		list_add(&jeb->list, &c->erase_pending_list);
+		list_move(&jeb->list, &c->erase_pending_list);
 		c->erasing_size -= c->sector_size;
 		c->dirty_size += c->sector_size;
 		jeb->dirty_size = c->sector_size;
@@ -86,8 +85,7 @@
 		/* Erase failed immediately. Refile it on the list */
 		D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
 		spin_lock(&c->erase_completion_lock);
-		list_del(&jeb->list);
-		list_add(&jeb->list, &c->erase_pending_list);
+		list_move(&jeb->list, &c->erase_pending_list);
 		c->erasing_size -= c->sector_size;
 		c->dirty_size += c->sector_size;
 		jeb->dirty_size = c->sector_size;
@@ -161,8 +159,7 @@
 {
 	D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
 	spin_lock(&c->erase_completion_lock);
-	list_del(&jeb->list);
-	list_add_tail(&jeb->list, &c->erase_complete_list);
+	list_move_tail(&jeb->list, &c->erase_complete_list);
 	spin_unlock(&c->erase_completion_lock);
 	/* Ensure that kupdated calls us again to mark them clean */
 	jffs2_erase_pending_trigger(c);
@@ -178,8 +175,7 @@
 		if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
 			/* We'd like to give this block another try. */
 			spin_lock(&c->erase_completion_lock);
-			list_del(&jeb->list);
-			list_add(&jeb->list, &c->erase_pending_list);
+			list_move(&jeb->list, &c->erase_pending_list);
 			c->erasing_size -= c->sector_size;
 			c->dirty_size += c->sector_size;
 			jeb->dirty_size = c->sector_size;
@@ -191,8 +187,7 @@
 	spin_lock(&c->erase_completion_lock);
 	c->erasing_size -= c->sector_size;
 	c->bad_size += c->sector_size;
-	list_del(&jeb->list);
-	list_add(&jeb->list, &c->bad_list);
+	list_move(&jeb->list, &c->bad_list);
 	c->nr_erasing_blocks--;
 	spin_unlock(&c->erase_completion_lock);
 	wake_up(&c->erase_wait);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 8bedfd2..ac0c350 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -211,8 +211,7 @@
 			struct jffs2_eraseblock *ejeb;
 
 			ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
-			list_del(&ejeb->list);
-			list_add_tail(&ejeb->list, &c->erase_pending_list);
+			list_move_tail(&ejeb->list, &c->erase_pending_list);
 			c->nr_erasing_blocks++;
 			jffs2_erase_pending_trigger(c);
 			D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 0b02fc7..be1acc3 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -43,7 +43,7 @@
 		return -ENOMEM;
 	}
 
-	dbg_summary("returned succesfully\n");
+	dbg_summary("returned successfully\n");
 
 	return 0;
 }
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index a7f153f..b9b7007 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -495,8 +495,7 @@
 	/* Fix up the original jeb now it's on the bad_list */
 	if (first_raw == jeb->first_node) {
 		D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
-		list_del(&jeb->list);
-		list_add(&jeb->list, &c->erase_pending_list);
+		list_move(&jeb->list, &c->erase_pending_list);
 		c->nr_erasing_blocks++;
 		jffs2_erase_pending_trigger(c);
 	}
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
index 5549378..4d52593 100644
--- a/fs/jfs/jfs_extent.c
+++ b/fs/jfs/jfs_extent.c
@@ -126,7 +126,7 @@
 
 	/* allocate the disk blocks for the extent.  initially, extBalloc()
 	 * will try to allocate disk blocks for the requested size (xlen). 
-	 * if this fails (xlen contigious free blocks not avaliable), it'll
+	 * if this fails (xlen contiguous free blocks not avaliable), it'll
 	 * try to allocate a smaller number of blocks (producing a smaller
 	 * extent), with this smaller number of blocks consisting of the
 	 * requested number of blocks rounded down to the next smaller
@@ -493,7 +493,7 @@
  *
  *		initially, we will try to allocate disk blocks for the
  *		requested size (nblocks).  if this fails (nblocks 
- *		contigious free blocks not avaliable), we'll try to allocate
+ *		contiguous free blocks not avaliable), we'll try to allocate
  *		a smaller number of blocks (producing a smaller extent), with
  *		this smaller number of blocks consisting of the requested
  *		number of blocks rounded down to the next smaller power of 2
@@ -529,7 +529,7 @@
 
 	/* get the number of blocks to initially attempt to allocate.
 	 * we'll first try the number of blocks requested unless this
-	 * number is greater than the maximum number of contigious free
+	 * number is greater than the maximum number of contiguous free
 	 * blocks in the map. in that case, we'll start off with the 
 	 * maximum free.
 	 */
@@ -586,7 +586,7 @@
  *		in place.  if this fails, we'll try to move the extent
  *		to a new set of blocks. if moving the extent, we initially
  *		will try to allocate disk blocks for the requested size
- *		(nnew).  if this fails 	(nnew contigious free blocks not
+ *		(nnew).  if this fails 	(new contiguous free blocks not
  *		avaliable), we'll try  to allocate a smaller number of
  *		blocks (producing a smaller extent), with this smaller
  *		number of blocks consisting of the requested number of
diff --git a/fs/libfs.c b/fs/libfs.c
index 1b11563..ac02ea6 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -149,10 +149,9 @@
 			/* fallthrough */
 		default:
 			spin_lock(&dcache_lock);
-			if (filp->f_pos == 2) {
-				list_del(q);
-				list_add(q, &dentry->d_subdirs);
-			}
+			if (filp->f_pos == 2)
+				list_move(q, &dentry->d_subdirs);
+
 			for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
 				struct dentry *next;
 				next = list_entry(p, struct dentry, d_u.d_child);
@@ -164,8 +163,7 @@
 					return 0;
 				spin_lock(&dcache_lock);
 				/* next is still alive */
-				list_del(q);
-				list_add(q, p);
+				list_move(q, p);
 				p = q;
 				filp->f_pos++;
 			}
@@ -424,13 +422,13 @@
 
 static DEFINE_SPINLOCK(pin_fs_lock);
 
-int simple_pin_fs(char *name, struct vfsmount **mount, int *count)
+int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
 {
 	struct vfsmount *mnt = NULL;
 	spin_lock(&pin_fs_lock);
 	if (unlikely(!*mount)) {
 		spin_unlock(&pin_fs_lock);
-		mnt = do_kern_mount(name, 0, name, NULL);
+		mnt = vfs_kern_mount(type, 0, type->name, NULL);
 		if (IS_ERR(mnt))
 			return PTR_ERR(mnt);
 		spin_lock(&pin_fs_lock);
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index bce7444..52774fe 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -147,11 +147,10 @@
  * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
  * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
  */
-static inline
-void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
+static void nlmclnt_prepare_reclaim(struct nlm_host *host)
 {
+	down_write(&host->h_rwsem);
 	host->h_monitored = 0;
-	host->h_nsmstate = newstate;
 	host->h_state++;
 	host->h_nextrebind = 0;
 	nlm_rebind_host(host);
@@ -164,6 +163,13 @@
 	dprintk("NLM: reclaiming locks for host %s", host->h_name);
 }
 
+static void nlmclnt_finish_reclaim(struct nlm_host *host)
+{
+	host->h_reclaiming = 0;
+	up_write(&host->h_rwsem);
+	dprintk("NLM: done reclaiming locks for host %s", host->h_name);
+}
+
 /*
  * Reclaim all locks on server host. We do this by spawning a separate
  * reclaimer thread.
@@ -171,12 +177,10 @@
 void
 nlmclnt_recovery(struct nlm_host *host, u32 newstate)
 {
-	if (host->h_reclaiming++) {
-		if (host->h_nsmstate == newstate)
-			return;
-		nlmclnt_prepare_reclaim(host, newstate);
-	} else {
-		nlmclnt_prepare_reclaim(host, newstate);
+	if (host->h_nsmstate == newstate)
+		return;
+	host->h_nsmstate = newstate;
+	if (!host->h_reclaiming++) {
 		nlm_get_host(host);
 		__module_get(THIS_MODULE);
 		if (kernel_thread(reclaimer, host, CLONE_KERNEL) < 0)
@@ -190,6 +194,7 @@
 	struct nlm_host	  *host = (struct nlm_host *) ptr;
 	struct nlm_wait	  *block;
 	struct file_lock *fl, *next;
+	u32 nsmstate;
 
 	daemonize("%s-reclaim", host->h_name);
 	allow_signal(SIGKILL);
@@ -199,19 +204,25 @@
 	lock_kernel();
 	lockd_up();
 
+	nlmclnt_prepare_reclaim(host);
 	/* First, reclaim all locks that have been marked. */
 restart:
+	nsmstate = host->h_nsmstate;
 	list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
 		list_del_init(&fl->fl_u.nfs_fl.list);
 
 		if (signalled())
 			continue;
-		if (nlmclnt_reclaim(host, fl) == 0)
-			list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
-		goto restart;
+		if (nlmclnt_reclaim(host, fl) != 0)
+			continue;
+		list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
+		if (host->h_nsmstate != nsmstate) {
+			/* Argh! The server rebooted again! */
+			list_splice_init(&host->h_granted, &host->h_reclaim);
+			goto restart;
+		}
 	}
-
-	host->h_reclaiming = 0;
+	nlmclnt_finish_reclaim(host);
 
 	/* Now, wake up all processes that sleep on a blocked lock */
 	list_for_each_entry(block, &nlm_blocked, b_list) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index f96e381..4db6209 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -508,7 +508,10 @@
 	}
 
 	block = nlmclnt_prepare_block(host, fl);
+again:
 	for(;;) {
+		/* Reboot protection */
+		fl->fl_u.nfs_fl.state = host->h_state;
 		status = nlmclnt_call(req, NLMPROC_LOCK);
 		if (status < 0)
 			goto out_unblock;
@@ -531,10 +534,16 @@
 	}
 
 	if (resp->status == NLM_LCK_GRANTED) {
-		fl->fl_u.nfs_fl.state = host->h_state;
+		down_read(&host->h_rwsem);
+		/* Check whether or not the server has rebooted */
+		if (fl->fl_u.nfs_fl.state != host->h_state) {
+			up_read(&host->h_rwsem);
+			goto again;
+		}
 		fl->fl_flags |= FL_SLEEP;
 		/* Ensure the resulting lock will get added to granted list */
 		do_vfs_lock(fl);
+		up_read(&host->h_rwsem);
 	}
 	status = nlm_stat_to_errno(resp->status);
 out_unblock:
@@ -596,6 +605,7 @@
 static int
 nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 {
+	struct nlm_host	*host = req->a_host;
 	struct nlm_res	*resp = &req->a_res;
 	int		status;
 
@@ -604,7 +614,9 @@
 	 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
 	 * case, we want to unlock.
 	 */
+	down_read(&host->h_rwsem);
 	do_vfs_lock(fl);
+	up_read(&host->h_rwsem);
 
 	if (req->a_flags & RPC_TASK_ASYNC)
 		return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 729ac42..38b0e8a 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -112,11 +112,12 @@
 	host->h_version    = version;
 	host->h_proto      = proto;
 	host->h_rpcclnt    = NULL;
-	init_MUTEX(&host->h_sema);
+	mutex_init(&host->h_mutex);
 	host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 	host->h_expires    = jiffies + NLM_HOST_EXPIRE;
 	atomic_set(&host->h_count, 1);
 	init_waitqueue_head(&host->h_gracewait);
+	init_rwsem(&host->h_rwsem);
 	host->h_state      = 0;			/* pseudo NSM state */
 	host->h_nsmstate   = 0;			/* real NSM state */
 	host->h_server	   = server;
@@ -172,7 +173,7 @@
 			(unsigned)ntohl(host->h_addr.sin_addr.s_addr));
 
 	/* Lock host handle */
-	down(&host->h_sema);
+	mutex_lock(&host->h_mutex);
 
 	/* If we've already created an RPC client, check whether
 	 * RPC rebind is required
@@ -204,12 +205,12 @@
 		host->h_rpcclnt = clnt;
 	}
 
-	up(&host->h_sema);
+	mutex_unlock(&host->h_mutex);
 	return clnt;
 
 forgetit:
 	printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
-	up(&host->h_sema);
+	mutex_unlock(&host->h_mutex);
 	return NULL;
 }
 
diff --git a/fs/namei.c b/fs/namei.c
index bb4a3e4..c784e8b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2243,14 +2243,16 @@
 	int error;
 	char * to;
 
-	if (flags != 0)
+	if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
 		return -EINVAL;
 
 	to = getname(newname);
 	if (IS_ERR(to))
 		return PTR_ERR(to);
 
-	error = __user_walk_fd(olddfd, oldname, 0, &old_nd);
+	error = __user_walk_fd(olddfd, oldname,
+			       flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
+			       &old_nd);
 	if (error)
 		goto exit;
 	error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
diff --git a/fs/namespace.c b/fs/namespace.c
index c13072a..b3ed212 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -526,10 +526,8 @@
 {
 	struct vfsmount *p;
 
-	for (p = mnt; p; p = next_mnt(p, mnt)) {
-		list_del(&p->mnt_hash);
-		list_add(&p->mnt_hash, kill);
-	}
+	for (p = mnt; p; p = next_mnt(p, mnt))
+		list_move(&p->mnt_hash, kill);
 
 	if (propagate)
 		propagate_umount(kill);
@@ -585,8 +583,8 @@
 	 */
 
 	lock_kernel();
-	if ((flags & MNT_FORCE) && sb->s_op->umount_begin)
-		sb->s_op->umount_begin(sb);
+	if (sb->s_op->umount_begin)
+		sb->s_op->umount_begin(mnt, flags);
 	unlock_kernel();
 
 	/*
@@ -1172,13 +1170,46 @@
 }
 
 /*
+ * go through the vfsmounts we've just consigned to the graveyard to
+ * - check that they're still dead
+ * - delete the vfsmount from the appropriate namespace under lock
+ * - dispose of the corpse
+ */
+static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
+{
+	struct namespace *namespace;
+	struct vfsmount *mnt;
+
+	while (!list_empty(graveyard)) {
+		LIST_HEAD(umounts);
+		mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
+		list_del_init(&mnt->mnt_expire);
+
+		/* don't do anything if the namespace is dead - all the
+		 * vfsmounts from it are going away anyway */
+		namespace = mnt->mnt_namespace;
+		if (!namespace || !namespace->root)
+			continue;
+		get_namespace(namespace);
+
+		spin_unlock(&vfsmount_lock);
+		down_write(&namespace_sem);
+		expire_mount(mnt, mounts, &umounts);
+		up_write(&namespace_sem);
+		release_mounts(&umounts);
+		mntput(mnt);
+		put_namespace(namespace);
+		spin_lock(&vfsmount_lock);
+	}
+}
+
+/*
  * process a list of expirable mountpoints with the intent of discarding any
  * mountpoints that aren't in use and haven't been touched since last we came
  * here
  */
 void mark_mounts_for_expiry(struct list_head *mounts)
 {
-	struct namespace *namespace;
 	struct vfsmount *mnt, *next;
 	LIST_HEAD(graveyard);
 
@@ -1202,33 +1233,7 @@
 		list_move(&mnt->mnt_expire, &graveyard);
 	}
 
-	/*
-	 * go through the vfsmounts we've just consigned to the graveyard to
-	 * - check that they're still dead
-	 * - delete the vfsmount from the appropriate namespace under lock
-	 * - dispose of the corpse
-	 */
-	while (!list_empty(&graveyard)) {
-		LIST_HEAD(umounts);
-		mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
-		list_del_init(&mnt->mnt_expire);
-
-		/* don't do anything if the namespace is dead - all the
-		 * vfsmounts from it are going away anyway */
-		namespace = mnt->mnt_namespace;
-		if (!namespace || !namespace->root)
-			continue;
-		get_namespace(namespace);
-
-		spin_unlock(&vfsmount_lock);
-		down_write(&namespace_sem);
-		expire_mount(mnt, mounts, &umounts);
-		up_write(&namespace_sem);
-		release_mounts(&umounts);
-		mntput(mnt);
-		put_namespace(namespace);
-		spin_lock(&vfsmount_lock);
-	}
+	expire_mount_list(&graveyard, mounts);
 
 	spin_unlock(&vfsmount_lock);
 }
@@ -1236,6 +1241,73 @@
 EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
 
 /*
+ * Ripoff of 'select_parent()'
+ *
+ * search the list of submounts for a given mountpoint, and move any
+ * shrinkable submounts to the 'graveyard' list.
+ */
+static int select_submounts(struct vfsmount *parent, struct list_head *graveyard)
+{
+	struct vfsmount *this_parent = parent;
+	struct list_head *next;
+	int found = 0;
+
+repeat:
+	next = this_parent->mnt_mounts.next;
+resume:
+	while (next != &this_parent->mnt_mounts) {
+		struct list_head *tmp = next;
+		struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child);
+
+		next = tmp->next;
+		if (!(mnt->mnt_flags & MNT_SHRINKABLE))
+			continue;
+		/*
+		 * Descend a level if the d_mounts list is non-empty.
+		 */
+		if (!list_empty(&mnt->mnt_mounts)) {
+			this_parent = mnt;
+			goto repeat;
+		}
+
+		if (!propagate_mount_busy(mnt, 1)) {
+			mntget(mnt);
+			list_move_tail(&mnt->mnt_expire, graveyard);
+			found++;
+		}
+	}
+	/*
+	 * All done at this level ... ascend and resume the search
+	 */
+	if (this_parent != parent) {
+		next = this_parent->mnt_child.next;
+		this_parent = this_parent->mnt_parent;
+		goto resume;
+	}
+	return found;
+}
+
+/*
+ * process a list of expirable mountpoints with the intent of discarding any
+ * submounts of a specific parent mountpoint
+ */
+void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts)
+{
+	LIST_HEAD(graveyard);
+	int found;
+
+	spin_lock(&vfsmount_lock);
+
+	/* extract submounts of 'mountpoint' from the expiration list */
+	while ((found = select_submounts(mountpoint, &graveyard)) != 0)
+		expire_mount_list(&graveyard, mounts);
+
+	spin_unlock(&vfsmount_lock);
+}
+
+EXPORT_SYMBOL_GPL(shrink_submounts);
+
+/*
  * Some copy_from_user() implementations do not return the exact number of
  * bytes remaining to copy on a fault.  But copy_mount_options() requires that.
  * Note that this function differs from copy_from_user() in that it will oops
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index ec61fd5..0b572a0 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -4,14 +4,16 @@
 
 obj-$(CONFIG_NFS_FS) += nfs.o
 
-nfs-y 			:= dir.o file.o inode.o nfs2xdr.o pagelist.o \
-			   proc.o read.o symlink.o unlink.o write.o
+nfs-y 			:= dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
+			   proc.o read.o symlink.o unlink.o write.o \
+			   namespace.o
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o mount_clnt.o      
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
 			   delegation.o idmap.o \
-			   callback.o callback_xdr.o callback_proc.o
+			   callback.o callback_xdr.o callback_proc.o \
+			   nfs4namespace.o
 nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
 nfs-$(CONFIG_SYSCTL) += sysctl.o
 nfs-objs		:= $(nfs-y)
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 90c95ad..d53f8c6 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -182,8 +182,6 @@
 /*
  * Define NFS4 callback program
  */
-extern struct svc_version nfs4_callback_version1;
-
 static struct svc_version *nfs4_callback_version[] = {
 	[1] = &nfs4_callback_version1,
 };
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 05c38cf..c929913 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -202,7 +202,7 @@
 	status = decode_fh(xdr, &args->fh);
 out:
 	dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
-	return 0;
+	return status;
 }
 
 static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index cae74dd..3ddda6f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -528,7 +528,7 @@
 
 	lock_kernel();
 
-	res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+	res = nfs_revalidate_mapping(inode, filp->f_mapping);
 	if (res < 0) {
 		unlock_kernel();
 		return res;
@@ -868,6 +868,17 @@
 	return (nd->intent.open.flags & O_EXCL) != 0;
 }
 
+static inline int nfs_reval_fsid(struct inode *dir,
+		struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+	struct nfs_server *server = NFS_SERVER(dir);
+
+	if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
+		/* Revalidate fsid on root dir */
+		return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
+	return 0;
+}
+
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
 	struct dentry *res;
@@ -900,6 +911,11 @@
 		res = ERR_PTR(error);
 		goto out_unlock;
 	}
+	error = nfs_reval_fsid(dir, &fhandle, &fattr);
+	if (error < 0) {
+		res = ERR_PTR(error);
+		goto out_unlock;
+	}
 	inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
 	res = (struct dentry *)inode;
 	if (IS_ERR(res))
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 3c72b0c..402005c 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -892,7 +892,7 @@
  * nfs_init_directcache - create a slab cache for nfs_direct_req structures
  *
  */
-int nfs_init_directcache(void)
+int __init nfs_init_directcache(void)
 {
 	nfs_direct_cachep = kmem_cache_create("nfs_direct_cache",
 						sizeof(struct nfs_direct_req),
@@ -906,10 +906,10 @@
 }
 
 /**
- * nfs_init_directcache - destroy the slab cache for nfs_direct_req structures
+ * nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures
  *
  */
-void nfs_destroy_directcache(void)
+void __exit nfs_destroy_directcache(void)
 {
 	if (kmem_cache_destroy(nfs_direct_cachep))
 		printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index fa05c02..add2891 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -127,23 +127,6 @@
 }
 
 /**
- * nfs_revalidate_file - Revalidate the page cache & related metadata
- * @inode - pointer to inode struct
- * @file - pointer to file
- */
-static int nfs_revalidate_file(struct inode *inode, struct file *filp)
-{
-	struct nfs_inode *nfsi = NFS_I(inode);
-	int retval = 0;
-
-	if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR))
-			|| nfs_attribute_timeout(inode))
-		retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
-	nfs_revalidate_mapping(inode, filp->f_mapping);
-	return 0;
-}
-
-/**
  * nfs_revalidate_size - Revalidate the file size
  * @inode - pointer to inode struct
  * @file - pointer to struct file
@@ -228,7 +211,7 @@
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long) pos);
 
-	result = nfs_revalidate_file(inode, iocb->ki_filp);
+	result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
 	nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
 	if (!result)
 		result = generic_file_aio_read(iocb, buf, count, pos);
@@ -247,7 +230,7 @@
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long long) *ppos);
 
-	res = nfs_revalidate_file(inode, filp);
+	res = nfs_revalidate_mapping(inode, filp->f_mapping);
 	if (!res)
 		res = generic_file_sendfile(filp, ppos, count, actor, target);
 	return res;
@@ -263,7 +246,7 @@
 	dfprintk(VFS, "nfs: mmap(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
-	status = nfs_revalidate_file(inode, file);
+	status = nfs_revalidate_mapping(inode, file->f_mapping);
 	if (!status)
 		status = generic_file_mmap(file, vma);
 	return status;
@@ -320,7 +303,11 @@
 
 static void nfs_invalidate_page(struct page *page, unsigned long offset)
 {
-	/* FIXME: we really should cancel any unstarted writes on this page */
+	struct inode *inode = page->mapping->host;
+
+	/* Cancel any unstarted writes on this page */
+	if (offset == 0)
+		nfs_sync_inode_wait(inode, page->index, 1, FLUSH_INVALIDATE);
 }
 
 static int nfs_release_page(struct page *page, gfp_t gfp)
@@ -373,7 +360,6 @@
 		if (result)
 			goto out;
 	}
-	nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
 
 	result = count;
 	if (!count)
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 3fab5b0..b81e7ed 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -47,7 +47,6 @@
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
-#include <linux/nfs_fs_sb.h>
 #include <linux/nfs_fs.h>
 
 #include <linux/nfs_idmap.h>
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 937fbfc..51bc88b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -36,6 +36,8 @@
 #include <linux/mount.h>
 #include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
+#include <linux/inet.h>
+#include <linux/nfs_xdr.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -44,89 +46,17 @@
 #include "callback.h"
 #include "delegation.h"
 #include "iostat.h"
+#include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
-/* Maximum number of readahead requests
- * FIXME: this should really be a sysctl so that users may tune it to suit
- *        their needs. People that do NFS over a slow network, might for
- *        instance want to reduce it to something closer to 1 for improved
- *        interactive response.
- */
-#define NFS_MAX_READAHEAD	(RPC_DEF_SLOT_TABLE - 1)
-
 static void nfs_invalidate_inode(struct inode *);
 static int nfs_update_inode(struct inode *, struct nfs_fattr *);
 
-static struct inode *nfs_alloc_inode(struct super_block *sb);
-static void nfs_destroy_inode(struct inode *);
-static int nfs_write_inode(struct inode *,int);
-static void nfs_delete_inode(struct inode *);
-static void nfs_clear_inode(struct inode *);
-static void nfs_umount_begin(struct super_block *);
-static int  nfs_statfs(struct dentry *, struct kstatfs *);
-static int  nfs_show_options(struct seq_file *, struct vfsmount *);
-static int  nfs_show_stats(struct seq_file *, struct vfsmount *);
 static void nfs_zap_acl_cache(struct inode *);
 
-static struct rpc_program	nfs_program;
-
-static struct super_operations nfs_sops = { 
-	.alloc_inode	= nfs_alloc_inode,
-	.destroy_inode	= nfs_destroy_inode,
-	.write_inode	= nfs_write_inode,
-	.delete_inode	= nfs_delete_inode,
-	.statfs		= nfs_statfs,
-	.clear_inode	= nfs_clear_inode,
-	.umount_begin	= nfs_umount_begin,
-	.show_options	= nfs_show_options,
-	.show_stats	= nfs_show_stats,
-};
-
-/*
- * RPC cruft for NFS
- */
-static struct rpc_stat		nfs_rpcstat = {
-	.program		= &nfs_program
-};
-static struct rpc_version *	nfs_version[] = {
-	NULL,
-	NULL,
-	&nfs_version2,
-#if defined(CONFIG_NFS_V3)
-	&nfs_version3,
-#elif defined(CONFIG_NFS_V4)
-	NULL,
-#endif
-#if defined(CONFIG_NFS_V4)
-	&nfs_version4,
-#endif
-};
-
-static struct rpc_program	nfs_program = {
-	.name			= "nfs",
-	.number			= NFS_PROGRAM,
-	.nrvers			= ARRAY_SIZE(nfs_version),
-	.version		= nfs_version,
-	.stats			= &nfs_rpcstat,
-	.pipe_dir_name		= "/nfs",
-};
-
-#ifdef CONFIG_NFS_V3_ACL
-static struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program };
-static struct rpc_version *	nfsacl_version[] = {
-	[3]			= &nfsacl_version3,
-};
-
-struct rpc_program		nfsacl_program = {
-	.name =			"nfsacl",
-	.number =		NFS_ACL_PROGRAM,
-	.nrvers =		ARRAY_SIZE(nfsacl_version),
-	.version =		nfsacl_version,
-	.stats =		&nfsacl_rpcstat,
-};
-#endif  /* CONFIG_NFS_V3_ACL */
+static kmem_cache_t * nfs_inode_cachep;
 
 static inline unsigned long
 nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
@@ -134,8 +64,7 @@
 	return nfs_fileid_to_ino_t(fattr->fileid);
 }
 
-static int
-nfs_write_inode(struct inode *inode, int sync)
+int nfs_write_inode(struct inode *inode, int sync)
 {
 	int flags = sync ? FLUSH_SYNC : 0;
 	int ret;
@@ -146,31 +75,15 @@
 	return 0;
 }
 
-static void
-nfs_delete_inode(struct inode * inode)
-{
-	dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
-
-	truncate_inode_pages(&inode->i_data, 0);
-
-	nfs_wb_all(inode);
-	/*
-	 * The following should never happen...
-	 */
-	if (nfs_have_writebacks(inode)) {
-		printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
-	}
-
-	clear_inode(inode);
-}
-
-static void
-nfs_clear_inode(struct inode *inode)
+void nfs_clear_inode(struct inode *inode)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct rpc_cred *cred;
 
-	nfs_wb_all(inode);
+	/*
+	 * The following should never happen...
+	 */
+	BUG_ON(nfs_have_writebacks(inode));
 	BUG_ON (!list_empty(&nfsi->open_files));
 	nfs_zap_acl_cache(inode);
 	cred = nfsi->cache_access.cred;
@@ -179,555 +92,6 @@
 	BUG_ON(atomic_read(&nfsi->data_updates) != 0);
 }
 
-void
-nfs_umount_begin(struct super_block *sb)
-{
-	struct rpc_clnt	*rpc = NFS_SB(sb)->client;
-
-	/* -EIO all pending I/O */
-	if (!IS_ERR(rpc))
-		rpc_killall_tasks(rpc);
-	rpc = NFS_SB(sb)->client_acl;
-	if (!IS_ERR(rpc))
-		rpc_killall_tasks(rpc);
-}
-
-
-static inline unsigned long
-nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
-{
-	/* make sure blocksize is a power of two */
-	if ((bsize & (bsize - 1)) || nrbitsp) {
-		unsigned char	nrbits;
-
-		for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
-			;
-		bsize = 1 << nrbits;
-		if (nrbitsp)
-			*nrbitsp = nrbits;
-	}
-
-	return bsize;
-}
-
-/*
- * Calculate the number of 512byte blocks used.
- */
-static inline unsigned long
-nfs_calc_block_size(u64 tsize)
-{
-	loff_t used = (tsize + 511) >> 9;
-	return (used > ULONG_MAX) ? ULONG_MAX : used;
-}
-
-/*
- * Compute and set NFS server blocksize
- */
-static inline unsigned long
-nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
-{
-	if (bsize < NFS_MIN_FILE_IO_SIZE)
-		bsize = NFS_DEF_FILE_IO_SIZE;
-	else if (bsize >= NFS_MAX_FILE_IO_SIZE)
-		bsize = NFS_MAX_FILE_IO_SIZE;
-
-	return nfs_block_bits(bsize, nrbitsp);
-}
-
-/*
- * Obtain the root inode of the file system.
- */
-static struct inode *
-nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
-{
-	struct nfs_server	*server = NFS_SB(sb);
-	int			error;
-
-	error = server->rpc_ops->getroot(server, rootfh, fsinfo);
-	if (error < 0) {
-		dprintk("nfs_get_root: getattr error = %d\n", -error);
-		return ERR_PTR(error);
-	}
-
-	return nfs_fhget(sb, rootfh, fsinfo->fattr);
-}
-
-/*
- * Do NFS version-independent mount processing, and sanity checking
- */
-static int
-nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
-{
-	struct nfs_server	*server;
-	struct inode		*root_inode;
-	struct nfs_fattr	fattr;
-	struct nfs_fsinfo	fsinfo = {
-					.fattr = &fattr,
-				};
-	struct nfs_pathconf pathinfo = {
-			.fattr = &fattr,
-	};
-	int no_root_error = 0;
-	unsigned long max_rpc_payload;
-
-	/* We probably want something more informative here */
-	snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
-	server = NFS_SB(sb);
-
-	sb->s_magic      = NFS_SUPER_MAGIC;
-
-	server->io_stats = nfs_alloc_iostats();
-	if (server->io_stats == NULL)
-		return -ENOMEM;
-
-	root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
-	/* Did getting the root inode fail? */
-	if (IS_ERR(root_inode)) {
-		no_root_error = PTR_ERR(root_inode);
-		goto out_no_root;
-	}
-	sb->s_root = d_alloc_root(root_inode);
-	if (!sb->s_root) {
-		no_root_error = -ENOMEM;
-		goto out_no_root;
-	}
-	sb->s_root->d_op = server->rpc_ops->dentry_ops;
-
-	/* mount time stamp, in seconds */
-	server->mount_time = jiffies;
-
-	/* Get some general file system info */
-	if (server->namelen == 0 &&
-	    server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
-		server->namelen = pathinfo.max_namelen;
-	/* Work out a lot of parameters */
-	if (server->rsize == 0)
-		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
-	if (server->wsize == 0)
-		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
-
-	if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
-		server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
-	if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
-		server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
-
-	max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
-	if (server->rsize > max_rpc_payload)
-		server->rsize = max_rpc_payload;
-	if (server->rsize > NFS_MAX_FILE_IO_SIZE)
-		server->rsize = NFS_MAX_FILE_IO_SIZE;
-	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-	if (server->wsize > max_rpc_payload)
-		server->wsize = max_rpc_payload;
-	if (server->wsize > NFS_MAX_FILE_IO_SIZE)
-		server->wsize = NFS_MAX_FILE_IO_SIZE;
-	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-	if (sb->s_blocksize == 0)
-		sb->s_blocksize = nfs_block_bits(server->wsize,
-							 &sb->s_blocksize_bits);
-	server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
-
-	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
-	if (server->dtsize > PAGE_CACHE_SIZE)
-		server->dtsize = PAGE_CACHE_SIZE;
-	if (server->dtsize > server->rsize)
-		server->dtsize = server->rsize;
-
-	if (server->flags & NFS_MOUNT_NOAC) {
-		server->acregmin = server->acregmax = 0;
-		server->acdirmin = server->acdirmax = 0;
-		sb->s_flags |= MS_SYNCHRONOUS;
-	}
-	server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
-
-	sb->s_maxbytes = fsinfo.maxfilesize;
-	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
-		sb->s_maxbytes = MAX_LFS_FILESIZE; 
-
-	server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
-	server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
-
-	/* We're airborne Set socket buffersize */
-	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
-	return 0;
-	/* Yargs. It didn't work out. */
-out_no_root:
-	dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
-	if (!IS_ERR(root_inode))
-		iput(root_inode);
-	return no_root_error;
-}
-
-static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
-{
-	to->to_initval = timeo * HZ / 10;
-	to->to_retries = retrans;
-	if (!to->to_retries)
-		to->to_retries = 2;
-
-	switch (proto) {
-	case IPPROTO_TCP:
-		if (!to->to_initval)
-			to->to_initval = 60 * HZ;
-		if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
-			to->to_initval = NFS_MAX_TCP_TIMEOUT;
-		to->to_increment = to->to_initval;
-		to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
-		to->to_exponential = 0;
-		break;
-	case IPPROTO_UDP:
-	default:
-		if (!to->to_initval)
-			to->to_initval = 11 * HZ / 10;
-		if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
-			to->to_initval = NFS_MAX_UDP_TIMEOUT;
-		to->to_maxval = NFS_MAX_UDP_TIMEOUT;
-		to->to_exponential = 1;
-		break;
-	}
-}
-
-/*
- * Create an RPC client handle.
- */
-static struct rpc_clnt *
-nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
-{
-	struct rpc_timeout	timeparms;
-	struct rpc_xprt		*xprt = NULL;
-	struct rpc_clnt		*clnt = NULL;
-	int			proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
-	nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
-
-	server->retrans_timeo = timeparms.to_initval;
-	server->retrans_count = timeparms.to_retries;
-
-	/* create transport and client */
-	xprt = xprt_create_proto(proto, &server->addr, &timeparms);
-	if (IS_ERR(xprt)) {
-		dprintk("%s: cannot create RPC transport. Error = %ld\n",
-				__FUNCTION__, PTR_ERR(xprt));
-		return (struct rpc_clnt *)xprt;
-	}
-	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
-				 server->rpc_ops->version, data->pseudoflavor);
-	if (IS_ERR(clnt)) {
-		dprintk("%s: cannot create RPC client. Error = %ld\n",
-				__FUNCTION__, PTR_ERR(xprt));
-		goto out_fail;
-	}
-
-	clnt->cl_intr     = 1;
-	clnt->cl_softrtry = 1;
-
-	return clnt;
-
-out_fail:
-	return clnt;
-}
-
-/*
- * The way this works is that the mount process passes a structure
- * in the data argument which contains the server's IP address
- * and the root file handle obtained from the server's mount
- * daemon. We stash these away in the private superblock fields.
- */
-static int
-nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
-{
-	struct nfs_server	*server;
-	rpc_authflavor_t	authflavor;
-
-	server           = NFS_SB(sb);
-	sb->s_blocksize_bits = 0;
-	sb->s_blocksize = 0;
-	if (data->bsize)
-		sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
-	if (data->rsize)
-		server->rsize = nfs_block_size(data->rsize, NULL);
-	if (data->wsize)
-		server->wsize = nfs_block_size(data->wsize, NULL);
-	server->flags    = data->flags & NFS_MOUNT_FLAGMASK;
-
-	server->acregmin = data->acregmin*HZ;
-	server->acregmax = data->acregmax*HZ;
-	server->acdirmin = data->acdirmin*HZ;
-	server->acdirmax = data->acdirmax*HZ;
-
-	/* Start lockd here, before we might error out */
-	if (!(server->flags & NFS_MOUNT_NONLM))
-		lockd_up();
-
-	server->namelen  = data->namlen;
-	server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
-	if (!server->hostname)
-		return -ENOMEM;
-	strcpy(server->hostname, data->hostname);
-
-	/* Check NFS protocol revision and initialize RPC op vector
-	 * and file handle pool. */
-#ifdef CONFIG_NFS_V3
-	if (server->flags & NFS_MOUNT_VER3) {
-		server->rpc_ops = &nfs_v3_clientops;
-		server->caps |= NFS_CAP_READDIRPLUS;
-	} else {
-		server->rpc_ops = &nfs_v2_clientops;
-	}
-#else
-	server->rpc_ops = &nfs_v2_clientops;
-#endif
-
-	/* Fill in pseudoflavor for mount version < 5 */
-	if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
-		data->pseudoflavor = RPC_AUTH_UNIX;
-	authflavor = data->pseudoflavor;	/* save for sb_init() */
-	/* XXX maybe we want to add a server->pseudoflavor field */
-
-	/* Create RPC client handles */
-	server->client = nfs_create_client(server, data);
-	if (IS_ERR(server->client))
-		return PTR_ERR(server->client);
-	/* RFC 2623, sec 2.3.2 */
-	if (authflavor != RPC_AUTH_UNIX) {
-		struct rpc_auth *auth;
-
-		server->client_sys = rpc_clone_client(server->client);
-		if (IS_ERR(server->client_sys))
-			return PTR_ERR(server->client_sys);
-		auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys);
-		if (IS_ERR(auth))
-			return PTR_ERR(auth);
-	} else {
-		atomic_inc(&server->client->cl_count);
-		server->client_sys = server->client;
-	}
-	if (server->flags & NFS_MOUNT_VER3) {
-#ifdef CONFIG_NFS_V3_ACL
-		if (!(server->flags & NFS_MOUNT_NOACL)) {
-			server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
-			/* No errors! Assume that Sun nfsacls are supported */
-			if (!IS_ERR(server->client_acl))
-				server->caps |= NFS_CAP_ACLS;
-		}
-#else
-		server->flags &= ~NFS_MOUNT_NOACL;
-#endif /* CONFIG_NFS_V3_ACL */
-		/*
-		 * The VFS shouldn't apply the umask to mode bits. We will
-		 * do so ourselves when necessary.
-		 */
-		sb->s_flags |= MS_POSIXACL;
-		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
-			server->namelen = NFS3_MAXNAMLEN;
-		sb->s_time_gran = 1;
-	} else {
-		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
-			server->namelen = NFS2_MAXNAMLEN;
-	}
-
-	sb->s_op = &nfs_sops;
-	return nfs_sb_init(sb, authflavor);
-}
-
-static int
-nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
-	struct super_block *sb = dentry->d_sb;
-	struct nfs_server *server = NFS_SB(sb);
-	unsigned char blockbits;
-	unsigned long blockres;
-	struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
-	struct nfs_fattr fattr;
-	struct nfs_fsstat res = {
-			.fattr = &fattr,
-	};
-	int error;
-
-	lock_kernel();
-
-	error = server->rpc_ops->statfs(server, rootfh, &res);
-	buf->f_type = NFS_SUPER_MAGIC;
-	if (error < 0)
-		goto out_err;
-
-	/*
-	 * Current versions of glibc do not correctly handle the
-	 * case where f_frsize != f_bsize.  Eventually we want to
-	 * report the value of wtmult in this field.
-	 */
-	buf->f_frsize = sb->s_blocksize;
-
-	/*
-	 * On most *nix systems, f_blocks, f_bfree, and f_bavail
-	 * are reported in units of f_frsize.  Linux hasn't had
-	 * an f_frsize field in its statfs struct until recently,
-	 * thus historically Linux's sys_statfs reports these
-	 * fields in units of f_bsize.
-	 */
-	buf->f_bsize = sb->s_blocksize;
-	blockbits = sb->s_blocksize_bits;
-	blockres = (1 << blockbits) - 1;
-	buf->f_blocks = (res.tbytes + blockres) >> blockbits;
-	buf->f_bfree = (res.fbytes + blockres) >> blockbits;
-	buf->f_bavail = (res.abytes + blockres) >> blockbits;
-
-	buf->f_files = res.tfiles;
-	buf->f_ffree = res.afiles;
-
-	buf->f_namelen = server->namelen;
- out:
-	unlock_kernel();
-	return 0;
-
- out_err:
-	dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
-	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
-	goto out;
-
-}
-
-static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
-{
-	static struct proc_nfs_info {
-		int flag;
-		char *str;
-		char *nostr;
-	} nfs_info[] = {
-		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
-		{ NFS_MOUNT_INTR, ",intr", "" },
-		{ NFS_MOUNT_NOCTO, ",nocto", "" },
-		{ NFS_MOUNT_NOAC, ",noac", "" },
-		{ NFS_MOUNT_NONLM, ",nolock", "" },
-		{ NFS_MOUNT_NOACL, ",noacl", "" },
-		{ 0, NULL, NULL }
-	};
-	struct proc_nfs_info *nfs_infop;
-	char buf[12];
-	char *proto;
-
-	seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
-	seq_printf(m, ",rsize=%d", nfss->rsize);
-	seq_printf(m, ",wsize=%d", nfss->wsize);
-	if (nfss->acregmin != 3*HZ || showdefaults)
-		seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
-	if (nfss->acregmax != 60*HZ || showdefaults)
-		seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
-	if (nfss->acdirmin != 30*HZ || showdefaults)
-		seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
-	if (nfss->acdirmax != 60*HZ || showdefaults)
-		seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
-	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
-		if (nfss->flags & nfs_infop->flag)
-			seq_puts(m, nfs_infop->str);
-		else
-			seq_puts(m, nfs_infop->nostr);
-	}
-	switch (nfss->client->cl_xprt->prot) {
-		case IPPROTO_TCP:
-			proto = "tcp";
-			break;
-		case IPPROTO_UDP:
-			proto = "udp";
-			break;
-		default:
-			snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
-			proto = buf;
-	}
-	seq_printf(m, ",proto=%s", proto);
-	seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
-	seq_printf(m, ",retrans=%u", nfss->retrans_count);
-}
-
-static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
-{
-	struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
-
-	nfs_show_mount_options(m, nfss, 0);
-
-	seq_puts(m, ",addr=");
-	seq_escape(m, nfss->hostname, " \t\n\\");
-
-	return 0;
-}
-
-static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
-{
-	int i, cpu;
-	struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
-	struct rpc_auth *auth = nfss->client->cl_auth;
-	struct nfs_iostats totals = { };
-
-	seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
-
-	/*
-	 * Display all mount option settings
-	 */
-	seq_printf(m, "\n\topts:\t");
-	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
-	seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
-	seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
-	seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
-	nfs_show_mount_options(m, nfss, 1);
-
-	seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
-
-	seq_printf(m, "\n\tcaps:\t");
-	seq_printf(m, "caps=0x%x", nfss->caps);
-	seq_printf(m, ",wtmult=%d", nfss->wtmult);
-	seq_printf(m, ",dtsize=%d", nfss->dtsize);
-	seq_printf(m, ",bsize=%d", nfss->bsize);
-	seq_printf(m, ",namelen=%d", nfss->namelen);
-
-#ifdef CONFIG_NFS_V4
-	if (nfss->rpc_ops->version == 4) {
-		seq_printf(m, "\n\tnfsv4:\t");
-		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
-		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
-		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
-	}
-#endif
-
-	/*
-	 * Display security flavor in effect for this mount
-	 */
-	seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
-	if (auth->au_flavor)
-		seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
-
-	/*
-	 * Display superblock I/O counters
-	 */
-	for_each_possible_cpu(cpu) {
-		struct nfs_iostats *stats;
-
-		preempt_disable();
-		stats = per_cpu_ptr(nfss->io_stats, cpu);
-
-		for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
-			totals.events[i] += stats->events[i];
-		for (i = 0; i < __NFSIOS_BYTESMAX; i++)
-			totals.bytes[i] += stats->bytes[i];
-
-		preempt_enable();
-	}
-
-	seq_printf(m, "\n\tevents:\t");
-	for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
-		seq_printf(m, "%lu ", totals.events[i]);
-	seq_printf(m, "\n\tbytes:\t");
-	for (i = 0; i < __NFSIOS_BYTESMAX; i++)
-		seq_printf(m, "%Lu ", totals.bytes[i]);
-	seq_printf(m, "\n");
-
-	rpc_print_iostats(m, nfss->client);
-
-	return 0;
-}
-
 /**
  * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
  */
@@ -890,6 +254,14 @@
 			if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
 			    && fattr->size <= NFS_LIMIT_READDIRPLUS)
 				set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
+			/* Deal with crossing mountpoints */
+			if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
+				if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
+					inode->i_op = &nfs_referral_inode_operations;
+				else
+					inode->i_op = &nfs_mountpoint_inode_operations;
+				inode->i_fop = NULL;
+			}
 		} else if (S_ISLNK(inode->i_mode))
 			inode->i_op = &nfs_symlink_inode_operations;
 		else
@@ -1208,6 +580,7 @@
 	dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
 		inode->i_sb->s_id, (long long)NFS_FILEID(inode));
 
+	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
 	lock_kernel();
 	if (!inode || is_bad_inode(inode))
  		goto out_nowait;
@@ -1221,7 +594,7 @@
 		status = -ESTALE;
 		/* Do we trust the cached ESTALE? */
 		if (NFS_ATTRTIMEO(inode) != 0) {
-			if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) {
+			if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME)) {
 				/* no */
 			} else
 				goto out;
@@ -1252,8 +625,6 @@
 	}
 	spin_unlock(&inode->i_lock);
 
-	nfs_revalidate_mapping(inode, inode->i_mapping);
-
 	if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
 		nfs_zap_acl_cache(inode);
 
@@ -1287,8 +658,7 @@
  */
 int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
-	if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+	if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
 			&& !nfs_attribute_timeout(inode))
 		return NFS_STALE(inode) ? -ESTALE : 0;
 	return __nfs_revalidate_inode(server, inode);
@@ -1299,9 +669,16 @@
  * @inode - pointer to host inode
  * @mapping - pointer to mapping
  */
-void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
+	int ret = 0;
+
+	if (NFS_STALE(inode))
+		ret = -ESTALE;
+	if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
+			|| nfs_attribute_timeout(inode))
+		ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
 
 	if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
 		nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
@@ -1322,6 +699,7 @@
 				inode->i_sb->s_id,
 				(long long)NFS_FILEID(inode));
 	}
+	return ret;
 }
 
 /**
@@ -1361,12 +739,6 @@
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 
-	if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
-			&& nfsi->change_attr == fattr->pre_change_attr) {
-		nfsi->change_attr = fattr->change_attr;
-		nfsi->cache_change_attribute = jiffies;
-	}
-
 	/* If we have atomic WCC data, we may update some attributes */
 	if ((fattr->valid & NFS_ATTR_WCC) != 0) {
 		if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
@@ -1400,9 +772,6 @@
 	int data_unstable;
 
 
-	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
-		return 0;
-
 	/* Has the inode gone and changed behind our back? */
 	if (nfsi->fileid != fattr->fileid
 			|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
@@ -1415,20 +784,13 @@
 	/* Do atomic weak cache consistency updates */
 	nfs_wcc_update_inode(inode, fattr);
 
-	if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0) {
-		if (nfsi->change_attr == fattr->change_attr)
-			goto out;
-		nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
-		if (!data_unstable)
-			nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
-	}
+	if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+			nfsi->change_attr != fattr->change_attr)
+		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
 	/* Verify a few of the more important attributes */
-	if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
-		nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
-		if (!data_unstable)
-			nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
-	}
+	if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
+		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 
 	cur_size = i_size_read(inode);
  	new_isize = nfs_size_to_loff_t(fattr->size);
@@ -1445,7 +807,6 @@
 	if (inode->i_nlink != fattr->nlink)
 		nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
 
-out:
 	if (!timespec_equal(&inode->i_atime, &fattr->atime))
 		nfsi->cache_validity |= NFS_INO_INVALID_ATIME;
 
@@ -1471,7 +832,6 @@
 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		return 0;
 	spin_lock(&inode->i_lock);
-	nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
 	if (time_after(fattr->time_start, nfsi->last_updated))
 		status = nfs_update_inode(inode, fattr);
 	else
@@ -1496,7 +856,7 @@
 
 	spin_lock(&inode->i_lock);
 	if (unlikely((fattr->valid & NFS_ATTR_FATTR) == 0)) {
-		nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+		nfsi->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
 		goto out;
 	}
 	status = nfs_update_inode(inode, fattr);
@@ -1519,6 +879,7 @@
  */
 static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
+	struct nfs_server *server;
 	struct nfs_inode *nfsi = NFS_I(inode);
 	loff_t cur_isize, new_isize;
 	unsigned int	invalid = 0;
@@ -1528,9 +889,6 @@
 			__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
-	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
-		return 0;
-
 	if (nfsi->fileid != fattr->fileid)
 		goto out_fileid;
 
@@ -1540,6 +898,12 @@
 	if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
 		goto out_changed;
 
+	server = NFS_SERVER(inode);
+	/* Update the fsid if and only if this is the root directory */
+	if (inode == inode->i_sb->s_root->d_inode
+			&& !nfs_fsid_equal(&server->fsid, &fattr->fsid))
+		server->fsid = fattr->fsid;
+
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
@@ -1549,7 +913,7 @@
 	/* Are we racing with known updates of the metadata on the server? */
 	data_stable = nfs_verify_change_attribute(inode, fattr->time_start);
 	if (data_stable)
-		nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
+		nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATIME);
 
 	/* Do atomic weak cache consistency updates */
 	nfs_wcc_update_inode(inode, fattr);
@@ -1613,15 +977,13 @@
  		inode->i_blksize = fattr->du.nfs2.blocksize;
  	}
 
-	if ((fattr->valid & NFS_ATTR_FATTR_V4)) {
-		if (nfsi->change_attr != fattr->change_attr) {
-			dprintk("NFS: change_attr change on server for file %s/%ld\n",
-					inode->i_sb->s_id, inode->i_ino);
-			nfsi->change_attr = fattr->change_attr;
-			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
-			nfsi->cache_change_attribute = jiffies;
-		} else
-			invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA);
+	if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
+			nfsi->change_attr != fattr->change_attr) {
+		dprintk("NFS: change_attr change on server for file %s/%ld\n",
+				inode->i_sb->s_id, inode->i_ino);
+		nfsi->change_attr = fattr->change_attr;
+		invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+		nfsi->cache_change_attribute = jiffies;
 	}
 
 	/* Update attrtimeo value if we're out of the unstable period */
@@ -1669,202 +1031,15 @@
 	goto out_err;
 }
 
-/*
- * File system information
- */
-
-static int nfs_set_super(struct super_block *s, void *data)
-{
-	s->s_fs_info = data;
-	return set_anon_super(s, data);
-}
- 
-static int nfs_compare_super(struct super_block *sb, void *data)
-{
-	struct nfs_server *server = data;
-	struct nfs_server *old = NFS_SB(sb);
-
-	if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
-		return 0;
-	if (old->addr.sin_port != server->addr.sin_port)
-		return 0;
-	return !nfs_compare_fh(&old->fh, &server->fh);
-}
-
-static int nfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
-{
-	int error;
-	struct nfs_server *server = NULL;
-	struct super_block *s;
-	struct nfs_fh *root;
-	struct nfs_mount_data *data = raw_data;
-
-	error = -EINVAL;
-	if (data == NULL) {
-		dprintk("%s: missing data argument\n", __FUNCTION__);
-		goto out_err_noserver;
-	}
-	if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
-		dprintk("%s: bad mount version\n", __FUNCTION__);
-		goto out_err_noserver;
-	}
-	switch (data->version) {
-		case 1:
-			data->namlen = 0;
-		case 2:
-			data->bsize  = 0;
-		case 3:
-			if (data->flags & NFS_MOUNT_VER3) {
-				dprintk("%s: mount structure version %d does not support NFSv3\n",
-						__FUNCTION__,
-						data->version);
-				goto out_err_noserver;
-			}
-			data->root.size = NFS2_FHSIZE;
-			memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
-		case 4:
-			if (data->flags & NFS_MOUNT_SECFLAVOUR) {
-				dprintk("%s: mount structure version %d does not support strong security\n",
-						__FUNCTION__,
-						data->version);
-				goto out_err_noserver;
-			}
-		case 5:
-			memset(data->context, 0, sizeof(data->context));
-	}
-#ifndef CONFIG_NFS_V3
-	/* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
-	error = -EPROTONOSUPPORT;
-	if (data->flags & NFS_MOUNT_VER3) {
-		dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
-		goto out_err_noserver;
-	}
-#endif /* CONFIG_NFS_V3 */
-
-	error = -ENOMEM;
-	server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
-	if (!server)
-		goto out_err_noserver;
-	/* Zero out the NFS state stuff */
-	init_nfsv4_state(server);
-	server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
-
-	root = &server->fh;
-	if (data->flags & NFS_MOUNT_VER3)
-		root->size = data->root.size;
-	else
-		root->size = NFS2_FHSIZE;
-	error = -EINVAL;
-	if (root->size > sizeof(root->data)) {
-		dprintk("%s: invalid root filehandle\n", __FUNCTION__);
-		goto out_err;
-	}
-	memcpy(root->data, data->root.data, root->size);
-
-	/* We now require that the mount process passes the remote address */
-	memcpy(&server->addr, &data->addr, sizeof(server->addr));
-	if (server->addr.sin_addr.s_addr == INADDR_ANY) {
-		dprintk("%s: mount program didn't pass remote address!\n",
-				__FUNCTION__);
-		goto out_err;
-	}
-
-	/* Fire up rpciod if not yet running */
-	error = rpciod_up();
-	if (error < 0) {
-		dprintk("%s: couldn't start rpciod! Error = %d\n",
-				__FUNCTION__, error);
-		goto out_err;
-	}
-
-	s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
-	if (IS_ERR(s)) {
-		error = PTR_ERR(s);
-		goto out_err_rpciod;
-	}
-
-	if (s->s_root)
-		goto out_rpciod_down;
-
-	s->s_flags = flags;
-
-	error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
-	if (error) {
-		up_write(&s->s_umount);
-		deactivate_super(s);
-		return error;
-	}
-	s->s_flags |= MS_ACTIVE;
-	return simple_set_mnt(mnt, s);
-
-out_rpciod_down:
-	rpciod_down();
-	kfree(server);
-	return simple_set_mnt(mnt, s);
-
-out_err_rpciod:
-	rpciod_down();
-out_err:
-	kfree(server);
-out_err_noserver:
-	return error;
-}
-
-static void nfs_kill_super(struct super_block *s)
-{
-	struct nfs_server *server = NFS_SB(s);
-
-	kill_anon_super(s);
-
-	if (!IS_ERR(server->client))
-		rpc_shutdown_client(server->client);
-	if (!IS_ERR(server->client_sys))
-		rpc_shutdown_client(server->client_sys);
-	if (!IS_ERR(server->client_acl))
-		rpc_shutdown_client(server->client_acl);
-
-	if (!(server->flags & NFS_MOUNT_NONLM))
-		lockd_down();	/* release rpc.lockd */
-
-	rpciod_down();		/* release rpciod */
-
-	nfs_free_iostats(server->io_stats);
-	kfree(server->hostname);
-	kfree(server);
-}
-
-static struct file_system_type nfs_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs",
-	.get_sb		= nfs_get_sb,
-	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
 
 #ifdef CONFIG_NFS_V4
 
-static void nfs4_clear_inode(struct inode *);
-
-
-static struct super_operations nfs4_sops = { 
-	.alloc_inode	= nfs_alloc_inode,
-	.destroy_inode	= nfs_destroy_inode,
-	.write_inode	= nfs_write_inode,
-	.delete_inode	= nfs_delete_inode,
-	.statfs		= nfs_statfs,
-	.clear_inode	= nfs4_clear_inode,
-	.umount_begin	= nfs_umount_begin,
-	.show_options	= nfs_show_options,
-	.show_stats	= nfs_show_stats,
-};
-
 /*
  * Clean out any remaining NFSv4 state that might be left over due
  * to open() calls that passed nfs_atomic_lookup, but failed to call
  * nfs_open().
  */
-static void nfs4_clear_inode(struct inode *inode)
+void nfs4_clear_inode(struct inode *inode)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 
@@ -1888,365 +1063,9 @@
 		nfs4_close_state(state, state->state);
 	}
 }
-
-
-static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
-{
-	struct nfs_server *server;
-	struct nfs4_client *clp = NULL;
-	struct rpc_xprt *xprt = NULL;
-	struct rpc_clnt *clnt = NULL;
-	struct rpc_timeout timeparms;
-	rpc_authflavor_t authflavour;
-	int err = -EIO;
-
-	sb->s_blocksize_bits = 0;
-	sb->s_blocksize = 0;
-	server = NFS_SB(sb);
-	if (data->rsize != 0)
-		server->rsize = nfs_block_size(data->rsize, NULL);
-	if (data->wsize != 0)
-		server->wsize = nfs_block_size(data->wsize, NULL);
-	server->flags = data->flags & NFS_MOUNT_FLAGMASK;
-	server->caps = NFS_CAP_ATOMIC_OPEN;
-
-	server->acregmin = data->acregmin*HZ;
-	server->acregmax = data->acregmax*HZ;
-	server->acdirmin = data->acdirmin*HZ;
-	server->acdirmax = data->acdirmax*HZ;
-
-	server->rpc_ops = &nfs_v4_clientops;
-
-	nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
-
-	server->retrans_timeo = timeparms.to_initval;
-	server->retrans_count = timeparms.to_retries;
-
-	clp = nfs4_get_client(&server->addr.sin_addr);
-	if (!clp) {
-		dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	/* Now create transport and client */
-	authflavour = RPC_AUTH_UNIX;
-	if (data->auth_flavourlen != 0) {
-		if (data->auth_flavourlen != 1) {
-			dprintk("%s: Invalid number of RPC auth flavours %d.\n",
-					__FUNCTION__, data->auth_flavourlen);
-			err = -EINVAL;
-			goto out_fail;
-		}
-		if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
-			err = -EFAULT;
-			goto out_fail;
-		}
-	}
-
-	down_write(&clp->cl_sem);
-	if (IS_ERR(clp->cl_rpcclient)) {
-		xprt = xprt_create_proto(data->proto, &server->addr, &timeparms);
-		if (IS_ERR(xprt)) {
-			up_write(&clp->cl_sem);
-			err = PTR_ERR(xprt);
-			dprintk("%s: cannot create RPC transport. Error = %d\n",
-					__FUNCTION__, err);
-			goto out_fail;
-		}
-		clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
-				server->rpc_ops->version, authflavour);
-		if (IS_ERR(clnt)) {
-			up_write(&clp->cl_sem);
-			err = PTR_ERR(clnt);
-			dprintk("%s: cannot create RPC client. Error = %d\n",
-					__FUNCTION__, err);
-			goto out_fail;
-		}
-		clnt->cl_intr     = 1;
-		clnt->cl_softrtry = 1;
-		clp->cl_rpcclient = clnt;
-		memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
-		nfs_idmap_new(clp);
-	}
-	list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
-	clnt = rpc_clone_client(clp->cl_rpcclient);
-	if (!IS_ERR(clnt))
-			server->nfs4_state = clp;
-	up_write(&clp->cl_sem);
-	clp = NULL;
-
-	if (IS_ERR(clnt)) {
-		err = PTR_ERR(clnt);
-		dprintk("%s: cannot create RPC client. Error = %d\n",
-				__FUNCTION__, err);
-		return err;
-	}
-
-	server->client    = clnt;
-
-	if (server->nfs4_state->cl_idmap == NULL) {
-		dprintk("%s: failed to create idmapper.\n", __FUNCTION__);
-		return -ENOMEM;
-	}
-
-	if (clnt->cl_auth->au_flavor != authflavour) {
-		struct rpc_auth *auth;
-
-		auth = rpcauth_create(authflavour, clnt);
-		if (IS_ERR(auth)) {
-			dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
-			return PTR_ERR(auth);
-		}
-	}
-
-	sb->s_time_gran = 1;
-
-	sb->s_op = &nfs4_sops;
-	err = nfs_sb_init(sb, authflavour);
-	if (err == 0)
-		return 0;
-out_fail:
-	if (clp)
-		nfs4_put_client(clp);
-	return err;
-}
-
-static int nfs4_compare_super(struct super_block *sb, void *data)
-{
-	struct nfs_server *server = data;
-	struct nfs_server *old = NFS_SB(sb);
-
-	if (strcmp(server->hostname, old->hostname) != 0)
-		return 0;
-	if (strcmp(server->mnt_path, old->mnt_path) != 0)
-		return 0;
-	return 1;
-}
-
-static void *
-nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
-{
-	void *p = NULL;
-
-	if (!src->len)
-		return ERR_PTR(-EINVAL);
-	if (src->len < maxlen)
-		maxlen = src->len;
-	if (dst == NULL) {
-		p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
-		if (p == NULL)
-			return ERR_PTR(-ENOMEM);
-	}
-	if (copy_from_user(dst, src->data, maxlen)) {
-		kfree(p);
-		return ERR_PTR(-EFAULT);
-	}
-	dst[maxlen] = '\0';
-	return dst;
-}
-
-static int nfs4_get_sb(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
-{
-	int error;
-	struct nfs_server *server;
-	struct super_block *s;
-	struct nfs4_mount_data *data = raw_data;
-	void *p;
-
-	if (data == NULL) {
-		dprintk("%s: missing data argument\n", __FUNCTION__);
-		return -EINVAL;
-	}
-	if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
-		dprintk("%s: bad mount version\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
-	if (!server)
-		return -ENOMEM;
-	/* Zero out the NFS state stuff */
-	init_nfsv4_state(server);
-	server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
-
-	p = nfs_copy_user_string(NULL, &data->hostname, 256);
-	if (IS_ERR(p))
-		goto out_err;
-	server->hostname = p;
-
-	p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
-	if (IS_ERR(p))
-		goto out_err;
-	server->mnt_path = p;
-
-	p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
-			sizeof(server->ip_addr) - 1);
-	if (IS_ERR(p))
-		goto out_err;
-
-	/* We now require that the mount process passes the remote address */
-	if (data->host_addrlen != sizeof(server->addr)) {
-		error = -EINVAL;
-		goto out_free;
-	}
-	if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
-		error = -EFAULT;
-		goto out_free;
-	}
-	if (server->addr.sin_family != AF_INET ||
-	    server->addr.sin_addr.s_addr == INADDR_ANY) {
-		dprintk("%s: mount program didn't pass remote IP address!\n",
-				__FUNCTION__);
-		error = -EINVAL;
-		goto out_free;
-	}
-
-	/* Fire up rpciod if not yet running */
-	error = rpciod_up();
-	if (error < 0) {
-		dprintk("%s: couldn't start rpciod! Error = %d\n",
-				__FUNCTION__, error);
-		goto out_free;
-	}
-
-	s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
-	if (IS_ERR(s)) {
-		error = PTR_ERR(s);
-		goto out_free;
-	}
-
-	if (s->s_root) {
-		kfree(server->mnt_path);
-		kfree(server->hostname);
-		kfree(server);
-		return simple_set_mnt(mnt, s);
-	}
-
-	s->s_flags = flags;
-
-	error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
-	if (error) {
-		up_write(&s->s_umount);
-		deactivate_super(s);
-		return error;
-	}
-	s->s_flags |= MS_ACTIVE;
-	return simple_set_mnt(mnt, s);
-out_err:
-	error = PTR_ERR(p);
-out_free:
-	kfree(server->mnt_path);
-	kfree(server->hostname);
-	kfree(server);
-	return error;
-}
-
-static void nfs4_kill_super(struct super_block *sb)
-{
-	struct nfs_server *server = NFS_SB(sb);
-
-	nfs_return_all_delegations(sb);
-	kill_anon_super(sb);
-
-	nfs4_renewd_prepare_shutdown(server);
-
-	if (server->client != NULL && !IS_ERR(server->client))
-		rpc_shutdown_client(server->client);
-
-	destroy_nfsv4_state(server);
-
-	rpciod_down();
-
-	nfs_free_iostats(server->io_stats);
-	kfree(server->hostname);
-	kfree(server);
-}
-
-static struct file_system_type nfs4_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "nfs4",
-	.get_sb		= nfs4_get_sb,
-	.kill_sb	= nfs4_kill_super,
-	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-static const int nfs_set_port_min = 0;
-static const int nfs_set_port_max = 65535;
-static int param_set_port(const char *val, struct kernel_param *kp)
-{
-	char *endp;
-	int num = simple_strtol(val, &endp, 0);
-	if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
-		return -EINVAL;
-	*((int *)kp->arg) = num;
-	return 0;
-}
-
-module_param_call(callback_tcpport, param_set_port, param_get_int,
-		 &nfs_callback_set_tcpport, 0644);
-
-static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
-{
-	char *endp;
-	int num = simple_strtol(val, &endp, 0);
-	int jif = num * HZ;
-	if (endp == val || *endp || num < 0 || jif < num)
-		return -EINVAL;
-	*((int *)kp->arg) = jif;
-	return 0;
-}
-
-module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
-		 &nfs_idmap_cache_timeout, 0644);
-
-#define nfs4_init_once(nfsi) \
-	do { \
-		INIT_LIST_HEAD(&(nfsi)->open_states); \
-		nfsi->delegation = NULL; \
-		nfsi->delegation_state = 0; \
-		init_rwsem(&nfsi->rwsem); \
-	} while(0)
-
-static inline int register_nfs4fs(void)
-{
-	int ret;
-
-	ret = nfs_register_sysctl();
-	if (ret != 0)
-		return ret;
-	ret = register_filesystem(&nfs4_fs_type);
-	if (ret != 0)
-		nfs_unregister_sysctl();
-	return ret;
-}
-
-static inline void unregister_nfs4fs(void)
-{
-	unregister_filesystem(&nfs4_fs_type);
-	nfs_unregister_sysctl();
-}
-#else
-#define nfs4_init_once(nfsi) \
-	do { } while (0)
-#define register_nfs4fs() (0)
-#define unregister_nfs4fs()
 #endif
 
-extern int nfs_init_nfspagecache(void);
-extern void nfs_destroy_nfspagecache(void);
-extern int nfs_init_readpagecache(void);
-extern void nfs_destroy_readpagecache(void);
-extern int nfs_init_writepagecache(void);
-extern void nfs_destroy_writepagecache(void);
-#ifdef CONFIG_NFS_DIRECTIO
-extern int nfs_init_directcache(void);
-extern void nfs_destroy_directcache(void);
-#endif
-
-static kmem_cache_t * nfs_inode_cachep;
-
-static struct inode *nfs_alloc_inode(struct super_block *sb)
+struct inode *nfs_alloc_inode(struct super_block *sb)
 {
 	struct nfs_inode *nfsi;
 	nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL);
@@ -2265,11 +1084,21 @@
 	return &nfsi->vfs_inode;
 }
 
-static void nfs_destroy_inode(struct inode *inode)
+void nfs_destroy_inode(struct inode *inode)
 {
 	kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
 }
 
+static inline void nfs4_init_once(struct nfs_inode *nfsi)
+{
+#ifdef CONFIG_NFS_V4
+	INIT_LIST_HEAD(&nfsi->open_states);
+	nfsi->delegation = NULL;
+	nfsi->delegation_state = 0;
+	init_rwsem(&nfsi->rwsem);
+#endif
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
 	struct nfs_inode *nfsi = (struct nfs_inode *) foo;
@@ -2290,7 +1119,7 @@
 	}
 }
  
-static int nfs_init_inodecache(void)
+static int __init nfs_init_inodecache(void)
 {
 	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
 					     sizeof(struct nfs_inode),
@@ -2303,7 +1132,7 @@
 	return 0;
 }
 
-static void nfs_destroy_inodecache(void)
+static void __exit nfs_destroy_inodecache(void)
 {
 	if (kmem_cache_destroy(nfs_inode_cachep))
 		printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
@@ -2332,29 +1161,22 @@
 	if (err)
 		goto out1;
 
-#ifdef CONFIG_NFS_DIRECTIO
 	err = nfs_init_directcache();
 	if (err)
 		goto out0;
-#endif
 
 #ifdef CONFIG_PROC_FS
 	rpc_proc_register(&nfs_rpcstat);
 #endif
-        err = register_filesystem(&nfs_fs_type);
-	if (err)
-		goto out;
-	if ((err = register_nfs4fs()) != 0)
+	if ((err = register_nfs_fs()) != 0)
 		goto out;
 	return 0;
 out:
 #ifdef CONFIG_PROC_FS
 	rpc_proc_unregister("nfs");
 #endif
-#ifdef CONFIG_NFS_DIRECTIO
 	nfs_destroy_directcache();
 out0:
-#endif
 	nfs_destroy_writepagecache();
 out1:
 	nfs_destroy_readpagecache();
@@ -2368,9 +1190,7 @@
 
 static void __exit exit_nfs_fs(void)
 {
-#ifdef CONFIG_NFS_DIRECTIO
 	nfs_destroy_directcache();
-#endif
 	nfs_destroy_writepagecache();
 	nfs_destroy_readpagecache();
 	nfs_destroy_inodecache();
@@ -2378,8 +1198,7 @@
 #ifdef CONFIG_PROC_FS
 	rpc_proc_unregister("nfs");
 #endif
-	unregister_filesystem(&nfs_fs_type);
-	unregister_nfs4fs();
+	unregister_nfs_fs();
 }
 
 /* Not quite true; I just maintain it */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
new file mode 100644
index 0000000..bd2815e
--- /dev/null
+++ b/fs/nfs/internal.h
@@ -0,0 +1,186 @@
+/*
+ * NFS internal definitions
+ */
+
+#include <linux/mount.h>
+
+struct nfs_clone_mount {
+	const struct super_block *sb;
+	const struct dentry *dentry;
+	struct nfs_fh *fh;
+	struct nfs_fattr *fattr;
+	char *hostname;
+	char *mnt_path;
+	struct sockaddr_in *addr;
+	rpc_authflavor_t authflavor;
+};
+
+/* namespace-nfs4.c */
+#ifdef CONFIG_NFS_V4
+extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
+#else
+static inline
+struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
+{
+	return ERR_PTR(-ENOENT);
+}
+#endif
+
+/* callback_xdr.c */
+extern struct svc_version nfs4_callback_version1;
+
+/* pagelist.c */
+extern int __init nfs_init_nfspagecache(void);
+extern void __exit nfs_destroy_nfspagecache(void);
+extern int __init nfs_init_readpagecache(void);
+extern void __exit nfs_destroy_readpagecache(void);
+extern int __init nfs_init_writepagecache(void);
+extern void __exit nfs_destroy_writepagecache(void);
+
+#ifdef CONFIG_NFS_DIRECTIO
+extern int __init nfs_init_directcache(void);
+extern void __exit nfs_destroy_directcache(void);
+#else
+#define nfs_init_directcache() (0)
+#define nfs_destroy_directcache() do {} while(0)
+#endif
+
+/* nfs2xdr.c */
+extern struct rpc_procinfo nfs_procedures[];
+extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+
+/* nfs3xdr.c */
+extern struct rpc_procinfo nfs3_procedures[];
+extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
+
+/* nfs4xdr.c */
+extern int nfs_stat_to_errno(int);
+extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
+
+/* nfs4proc.c */
+#ifdef CONFIG_NFS_V4
+extern struct rpc_procinfo nfs4_procedures[];
+
+extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+				  struct nfs4_fs_locations *fs_locations,
+				  struct page *page);
+#endif
+
+/* inode.c */
+extern struct inode *nfs_alloc_inode(struct super_block *sb);
+extern void nfs_destroy_inode(struct inode *);
+extern int nfs_write_inode(struct inode *,int);
+extern void nfs_clear_inode(struct inode *);
+#ifdef CONFIG_NFS_V4
+extern void nfs4_clear_inode(struct inode *);
+#endif
+
+/* super.c */
+extern struct file_system_type nfs_referral_nfs4_fs_type;
+extern struct file_system_type clone_nfs_fs_type;
+#ifdef CONFIG_NFS_V4
+extern struct file_system_type clone_nfs4_fs_type;
+#endif
+#ifdef CONFIG_PROC_FS
+extern struct rpc_stat nfs_rpcstat;
+#endif
+extern int __init register_nfs_fs(void);
+extern void __exit unregister_nfs_fs(void);
+
+/* namespace.c */
+extern char *nfs_path(const char *base, const struct dentry *dentry,
+		      char *buffer, ssize_t buflen);
+
+/*
+ * Determine the mount path as a string
+ */
+static inline char *
+nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
+{
+#ifdef CONFIG_NFS_V4
+	return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
+#else
+	return NULL;
+#endif
+}
+
+/*
+ * Determine the device name as a string
+ */
+static inline char *nfs_devname(const struct vfsmount *mnt_parent,
+			 const struct dentry *dentry,
+			 char *buffer, ssize_t buflen)
+{
+	return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
+}
+
+/*
+ * Determine the actual block size (and log2 thereof)
+ */
+static inline
+unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
+{
+	/* make sure blocksize is a power of two */
+	if ((bsize & (bsize - 1)) || nrbitsp) {
+		unsigned char	nrbits;
+
+		for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
+			;
+		bsize = 1 << nrbits;
+		if (nrbitsp)
+			*nrbitsp = nrbits;
+	}
+
+	return bsize;
+}
+
+/*
+ * Calculate the number of 512byte blocks used.
+ */
+static inline unsigned long nfs_calc_block_size(u64 tsize)
+{
+	loff_t used = (tsize + 511) >> 9;
+	return (used > ULONG_MAX) ? ULONG_MAX : used;
+}
+
+/*
+ * Compute and set NFS server blocksize
+ */
+static inline
+unsigned long nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
+{
+	if (bsize < NFS_MIN_FILE_IO_SIZE)
+		bsize = NFS_DEF_FILE_IO_SIZE;
+	else if (bsize >= NFS_MAX_FILE_IO_SIZE)
+		bsize = NFS_MAX_FILE_IO_SIZE;
+
+	return nfs_block_bits(bsize, nrbitsp);
+}
+
+/*
+ * Determine the maximum file size for a superblock
+ */
+static inline
+void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
+{
+	sb->s_maxbytes = (loff_t)maxfilesize;
+	if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
+		sb->s_maxbytes = MAX_LFS_FILESIZE;
+}
+
+/*
+ * Check if the string represents a "valid" IPv4 address
+ */
+static inline int valid_ipaddr4(const char *buf)
+{
+	int rc, count, in[4];
+
+	rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
+	if (rc != 4)
+		return -EINVAL;
+	for (count = 0; count < 4; count++) {
+		if (in[count] > 255)
+			return -EINVAL;
+	}
+	return 0;
+}
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
new file mode 100644
index 0000000..19b98ca
--- /dev/null
+++ b/fs/nfs/namespace.c
@@ -0,0 +1,229 @@
+/*
+ * linux/fs/nfs/namespace.c
+ *
+ * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ * NFS namespace
+ */
+
+#include <linux/config.h>
+
+#include <linux/dcache.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nfs_fs.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/vfs.h>
+#include "internal.h"
+
+#define NFSDBG_FACILITY		NFSDBG_VFS
+
+static void nfs_expire_automounts(void *list);
+
+LIST_HEAD(nfs_automount_list);
+static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
+int nfs_mountpoint_expiry_timeout = 500 * HZ;
+
+/*
+ * nfs_path - reconstruct the path given an arbitrary dentry
+ * @base - arbitrary string to prepend to the path
+ * @dentry - pointer to dentry
+ * @buffer - result buffer
+ * @buflen - length of buffer
+ *
+ * Helper function for constructing the path from the
+ * root dentry to an arbitrary hashed dentry.
+ *
+ * This is mainly for use in figuring out the path on the
+ * server side when automounting on top of an existing partition.
+ */
+char *nfs_path(const char *base, const struct dentry *dentry,
+	       char *buffer, ssize_t buflen)
+{
+	char *end = buffer+buflen;
+	int namelen;
+
+	*--end = '\0';
+	buflen--;
+	spin_lock(&dcache_lock);
+	while (!IS_ROOT(dentry)) {
+		namelen = dentry->d_name.len;
+		buflen -= namelen + 1;
+		if (buflen < 0)
+			goto Elong;
+		end -= namelen;
+		memcpy(end, dentry->d_name.name, namelen);
+		*--end = '/';
+		dentry = dentry->d_parent;
+	}
+	spin_unlock(&dcache_lock);
+	namelen = strlen(base);
+	/* Strip off excess slashes in base string */
+	while (namelen > 0 && base[namelen - 1] == '/')
+		namelen--;
+	buflen -= namelen;
+	if (buflen < 0)
+		goto Elong;
+	end -= namelen;
+	memcpy(end, base, namelen);
+	return end;
+Elong:
+	return ERR_PTR(-ENAMETOOLONG);
+}
+
+/*
+ * nfs_follow_mountpoint - handle crossing a mountpoint on the server
+ * @dentry - dentry of mountpoint
+ * @nd - nameidata info
+ *
+ * When we encounter a mountpoint on the server, we want to set up
+ * a mountpoint on the client too, to prevent inode numbers from
+ * colliding, and to allow "df" to work properly.
+ * On NFSv4, we also want to allow for the fact that different
+ * filesystems may be migrated to different servers in a failover
+ * situation, and that different filesystems may want to use
+ * different security flavours.
+ */
+static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+{
+	struct vfsmount *mnt;
+	struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+	struct dentry *parent;
+	struct nfs_fh fh;
+	struct nfs_fattr fattr;
+	int err;
+
+	BUG_ON(IS_ROOT(dentry));
+	dprintk("%s: enter\n", __FUNCTION__);
+	dput(nd->dentry);
+	nd->dentry = dget(dentry);
+	if (d_mountpoint(nd->dentry))
+		goto out_follow;
+	/* Look it up again */
+	parent = dget_parent(nd->dentry);
+	err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr);
+	dput(parent);
+	if (err != 0)
+		goto out_err;
+
+	if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL)
+		mnt = nfs_do_refmount(nd->mnt, nd->dentry);
+	else
+		mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr);
+	err = PTR_ERR(mnt);
+	if (IS_ERR(mnt))
+		goto out_err;
+
+	mntget(mnt);
+	err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list);
+	if (err < 0) {
+		mntput(mnt);
+		if (err == -EBUSY)
+			goto out_follow;
+		goto out_err;
+	}
+	mntput(nd->mnt);
+	dput(nd->dentry);
+	nd->mnt = mnt;
+	nd->dentry = dget(mnt->mnt_root);
+	schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+out:
+	dprintk("%s: done, returned %d\n", __FUNCTION__, err);
+	return ERR_PTR(err);
+out_err:
+	path_release(nd);
+	goto out;
+out_follow:
+	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+		;
+	err = 0;
+	goto out;
+}
+
+struct inode_operations nfs_mountpoint_inode_operations = {
+	.follow_link	= nfs_follow_mountpoint,
+	.getattr	= nfs_getattr,
+};
+
+struct inode_operations nfs_referral_inode_operations = {
+	.follow_link	= nfs_follow_mountpoint,
+};
+
+static void nfs_expire_automounts(void *data)
+{
+	struct list_head *list = (struct list_head *)data;
+
+	mark_mounts_for_expiry(list);
+	if (!list_empty(list))
+		schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+}
+
+void nfs_release_automount_timer(void)
+{
+	if (list_empty(&nfs_automount_list)) {
+		cancel_delayed_work(&nfs_automount_task);
+		flush_scheduled_work();
+	}
+}
+
+/*
+ * Clone a mountpoint of the appropriate type
+ */
+static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname,
+					   struct nfs_clone_mount *mountdata)
+{
+#ifdef CONFIG_NFS_V4
+	struct vfsmount *mnt = NULL;
+	switch (server->rpc_ops->version) {
+		case 2:
+		case 3:
+			mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
+			break;
+		case 4:
+			mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
+	}
+	return mnt;
+#else
+	return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
+#endif
+}
+
+/**
+ * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
+ * @mnt_parent - mountpoint of parent directory
+ * @dentry - parent directory
+ * @fh - filehandle for new root dentry
+ * @fattr - attributes for new root inode
+ *
+ */
+struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+		const struct dentry *dentry, struct nfs_fh *fh,
+		struct nfs_fattr *fattr)
+{
+	struct nfs_clone_mount mountdata = {
+		.sb = mnt_parent->mnt_sb,
+		.dentry = dentry,
+		.fh = fh,
+		.fattr = fattr,
+	};
+	struct vfsmount *mnt = ERR_PTR(-ENOMEM);
+	char *page = (char *) __get_free_page(GFP_USER);
+	char *devname;
+
+	dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
+			dentry->d_parent->d_name.name,
+			dentry->d_name.name);
+	if (page == NULL)
+		goto out;
+	devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
+	mnt = (struct vfsmount *)devname;
+	if (IS_ERR(devname))
+		goto free_page;
+	mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata);
+free_page:
+	free_page((unsigned long)page);
+out:
+	dprintk("%s: done\n", __FUNCTION__);
+	return mnt;
+}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index f0015fa..67391ee 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -23,12 +23,11 @@
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
+#include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_XDR
 /* #define NFS_PARANOIA 1 */
 
-extern int			nfs_stat_to_errno(int stat);
-
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
 
@@ -131,7 +130,8 @@
 	fattr->du.nfs2.blocksize = ntohl(*p++);
 	rdev = ntohl(*p++);
 	fattr->du.nfs2.blocks = ntohl(*p++);
-	fattr->fsid_u.nfs3 = ntohl(*p++);
+	fattr->fsid.major = ntohl(*p++);
+	fattr->fsid.minor = 0;
 	fattr->fileid = ntohl(*p++);
 	p = xdr_decode_time(p, &fattr->atime);
 	p = xdr_decode_time(p, &fattr->mtime);
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 3328787..7322da4 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -172,8 +172,10 @@
 		inode->i_ino, acl, dfacl);
 	spin_lock(&inode->i_lock);
 	__nfs3_forget_cached_acls(NFS_I(inode));
-	nfsi->acl_access = posix_acl_dup(acl);
-	nfsi->acl_default = posix_acl_dup(dfacl);
+	if (!IS_ERR(acl))
+		nfsi->acl_access = posix_acl_dup(acl);
+	if (!IS_ERR(dfacl))
+		nfsi->acl_default = posix_acl_dup(dfacl);
 	spin_unlock(&inode->i_lock);
 }
 
@@ -254,7 +256,9 @@
 			res.acl_access = NULL;
 		}
 	}
-	nfs3_cache_acls(inode, res.acl_access, res.acl_default);
+	nfs3_cache_acls(inode,
+		(res.mask & NFS_ACL)   ? res.acl_access  : ERR_PTR(-EINVAL),
+		(res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL));
 
 	switch(type) {
 		case ACL_TYPE_ACCESS:
@@ -329,6 +333,7 @@
 	switch (status) {
 		case 0:
 			status = nfs_refresh_inode(inode, &fattr);
+			nfs3_cache_acls(inode, acl, dfacl);
 			break;
 		case -EPFNOSUPPORT:
 		case -EPROTONOSUPPORT:
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index cf186f0..7143b1f 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -20,11 +20,10 @@
 #include <linux/nfs_mount.h>
 
 #include "iostat.h"
+#include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
-extern struct rpc_procinfo nfs3_procedures[];
-
 /* A wrapper to handle the EJUKEBOX error message */
 static int
 nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
@@ -809,8 +808,6 @@
 	return status;
 }
 
-extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
-
 static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
 {
 	if (nfs3_async_handle_jukebox(task, data->inode))
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index ec23361..0250269 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -22,14 +22,13 @@
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfsacl.h>
+#include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
 
-extern int			nfs_stat_to_errno(int);
-
 /*
  * Declare the space requirements for NFS arguments and replies as
  * number of 32bit-words
@@ -166,7 +165,8 @@
 	if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
 		fattr->rdev = 0;
 
-	p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
+	p = xdr_decode_hyper(p, &fattr->fsid.major);
+	fattr->fsid.minor = 0;
 	p = xdr_decode_hyper(p, &fattr->fileid);
 	p = xdr_decode_time3(p, &fattr->atime);
 	p = xdr_decode_time3(p, &fattr->mtime);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 0f5e4e7..9a10286 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -217,6 +217,9 @@
 extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
 extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
 extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
+extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
+extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+		struct nfs4_fs_locations *fs_locations, struct page *page);
 
 extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
 extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
@@ -225,6 +228,7 @@
 extern const u32 nfs4_statfs_bitmap[2];
 extern const u32 nfs4_pathconf_bitmap[2];
 extern const u32 nfs4_fsinfo_bitmap[2];
+extern const u32 nfs4_fs_locations_bitmap[2];
 
 /* nfs4renewd.c */
 extern void nfs4_schedule_state_renewal(struct nfs4_client *);
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
new file mode 100644
index 0000000..ea38d27
--- /dev/null
+++ b/fs/nfs/nfs4namespace.c
@@ -0,0 +1,201 @@
+/*
+ * linux/fs/nfs/nfs4namespace.c
+ *
+ * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ * NFSv4 namespace
+ */
+
+#include <linux/config.h>
+
+#include <linux/dcache.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/nfs_fs.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/vfs.h>
+#include <linux/inet.h>
+#include "internal.h"
+
+#define NFSDBG_FACILITY		NFSDBG_VFS
+
+/*
+ * Check if fs_root is valid
+ */
+static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
+					 char *buffer, ssize_t buflen)
+{
+	char *end = buffer + buflen;
+	int n;
+
+	*--end = '\0';
+	buflen--;
+
+	n = pathname->ncomponents;
+	while (--n >= 0) {
+		struct nfs4_string *component = &pathname->components[n];
+		buflen -= component->len + 1;
+		if (buflen < 0)
+			goto Elong;
+		end -= component->len;
+		memcpy(end, component->data, component->len);
+		*--end = '/';
+	}
+	return end;
+Elong:
+	return ERR_PTR(-ENAMETOOLONG);
+}
+
+
+/**
+ * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
+ * @mnt_parent - mountpoint of parent directory
+ * @dentry - parent directory
+ * @fspath - fs path returned in fs_locations
+ * @mntpath - mount path to new server
+ * @hostname - hostname of new server
+ * @addr - host addr of new server
+ *
+ */
+static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
+					    const struct dentry *dentry,
+					    struct nfs4_fs_locations *locations)
+{
+	struct vfsmount *mnt = ERR_PTR(-ENOENT);
+	struct nfs_clone_mount mountdata = {
+		.sb = mnt_parent->mnt_sb,
+		.dentry = dentry,
+		.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
+	};
+	char *page, *page2;
+	char *path, *fs_path;
+	char *devname;
+	int loc, s;
+
+	if (locations == NULL || locations->nlocations <= 0)
+		goto out;
+
+	dprintk("%s: referral at %s/%s\n", __FUNCTION__,
+		dentry->d_parent->d_name.name, dentry->d_name.name);
+
+	/* Ensure fs path is a prefix of current dentry path */
+	page = (char *) __get_free_page(GFP_USER);
+	if (page == NULL)
+		goto out;
+	page2 = (char *) __get_free_page(GFP_USER);
+	if (page2 == NULL)
+		goto out;
+
+	path = nfs4_path(dentry, page, PAGE_SIZE);
+	if (IS_ERR(path))
+		goto out_free;
+
+	fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
+	if (IS_ERR(fs_path))
+		goto out_free;
+
+	if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
+		dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
+		goto out_free;
+	}
+
+	devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
+	if (IS_ERR(devname)) {
+		mnt = (struct vfsmount *)devname;
+		goto out_free;
+	}
+
+	loc = 0;
+	while (loc < locations->nlocations && IS_ERR(mnt)) {
+		struct nfs4_fs_location *location = &locations->locations[loc];
+		char *mnt_path;
+
+		if (location == NULL || location->nservers <= 0 ||
+		    location->rootpath.ncomponents == 0) {
+			loc++;
+			continue;
+		}
+
+		mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
+		if (IS_ERR(mnt_path)) {
+			loc++;
+			continue;
+		}
+		mountdata.mnt_path = mnt_path;
+
+		s = 0;
+		while (s < location->nservers) {
+			struct sockaddr_in addr = {};
+
+			if (location->servers[s].len <= 0 ||
+			    valid_ipaddr4(location->servers[s].data) < 0) {
+				s++;
+				continue;
+			}
+
+			mountdata.hostname = location->servers[s].data;
+			addr.sin_addr.s_addr = in_aton(mountdata.hostname);
+			addr.sin_family = AF_INET;
+			addr.sin_port = htons(NFS_PORT);
+			mountdata.addr = &addr;
+
+			mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
+			if (!IS_ERR(mnt)) {
+				break;
+			}
+			s++;
+		}
+		loc++;
+	}
+
+out_free:
+	free_page((unsigned long)page);
+	free_page((unsigned long)page2);
+out:
+	dprintk("%s: done\n", __FUNCTION__);
+	return mnt;
+}
+
+/*
+ * nfs_do_refmount - handle crossing a referral on server
+ * @dentry - dentry of referral
+ * @nd - nameidata info
+ *
+ */
+struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
+{
+	struct vfsmount *mnt = ERR_PTR(-ENOENT);
+	struct dentry *parent;
+	struct nfs4_fs_locations *fs_locations = NULL;
+	struct page *page;
+	int err;
+
+	/* BUG_ON(IS_ROOT(dentry)); */
+	dprintk("%s: enter\n", __FUNCTION__);
+
+	page = alloc_page(GFP_KERNEL);
+	if (page == NULL)
+		goto out;
+
+	fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
+	if (fs_locations == NULL)
+		goto out_free;
+
+	/* Get locations */
+	parent = dget_parent(dentry);
+	dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
+	err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
+	dput(parent);
+	if (err != 0 || fs_locations->nlocations <= 0 ||
+	    fs_locations->fs_path.ncomponents <= 0)
+		goto out_free;
+
+	mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations);
+out_free:
+	__free_page(page);
+	kfree(fs_locations);
+out:
+	dprintk("%s: done\n", __FUNCTION__);
+	return mnt;
+}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d86c0db..b4916b0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -65,8 +65,6 @@
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
 static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
 static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
-extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
-extern struct rpc_procinfo nfs4_procedures[];
 
 /* Prevent leaks of NFSv4 errors into userland */
 int nfs4_map_errors(int err)
@@ -121,6 +119,25 @@
 			0
 };
 
+const u32 nfs4_fs_locations_bitmap[2] = {
+	FATTR4_WORD0_TYPE
+	| FATTR4_WORD0_CHANGE
+	| FATTR4_WORD0_SIZE
+	| FATTR4_WORD0_FSID
+	| FATTR4_WORD0_FILEID
+	| FATTR4_WORD0_FS_LOCATIONS,
+	FATTR4_WORD1_MODE
+	| FATTR4_WORD1_NUMLINKS
+	| FATTR4_WORD1_OWNER
+	| FATTR4_WORD1_OWNER_GROUP
+	| FATTR4_WORD1_RAWDEV
+	| FATTR4_WORD1_SPACE_USED
+	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_METADATA
+	| FATTR4_WORD1_TIME_MODIFY
+	| FATTR4_WORD1_MOUNTED_ON_FILEID
+};
+
 static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
 		struct nfs4_readdir_arg *readdir)
 {
@@ -185,15 +202,15 @@
 	spin_unlock(&clp->cl_lock);
 }
 
-static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo)
+static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
 {
-	struct nfs_inode *nfsi = NFS_I(inode);
+	struct nfs_inode *nfsi = NFS_I(dir);
 
-	spin_lock(&inode->i_lock);
-	nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
+	spin_lock(&dir->i_lock);
+	nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
 	if (cinfo->before == nfsi->change_attr && cinfo->atomic)
 		nfsi->change_attr = cinfo->after;
-	spin_unlock(&inode->i_lock);
+	spin_unlock(&dir->i_lock);
 }
 
 struct nfs4_opendata {
@@ -1331,7 +1348,7 @@
 	return status;
 }
 
-static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
+int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 {
 	struct nfs4_exception exception = { };
 	int err;
@@ -1443,6 +1460,50 @@
 	return nfs4_map_errors(status);
 }
 
+/*
+ * Get locations and (maybe) other attributes of a referral.
+ * Note that we'll actually follow the referral later when
+ * we detect fsid mismatch in inode revalidation
+ */
+static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+{
+	int status = -ENOMEM;
+	struct page *page = NULL;
+	struct nfs4_fs_locations *locations = NULL;
+	struct dentry dentry = {};
+
+	page = alloc_page(GFP_KERNEL);
+	if (page == NULL)
+		goto out;
+	locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
+	if (locations == NULL)
+		goto out;
+
+	dentry.d_name.name = name->name;
+	dentry.d_name.len = name->len;
+	status = nfs4_proc_fs_locations(dir, &dentry, locations, page);
+	if (status != 0)
+		goto out;
+	/* Make sure server returned a different fsid for the referral */
+	if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
+		dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name);
+		status = -EIO;
+		goto out;
+	}
+
+	memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
+	fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL;
+	if (!fattr->mode)
+		fattr->mode = S_IFDIR;
+	memset(fhandle, 0, sizeof(struct nfs_fh));
+out:
+	if (page)
+		__free_page(page);
+	if (locations)
+		kfree(locations);
+	return status;
+}
+
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs4_getattr_arg args = {
@@ -1547,6 +1608,8 @@
 	
 	dprintk("NFS call  lookup %s\n", name->name);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	if (status == -NFS4ERR_MOVED)
+		status = nfs4_get_referral(dir, name, fattr, fhandle);
 	dprintk("NFS reply lookup: %d\n", status);
 	return status;
 }
@@ -2008,7 +2071,7 @@
 	if (!status) {
 		update_changeattr(dir, &res.cinfo);
 		nfs_post_op_update_inode(dir, res.dir_attr);
-		nfs_refresh_inode(inode, res.fattr);
+		nfs_post_op_update_inode(inode, res.fattr);
 	}
 
 	return status;
@@ -3570,6 +3633,36 @@
 	return len;
 }
 
+int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
+		struct nfs4_fs_locations *fs_locations, struct page *page)
+{
+	struct nfs_server *server = NFS_SERVER(dir);
+	u32 bitmask[2] = {
+		[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
+		[1] = FATTR4_WORD1_MOUNTED_ON_FILEID,
+	};
+	struct nfs4_fs_locations_arg args = {
+		.dir_fh = NFS_FH(dir),
+		.name = &dentry->d_name,
+		.page = page,
+		.bitmask = bitmask,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
+		.rpc_argp = &args,
+		.rpc_resp = fs_locations,
+	};
+	int status;
+
+	dprintk("%s: start\n", __FUNCTION__);
+	fs_locations->fattr.valid = 0;
+	fs_locations->server = server;
+	fs_locations->nlocations = 0;
+	status = rpc_call_sync(server->client, &msg, 0);
+	dprintk("%s: returned status = %d\n", __FUNCTION__, status);
+	return status;
+}
+
 struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
 	.recover_open	= nfs4_open_reclaim,
 	.recover_lock	= nfs4_lock_reclaim,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 7c5d70e..1750d99 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -411,6 +411,15 @@
 #define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
 				op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+#define NFS4_enc_fs_locations_sz \
+				(compound_encode_hdr_maxsz + \
+				 encode_putfh_maxsz + \
+				 encode_getattr_maxsz)
+#define NFS4_dec_fs_locations_sz \
+				(compound_decode_hdr_maxsz + \
+				 decode_putfh_maxsz + \
+				 op_decode_hdr_maxsz + \
+				 nfs4_fattr_bitmap_maxsz)
 
 static struct {
 	unsigned int	mode;
@@ -722,6 +731,13 @@
 			bitmask[1] & nfs4_fsinfo_bitmap[1]);
 }
 
+static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
+{
+	return encode_getattr_two(xdr,
+				  bitmask[0] & nfs4_fs_locations_bitmap[0],
+				  bitmask[1] & nfs4_fs_locations_bitmap[1]);
+}
+
 static int encode_getfh(struct xdr_stream *xdr)
 {
 	uint32_t *p;
@@ -2003,6 +2019,38 @@
 }
 
 /*
+ * Encode FS_LOCATIONS request
+ */
+static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 3,
+	};
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	int replen;
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+		goto out;
+	if ((status = encode_lookup(&xdr, args->name)) != 0)
+		goto out;
+	if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
+		goto out;
+	/* set up reply
+	 *   toplevel_status + OP_PUTFH + status
+	 *   + OP_LOOKUP + status + OP_GETATTR + status = 7
+	 */
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
+	xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
+			0, PAGE_SIZE);
+out:
+	return status;
+}
+
+/*
  * START OF "GENERIC" DECODE ROUTINES.
  *   These may look a little ugly since they are imported from a "generic"
  * set of XDR encode/decode routines which are intended to be shared by
@@ -2036,7 +2084,7 @@
 	} \
 } while (0)
 
-static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
+static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
 {
 	uint32_t *p;
 
@@ -2087,7 +2135,7 @@
 static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
 {
 	uint32_t *p;
-	uint32_t strlen;
+	unsigned int strlen;
 	char *str;
 
 	READ_BUF(12);
@@ -2217,7 +2265,7 @@
 	return 0;
 }
 
-static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
+static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
 {
 	uint32_t *p;
 
@@ -2285,6 +2333,22 @@
 	return 0;
 }
 
+static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+{
+	uint32_t *p;
+
+	*fileid = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
+		READ_BUF(8);
+		READ64(*fileid);
+		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+	}
+	dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
+	return 0;
+}
+
 static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
 	uint32_t *p;
@@ -2336,6 +2400,116 @@
 	return status;
 }
 
+static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
+{
+	int n;
+	uint32_t *p;
+	int status = 0;
+
+	READ_BUF(4);
+	READ32(n);
+	if (n < 0)
+		goto out_eio;
+	if (n == 0)
+		goto root_path;
+	dprintk("path ");
+	path->ncomponents = 0;
+	while (path->ncomponents < n) {
+		struct nfs4_string *component = &path->components[path->ncomponents];
+		status = decode_opaque_inline(xdr, &component->len, &component->data);
+		if (unlikely(status != 0))
+			goto out_eio;
+		if (path->ncomponents != n)
+			dprintk("/");
+		dprintk("%s", component->data);
+		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
+			path->ncomponents++;
+		else {
+			dprintk("cannot parse %d components in path\n", n);
+			goto out_eio;
+		}
+	}
+out:
+	dprintk("\n");
+	return status;
+root_path:
+/* a root pathname is sent as a zero component4 */
+	path->ncomponents = 1;
+	path->components[0].len=0;
+	path->components[0].data=NULL;
+	dprintk("path /\n");
+	goto out;
+out_eio:
+	dprintk(" status %d", status);
+	status = -EIO;
+	goto out;
+}
+
+static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
+{
+	int n;
+	uint32_t *p;
+	int status = -EIO;
+
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
+		goto out;
+	status = 0;
+	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
+		goto out;
+	dprintk("%s: fsroot ", __FUNCTION__);
+	status = decode_pathname(xdr, &res->fs_path);
+	if (unlikely(status != 0))
+		goto out;
+	READ_BUF(4);
+	READ32(n);
+	if (n <= 0)
+		goto out_eio;
+	res->nlocations = 0;
+	while (res->nlocations < n) {
+		int m;
+		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
+
+		READ_BUF(4);
+		READ32(m);
+		if (m <= 0)
+			goto out_eio;
+
+		loc->nservers = 0;
+		dprintk("%s: servers ", __FUNCTION__);
+		while (loc->nservers < m) {
+			struct nfs4_string *server = &loc->servers[loc->nservers];
+			status = decode_opaque_inline(xdr, &server->len, &server->data);
+			if (unlikely(status != 0))
+				goto out_eio;
+			dprintk("%s ", server->data);
+			if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
+				loc->nservers++;
+			else {
+				int i;
+				dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations);
+				for (i = loc->nservers; i < m; i++) {
+					int len;
+					char *data;
+					status = decode_opaque_inline(xdr, &len, &data);
+					if (unlikely(status != 0))
+						goto out_eio;
+				}
+			}
+		}
+		status = decode_pathname(xdr, &loc->rootpath);
+		if (unlikely(status != 0))
+			goto out_eio;
+		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
+			res->nlocations++;
+	}
+out:
+	dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
+	return status;
+out_eio:
+	status = -EIO;
+	goto out;
+}
+
 static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
 	uint32_t *p;
@@ -2841,6 +3015,7 @@
 		 bitmap[2] = {0},
 		 type;
 	int status, fmode = 0;
+	uint64_t fileid;
 
 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
 		goto xdr_error;
@@ -2863,10 +3038,14 @@
 		goto xdr_error;
 	if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
 		goto xdr_error;
-	if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0)
+	if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
 		goto xdr_error;
 	if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
 		goto xdr_error;
+	if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
+						struct nfs4_fs_locations,
+						fattr))) != 0)
+		goto xdr_error;
 	if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
 		goto xdr_error;
 	fattr->mode |= fmode;
@@ -2886,6 +3065,10 @@
 		goto xdr_error;
 	if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
 		goto xdr_error;
+	if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
+		goto xdr_error;
+	if (fattr->fileid == 0 && fileid != 0)
+		fattr->fileid = fileid;
 	if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
 		fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
 xdr_error:
@@ -3350,8 +3533,7 @@
 					attrlen, recvd);
 			return -EINVAL;
 		}
-		if (attrlen <= *acl_len)
-			xdr_read_pages(xdr, attrlen);
+		xdr_read_pages(xdr, attrlen);
 		*acl_len = attrlen;
 	} else
 		status = -EOPNOTSUPP;
@@ -4211,6 +4393,29 @@
 	return status;
 }
 
+/*
+ * FS_LOCATIONS request
+ */
+static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (status != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_lookup(&xdr)) != 0)
+		goto out;
+	xdr_enter_page(&xdr, PAGE_SIZE);
+	status = decode_getfattr(&xdr, &res->fattr, res->server);
+out:
+	return status;
+}
+
 uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
 {
 	uint32_t bitmap[2] = {0};
@@ -4382,6 +4587,7 @@
   PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
   PROC(GETACL,		enc_getacl,	dec_getacl),
   PROC(SETACL,		enc_setacl,	dec_setacl),
+  PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
 };
 
 struct rpc_version		nfs_version4 = {
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 106aca3..ef94296 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -325,6 +325,7 @@
 
 /**
  * nfs_scan_list - Scan a list for matching requests
+ * @nfsi: NFS inode
  * @head: One of the NFS inode request lists
  * @dst: Destination list
  * @idx_start: lower bound of page->index to scan
@@ -336,14 +337,15 @@
  * The requests are *not* checked to ensure that they form a contiguous set.
  * You must be holding the inode's req_lock when calling this function
  */
-int
-nfs_scan_list(struct list_head *head, struct list_head *dst,
-	      unsigned long idx_start, unsigned int npages)
+int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
+		struct list_head *dst, unsigned long idx_start,
+		unsigned int npages)
 {
-	struct list_head	*pos, *tmp;
-	struct nfs_page		*req;
-	unsigned long		idx_end;
-	int			res;
+	struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
+	struct nfs_page *req;
+	unsigned long idx_end;
+	int found, i;
+	int res;
 
 	res = 0;
 	if (npages == 0)
@@ -351,25 +353,32 @@
 	else
 		idx_end = idx_start + npages - 1;
 
-	list_for_each_safe(pos, tmp, head) {
-
-		req = nfs_list_entry(pos);
-
-		if (req->wb_index < idx_start)
-			continue;
-		if (req->wb_index > idx_end)
+	for (;;) {
+		found = radix_tree_gang_lookup(&nfsi->nfs_page_tree,
+				(void **)&pgvec[0], idx_start,
+				NFS_SCAN_MAXENTRIES);
+		if (found <= 0)
 			break;
+		for (i = 0; i < found; i++) {
+			req = pgvec[i];
+			if (req->wb_index > idx_end)
+				goto out;
+			idx_start = req->wb_index + 1;
+			if (req->wb_list_head != head)
+				continue;
+			if (nfs_set_page_writeback_locked(req)) {
+				nfs_list_remove_request(req);
+				nfs_list_add_request(req, dst);
+				res++;
+			}
+		}
 
-		if (!nfs_set_page_writeback_locked(req))
-			continue;
-		nfs_list_remove_request(req);
-		nfs_list_add_request(req, dst);
-		res++;
 	}
+out:
 	return res;
 }
 
-int nfs_init_nfspagecache(void)
+int __init nfs_init_nfspagecache(void)
 {
 	nfs_page_cachep = kmem_cache_create("nfs_page",
 					    sizeof(struct nfs_page),
@@ -381,7 +390,7 @@
 	return 0;
 }
 
-void nfs_destroy_nfspagecache(void)
+void __exit nfs_destroy_nfspagecache(void)
 {
 	if (kmem_cache_destroy(nfs_page_cachep))
 		printk(KERN_INFO "nfs_page: not all structures were freed\n");
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 9dd85ca..b3899ea 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -44,11 +44,10 @@
 #include <linux/nfs_page.h>
 #include <linux/lockd/bind.h>
 #include <linux/smp_lock.h>
+#include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
-extern struct rpc_procinfo nfs_procedures[];
-
 /*
  * Bare-bones access to getattr: this is for nfs_read_super.
  */
@@ -611,8 +610,6 @@
 	return 0;
 }
 
-extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
-
 static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
 {
 	if (task->tk_status >= 0) {
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 624ca71..41c2ffe 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -51,14 +51,11 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
-		if (pagecount < NFS_PAGEVEC_SIZE)
-			p->pagevec = &p->page_array[0];
+		if (pagecount <= ARRAY_SIZE(p->page_array))
+			p->pagevec = p->page_array;
 		else {
-			size_t size = ++pagecount * sizeof(struct page *);
-			p->pagevec = kmalloc(size, GFP_NOFS);
-			if (p->pagevec) {
-				memset(p->pagevec, 0, size);
-			} else {
+			p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
+			if (!p->pagevec) {
 				mempool_free(p, nfs_rdata_mempool);
 				p = NULL;
 			}
@@ -104,6 +101,28 @@
 	return 0;
 }
 
+static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
+{
+	unsigned int remainder = data->args.count - data->res.count;
+	unsigned int base = data->args.pgbase + data->res.count;
+	unsigned int pglen;
+	struct page **pages;
+
+	if (data->res.eof == 0 || remainder == 0)
+		return;
+	/*
+	 * Note: "remainder" can never be negative, since we check for
+	 * 	this in the XDR code.
+	 */
+	pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
+	base &= ~PAGE_CACHE_MASK;
+	pglen = PAGE_CACHE_SIZE - base;
+	if (pglen < remainder)
+		memclear_highpage_flush(*pages, base, pglen);
+	else
+		memclear_highpage_flush(*pages, base, remainder);
+}
+
 /*
  * Read a page synchronously.
  */
@@ -177,11 +196,9 @@
 	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
 	spin_unlock(&inode->i_lock);
 
-	if (count)
-		memclear_highpage_flush(page, rdata->args.pgbase, count);
-	SetPageUptodate(page);
-	if (PageError(page))
-		ClearPageError(page);
+	nfs_readpage_truncate_uninitialised_page(rdata);
+	if (rdata->res.eof || rdata->res.count == rdata->args.count)
+		SetPageUptodate(page);
 	result = 0;
 
 io_error:
@@ -436,20 +453,12 @@
 	struct nfs_page *req = data->req;
 	struct page *page = req->wb_page;
  
+	if (likely(task->tk_status >= 0))
+		nfs_readpage_truncate_uninitialised_page(data);
+	else
+		SetPageError(page);
 	if (nfs_readpage_result(task, data) != 0)
 		return;
-	if (task->tk_status >= 0) {
-		unsigned int request = data->args.count;
-		unsigned int result = data->res.count;
-
-		if (result < request) {
-			memclear_highpage_flush(page,
-						data->args.pgbase + result,
-						request - result);
-		}
-	} else
-		SetPageError(page);
-
 	if (atomic_dec_and_test(&req->wb_complete)) {
 		if (!PageError(page))
 			SetPageUptodate(page);
@@ -462,6 +471,40 @@
 	.rpc_release = nfs_readdata_release,
 };
 
+static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
+{
+	unsigned int count = data->res.count;
+	unsigned int base = data->args.pgbase;
+	struct page **pages;
+
+	if (unlikely(count == 0))
+		return;
+	pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
+	base &= ~PAGE_CACHE_MASK;
+	count += base;
+	for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
+		SetPageUptodate(*pages);
+	/*
+	 * Was this an eof or a short read? If the latter, don't mark the page
+	 * as uptodate yet.
+	 */
+	if (count > 0 && (data->res.eof || data->args.count == data->res.count))
+		SetPageUptodate(*pages);
+}
+
+static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
+{
+	unsigned int count = data->args.count;
+	unsigned int base = data->args.pgbase;
+	struct page **pages;
+
+	pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
+	base &= ~PAGE_CACHE_MASK;
+	count += base;
+	for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
+		SetPageError(*pages);
+}
+
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -469,27 +512,24 @@
 static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
 {
 	struct nfs_read_data *data = calldata;
-	unsigned int count = data->res.count;
 
+	/*
+	 * Note: nfs_readpage_result may change the values of
+	 * data->args. In the multi-page case, we therefore need
+	 * to ensure that we call the next nfs_readpage_set_page_uptodate()
+	 * first in the multi-page case.
+	 */
+	if (likely(task->tk_status >= 0)) {
+		nfs_readpage_truncate_uninitialised_page(data);
+		nfs_readpage_set_pages_uptodate(data);
+	} else
+		nfs_readpage_set_pages_error(data);
 	if (nfs_readpage_result(task, data) != 0)
 		return;
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
-		struct page *page = req->wb_page;
-		nfs_list_remove_request(req);
 
-		if (task->tk_status >= 0) {
-			if (count < PAGE_CACHE_SIZE) {
-				if (count < req->wb_bytes)
-					memclear_highpage_flush(page,
-							req->wb_pgbase + count,
-							req->wb_bytes - count);
-				count = 0;
-			} else
-				count -= PAGE_CACHE_SIZE;
-			SetPageUptodate(page);
-		} else
-			SetPageError(page);
+		nfs_list_remove_request(req);
 		nfs_readpage_release(req);
 	}
 }
@@ -654,7 +694,7 @@
 	return ret;
 }
 
-int nfs_init_readpagecache(void)
+int __init nfs_init_readpagecache(void)
 {
 	nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
 					     sizeof(struct nfs_read_data),
@@ -671,7 +711,7 @@
 	return 0;
 }
 
-void nfs_destroy_readpagecache(void)
+void __exit nfs_destroy_readpagecache(void)
 {
 	mempool_destroy(nfs_rdata_mempool);
 	if (kmem_cache_destroy(nfs_rdata_cachep))
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
new file mode 100644
index 0000000..e8a9bee
--- /dev/null
+++ b/fs/nfs/super.c
@@ -0,0 +1,1537 @@
+/*
+ *  linux/fs/nfs/super.c
+ *
+ *  Copyright (C) 1992  Rick Sladkey
+ *
+ *  nfs superblock handling functions
+ *
+ *  Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
+ *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
+ *
+ *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
+ *  J.S.Peatfield@damtp.cam.ac.uk
+ *
+ *  Split from inode.c by David Howells <dhowells@redhat.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/metrics.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+#include <linux/lockd/bind.h>
+#include <linux/smp_lock.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/nfs_idmap.h>
+#include <linux/vfs.h>
+#include <linux/inet.h>
+#include <linux/nfs_xdr.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "nfs4_fs.h"
+#include "callback.h"
+#include "delegation.h"
+#include "iostat.h"
+#include "internal.h"
+
+#define NFSDBG_FACILITY		NFSDBG_VFS
+
+/* Maximum number of readahead requests
+ * FIXME: this should really be a sysctl so that users may tune it to suit
+ *        their needs. People that do NFS over a slow network, might for
+ *        instance want to reduce it to something closer to 1 for improved
+ *        interactive response.
+ */
+#define NFS_MAX_READAHEAD	(RPC_DEF_SLOT_TABLE - 1)
+
+/*
+ * RPC cruft for NFS
+ */
+static struct rpc_version * nfs_version[] = {
+	NULL,
+	NULL,
+	&nfs_version2,
+#if defined(CONFIG_NFS_V3)
+	&nfs_version3,
+#elif defined(CONFIG_NFS_V4)
+	NULL,
+#endif
+#if defined(CONFIG_NFS_V4)
+	&nfs_version4,
+#endif
+};
+
+static struct rpc_program nfs_program = {
+	.name			= "nfs",
+	.number			= NFS_PROGRAM,
+	.nrvers			= ARRAY_SIZE(nfs_version),
+	.version		= nfs_version,
+	.stats			= &nfs_rpcstat,
+	.pipe_dir_name		= "/nfs",
+};
+
+struct rpc_stat nfs_rpcstat = {
+	.program		= &nfs_program
+};
+
+
+#ifdef CONFIG_NFS_V3_ACL
+static struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program };
+static struct rpc_version *	nfsacl_version[] = {
+	[3]			= &nfsacl_version3,
+};
+
+struct rpc_program		nfsacl_program = {
+	.name =			"nfsacl",
+	.number =		NFS_ACL_PROGRAM,
+	.nrvers =		ARRAY_SIZE(nfsacl_version),
+	.version =		nfsacl_version,
+	.stats =		&nfsacl_rpcstat,
+};
+#endif  /* CONFIG_NFS_V3_ACL */
+
+static void nfs_umount_begin(struct vfsmount *, int);
+static int  nfs_statfs(struct dentry *, struct kstatfs *);
+static int  nfs_show_options(struct seq_file *, struct vfsmount *);
+static int  nfs_show_stats(struct seq_file *, struct vfsmount *);
+static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
+static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
+		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static void nfs_kill_super(struct super_block *);
+
+static struct file_system_type nfs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "nfs",
+	.get_sb		= nfs_get_sb,
+	.kill_sb	= nfs_kill_super,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type clone_nfs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "nfs",
+	.get_sb		= nfs_clone_nfs_sb,
+	.kill_sb	= nfs_kill_super,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static struct super_operations nfs_sops = {
+	.alloc_inode	= nfs_alloc_inode,
+	.destroy_inode	= nfs_destroy_inode,
+	.write_inode	= nfs_write_inode,
+	.statfs		= nfs_statfs,
+	.clear_inode	= nfs_clear_inode,
+	.umount_begin	= nfs_umount_begin,
+	.show_options	= nfs_show_options,
+	.show_stats	= nfs_show_stats,
+};
+
+#ifdef CONFIG_NFS_V4
+static int nfs4_get_sb(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
+		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
+		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
+static void nfs4_kill_super(struct super_block *sb);
+
+static struct file_system_type nfs4_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "nfs4",
+	.get_sb		= nfs4_get_sb,
+	.kill_sb	= nfs4_kill_super,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type clone_nfs4_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "nfs4",
+	.get_sb		= nfs_clone_nfs4_sb,
+	.kill_sb	= nfs4_kill_super,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type nfs_referral_nfs4_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "nfs4",
+	.get_sb		= nfs_referral_nfs4_sb,
+	.kill_sb	= nfs4_kill_super,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static struct super_operations nfs4_sops = {
+	.alloc_inode	= nfs_alloc_inode,
+	.destroy_inode	= nfs_destroy_inode,
+	.write_inode	= nfs_write_inode,
+	.statfs		= nfs_statfs,
+	.clear_inode	= nfs4_clear_inode,
+	.umount_begin	= nfs_umount_begin,
+	.show_options	= nfs_show_options,
+	.show_stats	= nfs_show_stats,
+};
+#endif
+
+#ifdef CONFIG_NFS_V4
+static const int nfs_set_port_min = 0;
+static const int nfs_set_port_max = 65535;
+
+static int param_set_port(const char *val, struct kernel_param *kp)
+{
+	char *endp;
+	int num = simple_strtol(val, &endp, 0);
+	if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max)
+		return -EINVAL;
+	*((int *)kp->arg) = num;
+	return 0;
+}
+
+module_param_call(callback_tcpport, param_set_port, param_get_int,
+		 &nfs_callback_set_tcpport, 0644);
+#endif
+
+#ifdef CONFIG_NFS_V4
+static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
+{
+	char *endp;
+	int num = simple_strtol(val, &endp, 0);
+	int jif = num * HZ;
+	if (endp == val || *endp || num < 0 || jif < num)
+		return -EINVAL;
+	*((int *)kp->arg) = jif;
+	return 0;
+}
+
+module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
+		 &nfs_idmap_cache_timeout, 0644);
+#endif
+
+/*
+ * Register the NFS filesystems
+ */
+int __init register_nfs_fs(void)
+{
+	int ret;
+
+        ret = register_filesystem(&nfs_fs_type);
+	if (ret < 0)
+		goto error_0;
+
+#ifdef CONFIG_NFS_V4
+	ret = nfs_register_sysctl();
+	if (ret < 0)
+		goto error_1;
+	ret = register_filesystem(&nfs4_fs_type);
+	if (ret < 0)
+		goto error_2;
+#endif
+	return 0;
+
+#ifdef CONFIG_NFS_V4
+error_2:
+	nfs_unregister_sysctl();
+error_1:
+	unregister_filesystem(&nfs_fs_type);
+#endif
+error_0:
+	return ret;
+}
+
+/*
+ * Unregister the NFS filesystems
+ */
+void __exit unregister_nfs_fs(void)
+{
+#ifdef CONFIG_NFS_V4
+	unregister_filesystem(&nfs4_fs_type);
+	nfs_unregister_sysctl();
+#endif
+	unregister_filesystem(&nfs_fs_type);
+}
+
+/*
+ * Deliver file system statistics to userspace
+ */
+static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct super_block *sb = dentry->d_sb;
+	struct nfs_server *server = NFS_SB(sb);
+	unsigned char blockbits;
+	unsigned long blockres;
+	struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
+	struct nfs_fattr fattr;
+	struct nfs_fsstat res = {
+			.fattr = &fattr,
+	};
+	int error;
+
+	lock_kernel();
+
+	error = server->rpc_ops->statfs(server, rootfh, &res);
+	buf->f_type = NFS_SUPER_MAGIC;
+	if (error < 0)
+		goto out_err;
+
+	/*
+	 * Current versions of glibc do not correctly handle the
+	 * case where f_frsize != f_bsize.  Eventually we want to
+	 * report the value of wtmult in this field.
+	 */
+	buf->f_frsize = sb->s_blocksize;
+
+	/*
+	 * On most *nix systems, f_blocks, f_bfree, and f_bavail
+	 * are reported in units of f_frsize.  Linux hasn't had
+	 * an f_frsize field in its statfs struct until recently,
+	 * thus historically Linux's sys_statfs reports these
+	 * fields in units of f_bsize.
+	 */
+	buf->f_bsize = sb->s_blocksize;
+	blockbits = sb->s_blocksize_bits;
+	blockres = (1 << blockbits) - 1;
+	buf->f_blocks = (res.tbytes + blockres) >> blockbits;
+	buf->f_bfree = (res.fbytes + blockres) >> blockbits;
+	buf->f_bavail = (res.abytes + blockres) >> blockbits;
+
+	buf->f_files = res.tfiles;
+	buf->f_ffree = res.afiles;
+
+	buf->f_namelen = server->namelen;
+ out:
+	unlock_kernel();
+	return 0;
+
+ out_err:
+	dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
+	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
+	goto out;
+
+}
+
+static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
+{
+	static struct {
+		rpc_authflavor_t flavour;
+		const char *str;
+	} sec_flavours[] = {
+		{ RPC_AUTH_NULL, "null" },
+		{ RPC_AUTH_UNIX, "sys" },
+		{ RPC_AUTH_GSS_KRB5, "krb5" },
+		{ RPC_AUTH_GSS_KRB5I, "krb5i" },
+		{ RPC_AUTH_GSS_KRB5P, "krb5p" },
+		{ RPC_AUTH_GSS_LKEY, "lkey" },
+		{ RPC_AUTH_GSS_LKEYI, "lkeyi" },
+		{ RPC_AUTH_GSS_LKEYP, "lkeyp" },
+		{ RPC_AUTH_GSS_SPKM, "spkm" },
+		{ RPC_AUTH_GSS_SPKMI, "spkmi" },
+		{ RPC_AUTH_GSS_SPKMP, "spkmp" },
+		{ -1, "unknown" }
+	};
+	int i;
+
+	for (i=0; sec_flavours[i].flavour != -1; i++) {
+		if (sec_flavours[i].flavour == flavour)
+			break;
+	}
+	return sec_flavours[i].str;
+}
+
+/*
+ * Describe the mount options in force on this server representation
+ */
+static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
+{
+	static struct proc_nfs_info {
+		int flag;
+		char *str;
+		char *nostr;
+	} nfs_info[] = {
+		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
+		{ NFS_MOUNT_INTR, ",intr", "" },
+		{ NFS_MOUNT_NOCTO, ",nocto", "" },
+		{ NFS_MOUNT_NOAC, ",noac", "" },
+		{ NFS_MOUNT_NONLM, ",nolock", "" },
+		{ NFS_MOUNT_NOACL, ",noacl", "" },
+		{ 0, NULL, NULL }
+	};
+	struct proc_nfs_info *nfs_infop;
+	char buf[12];
+	char *proto;
+
+	seq_printf(m, ",vers=%d", nfss->rpc_ops->version);
+	seq_printf(m, ",rsize=%d", nfss->rsize);
+	seq_printf(m, ",wsize=%d", nfss->wsize);
+	if (nfss->acregmin != 3*HZ || showdefaults)
+		seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+	if (nfss->acregmax != 60*HZ || showdefaults)
+		seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+	if (nfss->acdirmin != 30*HZ || showdefaults)
+		seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+	if (nfss->acdirmax != 60*HZ || showdefaults)
+		seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
+		if (nfss->flags & nfs_infop->flag)
+			seq_puts(m, nfs_infop->str);
+		else
+			seq_puts(m, nfs_infop->nostr);
+	}
+	switch (nfss->client->cl_xprt->prot) {
+		case IPPROTO_TCP:
+			proto = "tcp";
+			break;
+		case IPPROTO_UDP:
+			proto = "udp";
+			break;
+		default:
+			snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
+			proto = buf;
+	}
+	seq_printf(m, ",proto=%s", proto);
+	seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ);
+	seq_printf(m, ",retrans=%u", nfss->retrans_count);
+	seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+}
+
+/*
+ * Describe the mount options on this VFS mountpoint
+ */
+static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
+
+	nfs_show_mount_options(m, nfss, 0);
+
+	seq_puts(m, ",addr=");
+	seq_escape(m, nfss->hostname, " \t\n\\");
+
+	return 0;
+}
+
+/*
+ * Present statistical information for this VFS mountpoint
+ */
+static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
+{
+	int i, cpu;
+	struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
+	struct rpc_auth *auth = nfss->client->cl_auth;
+	struct nfs_iostats totals = { };
+
+	seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
+
+	/*
+	 * Display all mount option settings
+	 */
+	seq_printf(m, "\n\topts:\t");
+	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
+	seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
+	seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
+	seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
+	nfs_show_mount_options(m, nfss, 1);
+
+	seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
+
+	seq_printf(m, "\n\tcaps:\t");
+	seq_printf(m, "caps=0x%x", nfss->caps);
+	seq_printf(m, ",wtmult=%d", nfss->wtmult);
+	seq_printf(m, ",dtsize=%d", nfss->dtsize);
+	seq_printf(m, ",bsize=%d", nfss->bsize);
+	seq_printf(m, ",namelen=%d", nfss->namelen);
+
+#ifdef CONFIG_NFS_V4
+	if (nfss->rpc_ops->version == 4) {
+		seq_printf(m, "\n\tnfsv4:\t");
+		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
+		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
+		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+	}
+#endif
+
+	/*
+	 * Display security flavor in effect for this mount
+	 */
+	seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
+	if (auth->au_flavor)
+		seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
+
+	/*
+	 * Display superblock I/O counters
+	 */
+	for_each_possible_cpu(cpu) {
+		struct nfs_iostats *stats;
+
+		preempt_disable();
+		stats = per_cpu_ptr(nfss->io_stats, cpu);
+
+		for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
+			totals.events[i] += stats->events[i];
+		for (i = 0; i < __NFSIOS_BYTESMAX; i++)
+			totals.bytes[i] += stats->bytes[i];
+
+		preempt_enable();
+	}
+
+	seq_printf(m, "\n\tevents:\t");
+	for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
+		seq_printf(m, "%lu ", totals.events[i]);
+	seq_printf(m, "\n\tbytes:\t");
+	for (i = 0; i < __NFSIOS_BYTESMAX; i++)
+		seq_printf(m, "%Lu ", totals.bytes[i]);
+	seq_printf(m, "\n");
+
+	rpc_print_iostats(m, nfss->client);
+
+	return 0;
+}
+
+/*
+ * Begin unmount by attempting to remove all automounted mountpoints we added
+ * in response to traversals
+ */
+static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+{
+	struct nfs_server *server;
+	struct rpc_clnt	*rpc;
+
+	shrink_submounts(vfsmnt, &nfs_automount_list);
+	if (!(flags & MNT_FORCE))
+		return;
+	/* -EIO all pending I/O */
+	server = NFS_SB(vfsmnt->mnt_sb);
+	rpc = server->client;
+	if (!IS_ERR(rpc))
+		rpc_killall_tasks(rpc);
+	rpc = server->client_acl;
+	if (!IS_ERR(rpc))
+		rpc_killall_tasks(rpc);
+}
+
+/*
+ * Obtain the root inode of the file system.
+ */
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
+{
+	struct nfs_server	*server = NFS_SB(sb);
+	int			error;
+
+	error = server->rpc_ops->getroot(server, rootfh, fsinfo);
+	if (error < 0) {
+		dprintk("nfs_get_root: getattr error = %d\n", -error);
+		return ERR_PTR(error);
+	}
+
+	server->fsid = fsinfo->fattr->fsid;
+	return nfs_fhget(sb, rootfh, fsinfo->fattr);
+}
+
+/*
+ * Do NFS version-independent mount processing, and sanity checking
+ */
+static int
+nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
+{
+	struct nfs_server	*server;
+	struct inode		*root_inode;
+	struct nfs_fattr	fattr;
+	struct nfs_fsinfo	fsinfo = {
+					.fattr = &fattr,
+				};
+	struct nfs_pathconf pathinfo = {
+			.fattr = &fattr,
+	};
+	int no_root_error = 0;
+	unsigned long max_rpc_payload;
+
+	/* We probably want something more informative here */
+	snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+
+	server = NFS_SB(sb);
+
+	sb->s_magic      = NFS_SUPER_MAGIC;
+
+	server->io_stats = nfs_alloc_iostats();
+	if (server->io_stats == NULL)
+		return -ENOMEM;
+
+	root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
+	/* Did getting the root inode fail? */
+	if (IS_ERR(root_inode)) {
+		no_root_error = PTR_ERR(root_inode);
+		goto out_no_root;
+	}
+	sb->s_root = d_alloc_root(root_inode);
+	if (!sb->s_root) {
+		no_root_error = -ENOMEM;
+		goto out_no_root;
+	}
+	sb->s_root->d_op = server->rpc_ops->dentry_ops;
+
+	/* mount time stamp, in seconds */
+	server->mount_time = jiffies;
+
+	/* Get some general file system info */
+	if (server->namelen == 0 &&
+	    server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
+		server->namelen = pathinfo.max_namelen;
+	/* Work out a lot of parameters */
+	if (server->rsize == 0)
+		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+	if (server->wsize == 0)
+		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+
+	if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
+		server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
+	if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
+		server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
+
+	max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
+	if (server->rsize > max_rpc_payload)
+		server->rsize = max_rpc_payload;
+	if (server->rsize > NFS_MAX_FILE_IO_SIZE)
+		server->rsize = NFS_MAX_FILE_IO_SIZE;
+	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+	if (server->wsize > max_rpc_payload)
+		server->wsize = max_rpc_payload;
+	if (server->wsize > NFS_MAX_FILE_IO_SIZE)
+		server->wsize = NFS_MAX_FILE_IO_SIZE;
+	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
+	if (sb->s_blocksize == 0)
+		sb->s_blocksize = nfs_block_bits(server->wsize,
+							 &sb->s_blocksize_bits);
+	server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
+
+	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+	if (server->dtsize > PAGE_CACHE_SIZE)
+		server->dtsize = PAGE_CACHE_SIZE;
+	if (server->dtsize > server->rsize)
+		server->dtsize = server->rsize;
+
+	if (server->flags & NFS_MOUNT_NOAC) {
+		server->acregmin = server->acregmax = 0;
+		server->acdirmin = server->acdirmax = 0;
+		sb->s_flags |= MS_SYNCHRONOUS;
+	}
+	server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
+
+	nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
+
+	server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
+	server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
+
+	/* We're airborne Set socket buffersize */
+	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
+	return 0;
+	/* Yargs. It didn't work out. */
+out_no_root:
+	dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
+	if (!IS_ERR(root_inode))
+		iput(root_inode);
+	return no_root_error;
+}
+
+/*
+ * Initialise the timeout values for a connection
+ */
+static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans)
+{
+	to->to_initval = timeo * HZ / 10;
+	to->to_retries = retrans;
+	if (!to->to_retries)
+		to->to_retries = 2;
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		if (!to->to_initval)
+			to->to_initval = 60 * HZ;
+		if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
+			to->to_initval = NFS_MAX_TCP_TIMEOUT;
+		to->to_increment = to->to_initval;
+		to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
+		to->to_exponential = 0;
+		break;
+	case IPPROTO_UDP:
+	default:
+		if (!to->to_initval)
+			to->to_initval = 11 * HZ / 10;
+		if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
+			to->to_initval = NFS_MAX_UDP_TIMEOUT;
+		to->to_maxval = NFS_MAX_UDP_TIMEOUT;
+		to->to_exponential = 1;
+		break;
+	}
+}
+
+/*
+ * Create an RPC client handle.
+ */
+static struct rpc_clnt *
+nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
+{
+	struct rpc_timeout	timeparms;
+	struct rpc_xprt		*xprt = NULL;
+	struct rpc_clnt		*clnt = NULL;
+	int			proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
+
+	nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans);
+
+	server->retrans_timeo = timeparms.to_initval;
+	server->retrans_count = timeparms.to_retries;
+
+	/* create transport and client */
+	xprt = xprt_create_proto(proto, &server->addr, &timeparms);
+	if (IS_ERR(xprt)) {
+		dprintk("%s: cannot create RPC transport. Error = %ld\n",
+				__FUNCTION__, PTR_ERR(xprt));
+		return (struct rpc_clnt *)xprt;
+	}
+	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+				 server->rpc_ops->version, data->pseudoflavor);
+	if (IS_ERR(clnt)) {
+		dprintk("%s: cannot create RPC client. Error = %ld\n",
+				__FUNCTION__, PTR_ERR(xprt));
+		goto out_fail;
+	}
+
+	clnt->cl_intr     = 1;
+	clnt->cl_softrtry = 1;
+
+	return clnt;
+
+out_fail:
+	return clnt;
+}
+
+/*
+ * Clone a server record
+ */
+static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data)
+{
+	struct nfs_server *server = NFS_SB(sb);
+	struct nfs_server *parent = NFS_SB(data->sb);
+	struct inode *root_inode;
+	struct nfs_fsinfo fsinfo;
+	void *err = ERR_PTR(-ENOMEM);
+
+	sb->s_op = data->sb->s_op;
+	sb->s_blocksize = data->sb->s_blocksize;
+	sb->s_blocksize_bits = data->sb->s_blocksize_bits;
+	sb->s_maxbytes = data->sb->s_maxbytes;
+
+	server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+	server->io_stats = nfs_alloc_iostats();
+	if (server->io_stats == NULL)
+		goto out;
+
+	server->client = rpc_clone_client(parent->client);
+	if (IS_ERR((err = server->client)))
+		goto out;
+
+	if (!IS_ERR(parent->client_sys)) {
+		server->client_sys = rpc_clone_client(parent->client_sys);
+		if (IS_ERR((err = server->client_sys)))
+			goto out;
+	}
+	if (!IS_ERR(parent->client_acl)) {
+		server->client_acl = rpc_clone_client(parent->client_acl);
+		if (IS_ERR((err = server->client_acl)))
+			goto out;
+	}
+	root_inode = nfs_fhget(sb, data->fh, data->fattr);
+	if (!root_inode)
+		goto out;
+	sb->s_root = d_alloc_root(root_inode);
+	if (!sb->s_root)
+		goto out_put_root;
+	fsinfo.fattr = data->fattr;
+	if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0)
+		nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
+	sb->s_root->d_op = server->rpc_ops->dentry_ops;
+	sb->s_flags |= MS_ACTIVE;
+	return server;
+out_put_root:
+	iput(root_inode);
+out:
+	return err;
+}
+
+/*
+ * Copy an existing superblock and attach revised data
+ */
+static int nfs_clone_generic_sb(struct nfs_clone_mount *data,
+		struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *),
+		struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *),
+		struct vfsmount *mnt)
+{
+	struct nfs_server *server;
+	struct nfs_server *parent = NFS_SB(data->sb);
+	struct super_block *sb = ERR_PTR(-EINVAL);
+	char *hostname;
+	int error = -ENOMEM;
+	int len;
+
+	server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
+	if (server == NULL)
+		goto out_err;
+	memcpy(server, parent, sizeof(*server));
+	hostname = (data->hostname != NULL) ? data->hostname : parent->hostname;
+	len = strlen(hostname) + 1;
+	server->hostname = kmalloc(len, GFP_KERNEL);
+	if (server->hostname == NULL)
+		goto free_server;
+	memcpy(server->hostname, hostname, len);
+	error = rpciod_up();
+	if (error != 0)
+		goto free_hostname;
+
+	sb = fill_sb(server, data);
+	if (IS_ERR(sb)) {
+		error = PTR_ERR(sb);
+		goto kill_rpciod;
+	}
+		
+	if (sb->s_root)
+		goto out_rpciod_down;
+
+	server = fill_server(sb, data);
+	if (IS_ERR(server)) {
+		error = PTR_ERR(server);
+		goto out_deactivate;
+	}
+	return simple_set_mnt(mnt, sb);
+out_deactivate:
+	up_write(&sb->s_umount);
+	deactivate_super(sb);
+	return error;
+out_rpciod_down:
+	rpciod_down();
+	kfree(server->hostname);
+	kfree(server);
+	return simple_set_mnt(mnt, sb);
+kill_rpciod:
+	rpciod_down();
+free_hostname:
+	kfree(server->hostname);
+free_server:
+	kfree(server);
+out_err:
+	return error;
+}
+
+/*
+ * Set up an NFS2/3 superblock
+ *
+ * The way this works is that the mount process passes a structure
+ * in the data argument which contains the server's IP address
+ * and the root file handle obtained from the server's mount
+ * daemon. We stash these away in the private superblock fields.
+ */
+static int
+nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
+{
+	struct nfs_server	*server;
+	rpc_authflavor_t	authflavor;
+
+	server           = NFS_SB(sb);
+	sb->s_blocksize_bits = 0;
+	sb->s_blocksize = 0;
+	if (data->bsize)
+		sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+	if (data->rsize)
+		server->rsize = nfs_block_size(data->rsize, NULL);
+	if (data->wsize)
+		server->wsize = nfs_block_size(data->wsize, NULL);
+	server->flags    = data->flags & NFS_MOUNT_FLAGMASK;
+
+	server->acregmin = data->acregmin*HZ;
+	server->acregmax = data->acregmax*HZ;
+	server->acdirmin = data->acdirmin*HZ;
+	server->acdirmax = data->acdirmax*HZ;
+
+	/* Start lockd here, before we might error out */
+	if (!(server->flags & NFS_MOUNT_NONLM))
+		lockd_up();
+
+	server->namelen  = data->namlen;
+	server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
+	if (!server->hostname)
+		return -ENOMEM;
+	strcpy(server->hostname, data->hostname);
+
+	/* Check NFS protocol revision and initialize RPC op vector
+	 * and file handle pool. */
+#ifdef CONFIG_NFS_V3
+	if (server->flags & NFS_MOUNT_VER3) {
+		server->rpc_ops = &nfs_v3_clientops;
+		server->caps |= NFS_CAP_READDIRPLUS;
+	} else {
+		server->rpc_ops = &nfs_v2_clientops;
+	}
+#else
+	server->rpc_ops = &nfs_v2_clientops;
+#endif
+
+	/* Fill in pseudoflavor for mount version < 5 */
+	if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
+		data->pseudoflavor = RPC_AUTH_UNIX;
+	authflavor = data->pseudoflavor;	/* save for sb_init() */
+	/* XXX maybe we want to add a server->pseudoflavor field */
+
+	/* Create RPC client handles */
+	server->client = nfs_create_client(server, data);
+	if (IS_ERR(server->client))
+		return PTR_ERR(server->client);
+	/* RFC 2623, sec 2.3.2 */
+	if (authflavor != RPC_AUTH_UNIX) {
+		struct rpc_auth *auth;
+
+		server->client_sys = rpc_clone_client(server->client);
+		if (IS_ERR(server->client_sys))
+			return PTR_ERR(server->client_sys);
+		auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys);
+		if (IS_ERR(auth))
+			return PTR_ERR(auth);
+	} else {
+		atomic_inc(&server->client->cl_count);
+		server->client_sys = server->client;
+	}
+	if (server->flags & NFS_MOUNT_VER3) {
+#ifdef CONFIG_NFS_V3_ACL
+		if (!(server->flags & NFS_MOUNT_NOACL)) {
+			server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
+			/* No errors! Assume that Sun nfsacls are supported */
+			if (!IS_ERR(server->client_acl))
+				server->caps |= NFS_CAP_ACLS;
+		}
+#else
+		server->flags &= ~NFS_MOUNT_NOACL;
+#endif /* CONFIG_NFS_V3_ACL */
+		/*
+		 * The VFS shouldn't apply the umask to mode bits. We will
+		 * do so ourselves when necessary.
+		 */
+		sb->s_flags |= MS_POSIXACL;
+		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
+			server->namelen = NFS3_MAXNAMLEN;
+		sb->s_time_gran = 1;
+	} else {
+		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
+			server->namelen = NFS2_MAXNAMLEN;
+	}
+
+	sb->s_op = &nfs_sops;
+	return nfs_sb_init(sb, authflavor);
+}
+
+static int nfs_set_super(struct super_block *s, void *data)
+{
+	s->s_fs_info = data;
+	return set_anon_super(s, data);
+}
+
+static int nfs_compare_super(struct super_block *sb, void *data)
+{
+	struct nfs_server *server = data;
+	struct nfs_server *old = NFS_SB(sb);
+
+	if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
+		return 0;
+	if (old->addr.sin_port != server->addr.sin_port)
+		return 0;
+	return !nfs_compare_fh(&old->fh, &server->fh);
+}
+
+static int nfs_get_sb(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+	int error;
+	struct nfs_server *server = NULL;
+	struct super_block *s;
+	struct nfs_fh *root;
+	struct nfs_mount_data *data = raw_data;
+
+	error = -EINVAL;
+	if (data == NULL) {
+		dprintk("%s: missing data argument\n", __FUNCTION__);
+		goto out_err_noserver;
+	}
+	if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
+		dprintk("%s: bad mount version\n", __FUNCTION__);
+		goto out_err_noserver;
+	}
+	switch (data->version) {
+		case 1:
+			data->namlen = 0;
+		case 2:
+			data->bsize  = 0;
+		case 3:
+			if (data->flags & NFS_MOUNT_VER3) {
+				dprintk("%s: mount structure version %d does not support NFSv3\n",
+						__FUNCTION__,
+						data->version);
+				goto out_err_noserver;
+			}
+			data->root.size = NFS2_FHSIZE;
+			memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+		case 4:
+			if (data->flags & NFS_MOUNT_SECFLAVOUR) {
+				dprintk("%s: mount structure version %d does not support strong security\n",
+						__FUNCTION__,
+						data->version);
+				goto out_err_noserver;
+			}
+		case 5:
+			memset(data->context, 0, sizeof(data->context));
+	}
+#ifndef CONFIG_NFS_V3
+	/* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
+	error = -EPROTONOSUPPORT;
+	if (data->flags & NFS_MOUNT_VER3) {
+		dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
+		goto out_err_noserver;
+	}
+#endif /* CONFIG_NFS_V3 */
+
+	error = -ENOMEM;
+	server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
+	if (!server)
+		goto out_err_noserver;
+	/* Zero out the NFS state stuff */
+	init_nfsv4_state(server);
+	server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+
+	root = &server->fh;
+	if (data->flags & NFS_MOUNT_VER3)
+		root->size = data->root.size;
+	else
+		root->size = NFS2_FHSIZE;
+	error = -EINVAL;
+	if (root->size > sizeof(root->data)) {
+		dprintk("%s: invalid root filehandle\n", __FUNCTION__);
+		goto out_err;
+	}
+	memcpy(root->data, data->root.data, root->size);
+
+	/* We now require that the mount process passes the remote address */
+	memcpy(&server->addr, &data->addr, sizeof(server->addr));
+	if (server->addr.sin_addr.s_addr == INADDR_ANY) {
+		dprintk("%s: mount program didn't pass remote address!\n",
+				__FUNCTION__);
+		goto out_err;
+	}
+
+	/* Fire up rpciod if not yet running */
+	error = rpciod_up();
+	if (error < 0) {
+		dprintk("%s: couldn't start rpciod! Error = %d\n",
+				__FUNCTION__, error);
+		goto out_err;
+	}
+
+	s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
+	if (IS_ERR(s)) {
+		error = PTR_ERR(s);
+		goto out_err_rpciod;
+	}
+
+	if (s->s_root)
+		goto out_rpciod_down;
+
+	s->s_flags = flags;
+
+	error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+	if (error) {
+		up_write(&s->s_umount);
+		deactivate_super(s);
+		return error;
+	}
+	s->s_flags |= MS_ACTIVE;
+	return simple_set_mnt(mnt, s);
+
+out_rpciod_down:
+	rpciod_down();
+	kfree(server);
+	return simple_set_mnt(mnt, s);
+
+out_err_rpciod:
+	rpciod_down();
+out_err:
+	kfree(server);
+out_err_noserver:
+	return error;
+}
+
+static void nfs_kill_super(struct super_block *s)
+{
+	struct nfs_server *server = NFS_SB(s);
+
+	kill_anon_super(s);
+
+	if (!IS_ERR(server->client))
+		rpc_shutdown_client(server->client);
+	if (!IS_ERR(server->client_sys))
+		rpc_shutdown_client(server->client_sys);
+	if (!IS_ERR(server->client_acl))
+		rpc_shutdown_client(server->client_acl);
+
+	if (!(server->flags & NFS_MOUNT_NONLM))
+		lockd_down();	/* release rpc.lockd */
+
+	rpciod_down();		/* release rpciod */
+
+	nfs_free_iostats(server->io_stats);
+	kfree(server->hostname);
+	kfree(server);
+	nfs_release_automount_timer();
+}
+
+static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+{
+	struct super_block *sb;
+
+	server->fsid = data->fattr->fsid;
+	nfs_copy_fh(&server->fh, data->fh);
+	sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+	if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM))
+		lockd_up();
+	return sb;
+}
+
+static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
+		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+	struct nfs_clone_mount *data = raw_data;
+	return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt);
+}
+
+#ifdef CONFIG_NFS_V4
+static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
+	struct rpc_timeout *timeparms, int proto, rpc_authflavor_t flavor)
+{
+	struct nfs4_client *clp;
+	struct rpc_xprt *xprt = NULL;
+	struct rpc_clnt *clnt = NULL;
+	int err = -EIO;
+
+	clp = nfs4_get_client(&server->addr.sin_addr);
+	if (!clp) {
+		dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
+		return ERR_PTR(err);
+	}
+
+	/* Now create transport and client */
+	down_write(&clp->cl_sem);
+	if (IS_ERR(clp->cl_rpcclient)) {
+		xprt = xprt_create_proto(proto, &server->addr, timeparms);
+		if (IS_ERR(xprt)) {
+			up_write(&clp->cl_sem);
+			err = PTR_ERR(xprt);
+			dprintk("%s: cannot create RPC transport. Error = %d\n",
+					__FUNCTION__, err);
+			goto out_fail;
+		}
+		/* Bind to a reserved port! */
+		xprt->resvport = 1;
+		clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+				server->rpc_ops->version, flavor);
+		if (IS_ERR(clnt)) {
+			up_write(&clp->cl_sem);
+			err = PTR_ERR(clnt);
+			dprintk("%s: cannot create RPC client. Error = %d\n",
+					__FUNCTION__, err);
+			goto out_fail;
+		}
+		clnt->cl_intr     = 1;
+		clnt->cl_softrtry = 1;
+		clp->cl_rpcclient = clnt;
+		memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
+		nfs_idmap_new(clp);
+	}
+	list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
+	clnt = rpc_clone_client(clp->cl_rpcclient);
+	if (!IS_ERR(clnt))
+		server->nfs4_state = clp;
+	up_write(&clp->cl_sem);
+	clp = NULL;
+
+	if (IS_ERR(clnt)) {
+		dprintk("%s: cannot create RPC client. Error = %d\n",
+				__FUNCTION__, err);
+		return clnt;
+	}
+
+	if (server->nfs4_state->cl_idmap == NULL) {
+		dprintk("%s: failed to create idmapper.\n", __FUNCTION__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (clnt->cl_auth->au_flavor != flavor) {
+		struct rpc_auth *auth;
+
+		auth = rpcauth_create(flavor, clnt);
+		if (IS_ERR(auth)) {
+			dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
+			return (struct rpc_clnt *)auth;
+		}
+	}
+	return clnt;
+
+ out_fail:
+	if (clp)
+		nfs4_put_client(clp);
+	return ERR_PTR(err);
+}
+
+/*
+ * Set up an NFS4 superblock
+ */
+static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
+{
+	struct nfs_server *server;
+	struct rpc_timeout timeparms;
+	rpc_authflavor_t authflavour;
+	int err = -EIO;
+
+	sb->s_blocksize_bits = 0;
+	sb->s_blocksize = 0;
+	server = NFS_SB(sb);
+	if (data->rsize != 0)
+		server->rsize = nfs_block_size(data->rsize, NULL);
+	if (data->wsize != 0)
+		server->wsize = nfs_block_size(data->wsize, NULL);
+	server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+	server->caps = NFS_CAP_ATOMIC_OPEN;
+
+	server->acregmin = data->acregmin*HZ;
+	server->acregmax = data->acregmax*HZ;
+	server->acdirmin = data->acdirmin*HZ;
+	server->acdirmax = data->acdirmax*HZ;
+
+	server->rpc_ops = &nfs_v4_clientops;
+
+	nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans);
+
+	server->retrans_timeo = timeparms.to_initval;
+	server->retrans_count = timeparms.to_retries;
+
+	/* Now create transport and client */
+	authflavour = RPC_AUTH_UNIX;
+	if (data->auth_flavourlen != 0) {
+		if (data->auth_flavourlen != 1) {
+			dprintk("%s: Invalid number of RPC auth flavours %d.\n",
+					__FUNCTION__, data->auth_flavourlen);
+			err = -EINVAL;
+			goto out_fail;
+		}
+		if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
+			err = -EFAULT;
+			goto out_fail;
+		}
+	}
+
+	server->client = nfs4_create_client(server, &timeparms, data->proto, authflavour);
+	if (IS_ERR(server->client)) {
+		err = PTR_ERR(server->client);
+			dprintk("%s: cannot create RPC client. Error = %d\n",
+					__FUNCTION__, err);
+			goto out_fail;
+	}
+
+	sb->s_time_gran = 1;
+
+	sb->s_op = &nfs4_sops;
+	err = nfs_sb_init(sb, authflavour);
+
+ out_fail:
+	return err;
+}
+
+static int nfs4_compare_super(struct super_block *sb, void *data)
+{
+	struct nfs_server *server = data;
+	struct nfs_server *old = NFS_SB(sb);
+
+	if (strcmp(server->hostname, old->hostname) != 0)
+		return 0;
+	if (strcmp(server->mnt_path, old->mnt_path) != 0)
+		return 0;
+	return 1;
+}
+
+static void *
+nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
+{
+	void *p = NULL;
+
+	if (!src->len)
+		return ERR_PTR(-EINVAL);
+	if (src->len < maxlen)
+		maxlen = src->len;
+	if (dst == NULL) {
+		p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
+		if (p == NULL)
+			return ERR_PTR(-ENOMEM);
+	}
+	if (copy_from_user(dst, src->data, maxlen)) {
+		kfree(p);
+		return ERR_PTR(-EFAULT);
+	}
+	dst[maxlen] = '\0';
+	return dst;
+}
+
+static int nfs4_get_sb(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+	int error;
+	struct nfs_server *server;
+	struct super_block *s;
+	struct nfs4_mount_data *data = raw_data;
+	void *p;
+
+	if (data == NULL) {
+		dprintk("%s: missing data argument\n", __FUNCTION__);
+		return -EINVAL;
+	}
+	if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
+		dprintk("%s: bad mount version\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
+	if (!server)
+		return -ENOMEM;
+	/* Zero out the NFS state stuff */
+	init_nfsv4_state(server);
+	server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
+
+	p = nfs_copy_user_string(NULL, &data->hostname, 256);
+	if (IS_ERR(p))
+		goto out_err;
+	server->hostname = p;
+
+	p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
+	if (IS_ERR(p))
+		goto out_err;
+	server->mnt_path = p;
+
+	p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
+			sizeof(server->ip_addr) - 1);
+	if (IS_ERR(p))
+		goto out_err;
+
+	/* We now require that the mount process passes the remote address */
+	if (data->host_addrlen != sizeof(server->addr)) {
+		error = -EINVAL;
+		goto out_free;
+	}
+	if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
+		error = -EFAULT;
+		goto out_free;
+	}
+	if (server->addr.sin_family != AF_INET ||
+	    server->addr.sin_addr.s_addr == INADDR_ANY) {
+		dprintk("%s: mount program didn't pass remote IP address!\n",
+				__FUNCTION__);
+		error = -EINVAL;
+		goto out_free;
+	}
+
+	/* Fire up rpciod if not yet running */
+	error = rpciod_up();
+	if (error < 0) {
+		dprintk("%s: couldn't start rpciod! Error = %d\n",
+				__FUNCTION__, error);
+		goto out_free;
+	}
+
+	s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
+
+	if (IS_ERR(s)) {
+		error = PTR_ERR(s);
+		goto out_free;
+	}
+
+	if (s->s_root) {
+		kfree(server->mnt_path);
+		kfree(server->hostname);
+		kfree(server);
+		return simple_set_mnt(mnt, s);
+	}
+
+	s->s_flags = flags;
+
+	error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+	if (error) {
+		up_write(&s->s_umount);
+		deactivate_super(s);
+		return error;
+	}
+	s->s_flags |= MS_ACTIVE;
+	return simple_set_mnt(mnt, s);
+out_err:
+	error = PTR_ERR(p);
+out_free:
+	kfree(server->mnt_path);
+	kfree(server->hostname);
+	kfree(server);
+	return error;
+}
+
+static void nfs4_kill_super(struct super_block *sb)
+{
+	struct nfs_server *server = NFS_SB(sb);
+
+	nfs_return_all_delegations(sb);
+	kill_anon_super(sb);
+
+	nfs4_renewd_prepare_shutdown(server);
+
+	if (server->client != NULL && !IS_ERR(server->client))
+		rpc_shutdown_client(server->client);
+
+	destroy_nfsv4_state(server);
+
+	rpciod_down();
+
+	nfs_free_iostats(server->io_stats);
+	kfree(server->hostname);
+	kfree(server);
+	nfs_release_automount_timer();
+}
+
+/*
+ * Constructs the SERVER-side path
+ */
+static inline char *nfs4_dup_path(const struct dentry *dentry)
+{
+	char *page = (char *) __get_free_page(GFP_USER);
+	char *path;
+
+	path = nfs4_path(dentry, page, PAGE_SIZE);
+	if (!IS_ERR(path)) {
+		int len = PAGE_SIZE + page - path;
+		char *tmp = path;
+
+		path = kmalloc(len, GFP_KERNEL);
+		if (path)
+			memcpy(path, tmp, len);
+		else
+			path = ERR_PTR(-ENOMEM);
+	}
+	free_page((unsigned long)page);
+	return path;
+}
+
+static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+{
+	const struct dentry *dentry = data->dentry;
+	struct nfs4_client *clp = server->nfs4_state;
+	struct super_block *sb;
+
+	server->fsid = data->fattr->fsid;
+	nfs_copy_fh(&server->fh, data->fh);
+	server->mnt_path = nfs4_dup_path(dentry);
+	if (IS_ERR(server->mnt_path)) {
+		sb = (struct super_block *)server->mnt_path;
+		goto err;
+	}
+	sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
+	if (IS_ERR(sb) || sb->s_root)
+		goto free_path;
+	nfs4_server_capabilities(server, &server->fh);
+
+	down_write(&clp->cl_sem);
+	atomic_inc(&clp->cl_count);
+	list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
+	up_write(&clp->cl_sem);
+	return sb;
+free_path:
+	kfree(server->mnt_path);
+err:
+	server->mnt_path = NULL;
+	return sb;
+}
+
+static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
+		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+	struct nfs_clone_mount *data = raw_data;
+	return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
+}
+
+static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data)
+{
+	struct super_block *sb = ERR_PTR(-ENOMEM);
+	int len;
+
+	len = strlen(data->mnt_path) + 1;
+	server->mnt_path = kmalloc(len, GFP_KERNEL);
+	if (server->mnt_path == NULL)
+		goto err;
+	memcpy(server->mnt_path, data->mnt_path, len);
+	memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in));
+
+	sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
+	if (IS_ERR(sb) || sb->s_root)
+		goto free_path;
+	return sb;
+free_path:
+	kfree(server->mnt_path);
+err:
+	server->mnt_path = NULL;
+	return sb;
+}
+
+static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data)
+{
+	struct nfs_server *server = NFS_SB(sb);
+	struct rpc_timeout timeparms;
+	int proto, timeo, retrans;
+	void *err;
+
+	proto = IPPROTO_TCP;
+	/* Since we are following a referral and there may be alternatives,
+	   set the timeouts and retries to low values */
+	timeo = 2;
+	retrans = 1;
+	nfs_init_timeout_values(&timeparms, proto, timeo, retrans);
+
+	server->client = nfs4_create_client(server, &timeparms, proto, data->authflavor);
+	if (IS_ERR((err = server->client)))
+		goto out_err;
+
+	sb->s_time_gran = 1;
+	sb->s_op = &nfs4_sops;
+	err = ERR_PTR(nfs_sb_init(sb, data->authflavor));
+	if (!IS_ERR(err))
+		return server;
+out_err:
+	return (struct nfs_server *)err;
+}
+
+static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
+		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
+{
+	struct nfs_clone_mount *data = raw_data;
+	return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt);
+}
+
+#endif
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 18dc95b..600bbe6 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -52,7 +52,7 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct page *page;
-	void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode));
+	void *err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
 	if (err)
 		goto read_failed;
 	page = read_cache_page(&inode->i_data, 0,
@@ -75,22 +75,13 @@
 	return NULL;
 }
 
-static void nfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
-{
-	if (cookie) {
-		struct page *page = cookie;
-		kunmap(page);
-		page_cache_release(page);
-	}
-}
-
 /*
  * symlinks can't do much...
  */
 struct inode_operations nfs_symlink_inode_operations = {
 	.readlink	= generic_readlink,
 	.follow_link	= nfs_follow_link,
-	.put_link	= nfs_put_link,
+	.put_link	= page_put_link,
 	.getattr	= nfs_getattr,
 	.setattr	= nfs_setattr,
 };
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c
index 4c486eb..db61e51 100644
--- a/fs/nfs/sysctl.c
+++ b/fs/nfs/sysctl.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_idmap.h>
+#include <linux/nfs_fs.h>
 
 #include "callback.h"
 
@@ -46,6 +47,15 @@
 		.strategy = &sysctl_jiffies,
 	},
 #endif
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "nfs_mountpoint_timeout",
+		.data		= &nfs_mountpoint_expiry_timeout,
+		.maxlen		= sizeof(nfs_mountpoint_expiry_timeout),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+		.strategy	= &sysctl_jiffies,
+	},
 	{ .ctl_name = 0 }
 };
 
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 4cfada2..b383fdd 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -98,11 +98,10 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
-		if (pagecount < NFS_PAGEVEC_SIZE)
-			p->pagevec = &p->page_array[0];
+		if (pagecount <= ARRAY_SIZE(p->page_array))
+			p->pagevec = p->page_array;
 		else {
-			size_t size = ++pagecount * sizeof(struct page *);
-			p->pagevec = kzalloc(size, GFP_NOFS);
+			p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
 			if (!p->pagevec) {
 				mempool_free(p, nfs_commit_mempool);
 				p = NULL;
@@ -126,14 +125,11 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
-		if (pagecount < NFS_PAGEVEC_SIZE)
-			p->pagevec = &p->page_array[0];
+		if (pagecount <= ARRAY_SIZE(p->page_array))
+			p->pagevec = p->page_array;
 		else {
-			size_t size = ++pagecount * sizeof(struct page *);
-			p->pagevec = kmalloc(size, GFP_NOFS);
-			if (p->pagevec) {
-				memset(p->pagevec, 0, size);
-			} else {
+			p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
+			if (!p->pagevec) {
 				mempool_free(p, nfs_wdata_mempool);
 				p = NULL;
 			}
@@ -583,6 +579,17 @@
 	return ret;
 }
 
+static void nfs_cancel_requests(struct list_head *head)
+{
+	struct nfs_page *req;
+	while(!list_empty(head)) {
+		req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_inode_remove_request(req);
+		nfs_clear_page_writeback(req);
+	}
+}
+
 /*
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
@@ -627,7 +634,7 @@
 	int res = 0;
 
 	if (nfsi->ncommit != 0) {
-		res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
+		res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages);
 		nfsi->ncommit -= res;
 		if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
 			printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -1495,15 +1502,25 @@
 		pages = nfs_scan_dirty(inode, &head, idx_start, npages);
 		if (pages != 0) {
 			spin_unlock(&nfsi->req_lock);
-			ret = nfs_flush_list(inode, &head, pages, how);
+			if (how & FLUSH_INVALIDATE)
+				nfs_cancel_requests(&head);
+			else
+				ret = nfs_flush_list(inode, &head, pages, how);
 			spin_lock(&nfsi->req_lock);
 			continue;
 		}
 		if (nocommit)
 			break;
-		pages = nfs_scan_commit(inode, &head, 0, 0);
+		pages = nfs_scan_commit(inode, &head, idx_start, npages);
 		if (pages == 0)
 			break;
+		if (how & FLUSH_INVALIDATE) {
+			spin_unlock(&nfsi->req_lock);
+			nfs_cancel_requests(&head);
+			spin_lock(&nfsi->req_lock);
+			continue;
+		}
+		pages += nfs_scan_commit(inode, &head, 0, 0);
 		spin_unlock(&nfsi->req_lock);
 		ret = nfs_commit_list(inode, &head, how);
 		spin_lock(&nfsi->req_lock);
@@ -1512,7 +1529,7 @@
 	return ret;
 }
 
-int nfs_init_writepagecache(void)
+int __init nfs_init_writepagecache(void)
 {
 	nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
 					     sizeof(struct nfs_write_data),
@@ -1534,7 +1551,7 @@
 	return 0;
 }
 
-void nfs_destroy_writepagecache(void)
+void __exit nfs_destroy_writepagecache(void)
 {
 	mempool_destroy(nfs_commit_mempool);
 	mempool_destroy(nfs_wdata_mempool);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 96c7578..1630b56 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -529,8 +529,7 @@
 
 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
 	list_del_init(&clp->cl_strhash);
-	list_del_init(&clp->cl_idhash);
-	list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
+	list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
 	strhashval = clientstr_hashval(clp->cl_recdir);
 	list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
 	renew_client(clp);
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index d852ebb..fdf7cf3 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -103,8 +103,7 @@
 static void
 lru_put_end(struct svc_cacherep *rp)
 {
-	list_del(&rp->c_lru);
-	list_add_tail(&rp->c_lru, &lru_head);
+	list_move_tail(&rp->c_lru, &lru_head);
 }
 
 /*
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 88292f9..2e42c2d 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -1358,7 +1358,7 @@
 	goto out;
 }
 
-static size_t __ntfs_copy_from_user_iovec(char *vaddr,
+static size_t __ntfs_copy_from_user_iovec_inatomic(char *vaddr,
 		const struct iovec *iov, size_t iov_ofs, size_t bytes)
 {
 	size_t total = 0;
@@ -1376,10 +1376,6 @@
 		bytes -= len;
 		vaddr += len;
 		if (unlikely(left)) {
-			/*
-			 * Zero the rest of the target like __copy_from_user().
-			 */
-			memset(vaddr, 0, bytes);
 			total -= left;
 			break;
 		}
@@ -1420,11 +1416,13 @@
  * pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s
  * single-segment behaviour.
  *
- * We call the same helper (__ntfs_copy_from_user_iovec()) both when atomic and
- * when not atomic.  This is ok because __ntfs_copy_from_user_iovec() calls
- * __copy_from_user_inatomic() and it is ok to call this when non-atomic.  In
- * fact, the only difference between __copy_from_user_inatomic() and
- * __copy_from_user() is that the latter calls might_sleep().  And on many
+ * We call the same helper (__ntfs_copy_from_user_iovec_inatomic()) both
+ * when atomic and when not atomic.  This is ok because
+ * __ntfs_copy_from_user_iovec_inatomic() calls __copy_from_user_inatomic()
+ * and it is ok to call this when non-atomic.
+ * Infact, the only difference between __copy_from_user_inatomic() and
+ * __copy_from_user() is that the latter calls might_sleep() and the former
+ * should not zero the tail of the buffer on error.  And on many
  * architectures __copy_from_user_inatomic() is just defined to
  * __copy_from_user() so it makes no difference at all on those architectures.
  */
@@ -1441,14 +1439,18 @@
 		if (len > bytes)
 			len = bytes;
 		kaddr = kmap_atomic(*pages, KM_USER0);
-		copied = __ntfs_copy_from_user_iovec(kaddr + ofs,
+		copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
 				*iov, *iov_ofs, len);
 		kunmap_atomic(kaddr, KM_USER0);
 		if (unlikely(copied != len)) {
 			/* Do it the slow way. */
 			kaddr = kmap(*pages);
-			copied = __ntfs_copy_from_user_iovec(kaddr + ofs,
+			copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
 					*iov, *iov_ofs, len);
+			/*
+			 * Zero the rest of the target like __copy_from_user().
+			 */
+			memset(kaddr + ofs + copied, 0, len - copied);
 			kunmap(*pages);
 			if (unlikely(copied != len))
 				goto err_out;
diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
index 355593d..87ee29c 100644
--- a/fs/ocfs2/dlm/dlmast.c
+++ b/fs/ocfs2/dlm/dlmast.c
@@ -381,8 +381,7 @@
 	ret = DLM_NORMAL;
 	if (past->type == DLM_AST) {
 		/* do not alter lock refcount.  switching lists. */
-		list_del_init(&lock->list);
-		list_add_tail(&lock->list, &res->granted);
+		list_move_tail(&lock->list, &res->granted);
 		mlog(0, "ast: adding to granted list... type=%d, "
 			  "convert_type=%d\n", lock->ml.type, lock->ml.convert_type);
 		if (lock->ml.convert_type != LKM_IVMODE) {
diff --git a/fs/ocfs2/dlm/dlmconvert.c b/fs/ocfs2/dlm/dlmconvert.c
index 8285228..70888b3 100644
--- a/fs/ocfs2/dlm/dlmconvert.c
+++ b/fs/ocfs2/dlm/dlmconvert.c
@@ -231,8 +231,7 @@
 
 	lock->ml.convert_type = type;
 	/* do not alter lock refcount.  switching lists. */
-	list_del_init(&lock->list);
-	list_add_tail(&lock->list, &res->converting);
+	list_move_tail(&lock->list, &res->converting);
 
 unlock_exit:
 	spin_unlock(&lock->spinlock);
@@ -248,8 +247,7 @@
 				struct dlm_lock *lock)
 {
 	/* do not alter lock refcount.  switching lists. */
-	list_del_init(&lock->list);
-	list_add_tail(&lock->list, &res->granted);
+	list_move_tail(&lock->list, &res->granted);
 	lock->ml.convert_type = LKM_IVMODE;
 	lock->lksb->flags &= ~(DLM_LKSB_GET_LVB|DLM_LKSB_PUT_LVB);
 }
@@ -294,8 +292,7 @@
 	res->state |= DLM_LOCK_RES_IN_PROGRESS;
 	/* move lock to local convert queue */
 	/* do not alter lock refcount.  switching lists. */
-	list_del_init(&lock->list);
-	list_add_tail(&lock->list, &res->converting);
+	list_move_tail(&lock->list, &res->converting);
 	lock->convert_pending = 1;
 	lock->ml.convert_type = type;
 
diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c
index 6fea283..55cda25 100644
--- a/fs/ocfs2/dlm/dlmlock.c
+++ b/fs/ocfs2/dlm/dlmlock.c
@@ -239,8 +239,7 @@
 		mlog(0, "%s: $RECOVERY lock for this node (%u) is "
 		     "mastered by %u; got lock, manually granting (no ast)\n",
 		     dlm->name, dlm->node_num, res->owner);
-		list_del_init(&lock->list);
-		list_add_tail(&lock->list, &res->granted);
+		list_move_tail(&lock->list, &res->granted);
 	}
 	spin_unlock(&res->spinlock);
 
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 805cbab..9962190 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -905,13 +905,11 @@
 			mlog(0, "found lockres owned by dead node while "
 				  "doing recovery for node %u. sending it.\n",
 				  dead_node);
-			list_del_init(&res->recovering);
-			list_add_tail(&res->recovering, list);
+			list_move_tail(&res->recovering, list);
 		} else if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
 			mlog(0, "found UNKNOWN owner while doing recovery "
 				  "for node %u. sending it.\n", dead_node);
-			list_del_init(&res->recovering);
-			list_add_tail(&res->recovering, list);
+			list_move_tail(&res->recovering, list);
 		}
 	}
 	spin_unlock(&dlm->spinlock);
@@ -1529,8 +1527,7 @@
 
 			/* move the lock to its proper place */
 			/* do not alter lock refcount.  switching lists. */
-			list_del_init(&lock->list);
-			list_add_tail(&lock->list, queue);
+			list_move_tail(&lock->list, queue);
 			spin_unlock(&res->spinlock);
 
 			mlog(0, "just reordered a local lock!\n");
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
index 5be9d14..44d3b57 100644
--- a/fs/ocfs2/dlm/dlmthread.c
+++ b/fs/ocfs2/dlm/dlmthread.c
@@ -318,8 +318,7 @@
 
 		target->ml.type = target->ml.convert_type;
 		target->ml.convert_type = LKM_IVMODE;
-		list_del_init(&target->list);
-		list_add_tail(&target->list, &res->granted);
+		list_move_tail(&target->list, &res->granted);
 
 		BUG_ON(!target->lksb);
 		target->lksb->status = DLM_NORMAL;
@@ -380,8 +379,7 @@
 		     target->ml.type, target->ml.node);
 
 		// target->ml.type is already correct
-		list_del_init(&target->list);
-		list_add_tail(&target->list, &res->granted);
+		list_move_tail(&target->list, &res->granted);
 
 		BUG_ON(!target->lksb);
 		target->lksb->status = DLM_NORMAL;
diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c
index 7b1a275..ac89c50 100644
--- a/fs/ocfs2/dlm/dlmunlock.c
+++ b/fs/ocfs2/dlm/dlmunlock.c
@@ -271,8 +271,7 @@
 void dlm_commit_pending_cancel(struct dlm_lock_resource *res,
 			       struct dlm_lock *lock)
 {
-	list_del_init(&lock->list);
-	list_add_tail(&lock->list, &res->granted);
+	list_move_tail(&lock->list, &res->granted);
 	lock->ml.convert_type = LKM_IVMODE;
 }
 
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index eebc3cf..3fe8781 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -222,8 +222,7 @@
 	BUG_ON(!list_empty(&OCFS2_I(inode)->ip_handle_list));
 
 	OCFS2_I(inode)->ip_handle = handle;
-	list_del(&(OCFS2_I(inode)->ip_handle_list));
-	list_add_tail(&(OCFS2_I(inode)->ip_handle_list), &(handle->inode_list));
+	list_move_tail(&(OCFS2_I(inode)->ip_handle_list), &(handle->inode_list));
 }
 
 static void ocfs2_handle_unlock_inodes(struct ocfs2_journal_handle *handle)
diff --git a/fs/open.c b/fs/open.c
index 5fb16e5..303f06d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -322,7 +322,7 @@
 
 	error = locks_verify_truncate(inode, file, length);
 	if (!error)
-		error = do_truncate(dentry, length, 0, file);
+		error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
 	fput(file);
 out:
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 464e2bc..93a56bd 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1,5 +1,4 @@
-/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $
- * openpromfs.c: /proc/openprom handling routines
+/* inode.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
  * Copyright (C) 1998      Eddie C. Dost  (ecd@skynet.be)
@@ -12,756 +11,245 @@
 #include <linux/openprom_fs.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/seq_file.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/uaccess.h>
 
-#define ALIASES_NNODES 64
+static DEFINE_MUTEX(op_mutex);
 
-typedef struct {
-	u16	parent;
-	u16	next;
-	u16	child;
-	u16	first_prop;
-	u32	node;
-} openpromfs_node;
+#define OPENPROM_ROOT_INO	0
 
-typedef struct {
-#define OPP_STRING	0x10
-#define OPP_STRINGLIST	0x20
-#define OPP_BINARY	0x40
-#define OPP_HEXSTRING	0x80
-#define OPP_DIRTY	0x01
-#define OPP_QUOTED	0x02
-#define OPP_NOTQUOTED	0x04
-#define OPP_ASCIIZ	0x08
-	u32	flag;
-	u32	alloclen;
-	u32	len;
-	char	*value;
-	char	name[8];
-} openprom_property;
+enum op_inode_type {
+	op_inode_node,
+	op_inode_prop,
+};
 
-static openpromfs_node *nodes;
-static int alloced;
-static u16 last_node;
-static u16 first_prop;
-static u16 options = 0xffff;
-static u16 aliases = 0xffff;
-static int aliases_nodes;
-static char *alias_names [ALIASES_NNODES];
+union op_inode_data {
+	struct device_node	*node;
+	struct property		*prop;
+};
 
-#define OPENPROM_ROOT_INO	16
-#define OPENPROM_FIRST_INO	OPENPROM_ROOT_INO
-#define NODE(ino) nodes[ino - OPENPROM_FIRST_INO]
-#define NODE2INO(node) (node + OPENPROM_FIRST_INO)
-#define NODEP2INO(no) (no + OPENPROM_FIRST_INO + last_node)
+struct op_inode_info {
+	struct inode		vfs_inode;
+	enum op_inode_type	type;
+	union op_inode_data	u;
+};
 
-static int openpromfs_create (struct inode *, struct dentry *, int, struct nameidata *);
-static int openpromfs_readdir(struct file *, void *, filldir_t);
-static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry, struct nameidata *nd);
-static int openpromfs_unlink (struct inode *, struct dentry *dentry);
-
-static ssize_t nodenum_read(struct file *file, char __user *buf,
-			    size_t count, loff_t *ppos)
+static inline struct op_inode_info *OP_I(struct inode *inode)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	char buffer[10];
-	
-	if (count < 0 || !inode->u.generic_ip)
-		return -EINVAL;
-	sprintf (buffer, "%8.8x\n", (u32)(long)(inode->u.generic_ip));
-	if (file->f_pos >= 9)
-		return 0;
-	if (count > 9 - file->f_pos)
-		count = 9 - file->f_pos;
-	if (copy_to_user(buf, buffer + file->f_pos, count))
-		return -EFAULT;
-	*ppos += count;
-	return count;
+	return container_of(inode, struct op_inode_info, vfs_inode);
 }
 
-static ssize_t property_read(struct file *filp, char __user *buf,
-			     size_t count, loff_t *ppos)
+static int is_string(unsigned char *p, int len)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	int i, j, k;
-	u32 node;
-	char *p, *s;
-	u32 *q;
-	openprom_property *op;
-	char buffer[64];
-	
-	if (!filp->private_data) {
-		node = nodes[(u16)((long)inode->u.generic_ip)].node;
-		i = ((u32)(long)inode->u.generic_ip) >> 16;
-		if ((u16)((long)inode->u.generic_ip) == aliases) {
-			if (i >= aliases_nodes)
-				p = NULL;
-			else
-				p = alias_names [i];
-		} else
-			for (p = prom_firstprop (node, buffer);
-			     i && p && *p;
-			     p = prom_nextprop (node, p, buffer), i--)
-				/* nothing */ ;
-		if (!p || !*p)
-			return -EIO;
-		i = prom_getproplen (node, p);
-		if (i < 0) {
-			if ((u16)((long)inode->u.generic_ip) == aliases)
-				i = 0;
-			else
-				return -EIO;
-		}
-		k = i;
-		if (i < 64) i = 64;
-		filp->private_data = kmalloc (sizeof (openprom_property)
-					      + (j = strlen (p)) + 2 * i,
-					      GFP_KERNEL);
-		if (!filp->private_data)
-			return -ENOMEM;
-		op = (openprom_property *)filp->private_data;
-		op->flag = 0;
-		op->alloclen = 2 * i;
-		strcpy (op->name, p);
-		op->value = (char *)(((unsigned long)(op->name + j + 4)) & ~3);
-		op->len = k;
-		if (k && prom_getproperty (node, p, op->value, i) < 0)
-			return -EIO;
-		op->value [k] = 0;
-		if (k) {
-			for (s = NULL, p = op->value; p < op->value + k; p++) {
-				if ((*p >= ' ' && *p <= '~') || *p == '\n') {
-					op->flag |= OPP_STRING;
-					s = p;
-					continue;
-				}
-				if (p > op->value && !*p && s == p - 1) {
-					if (p < op->value + k - 1)
-						op->flag |= OPP_STRINGLIST;
-					else
-						op->flag |= OPP_ASCIIZ;
-					continue;
-				}
-				if (k == 1 && !*p) {
-					op->flag |= (OPP_STRING|OPP_ASCIIZ);
-					break;
-				}
-				op->flag &= ~(OPP_STRING|OPP_STRINGLIST);
-				if (k & 3)
-					op->flag |= OPP_HEXSTRING;
-				else
-					op->flag |= OPP_BINARY;
-				break;
-			}
-			if (op->flag & OPP_STRINGLIST)
-				op->flag &= ~(OPP_STRING);
-			if (op->flag & OPP_ASCIIZ)
-				op->len--;
-		}
-	} else
-		op = (openprom_property *)filp->private_data;
-	if (!count || !(op->len || (op->flag & OPP_ASCIIZ)))
+	int i;
+
+	for (i = 0; i < len; i++) {
+		unsigned char val = p[i];
+
+		if ((i && !val) ||
+		    (val >= ' ' && val <= '~'))
+			continue;
+
 		return 0;
-	if (*ppos >= 0xffffff || count >= 0xffffff)
-		return -EINVAL;
-	if (op->flag & OPP_STRINGLIST) {
-		for (k = 0, p = op->value; p < op->value + op->len; p++)
-			if (!*p)
-				k++;
-		i = op->len + 4 * k + 3;
-	} else if (op->flag & OPP_STRING) {
-		i = op->len + 3;
-	} else if (op->flag & OPP_BINARY) {
-		i = (op->len * 9) >> 2;
+	}
+
+	return 1;
+}
+
+static int property_show(struct seq_file *f, void *v)
+{
+	struct property *prop = f->private;
+	void *pval;
+	int len;
+
+	len = prop->length;
+	pval = prop->value;
+
+	if (is_string(pval, len)) {
+		while (len > 0) {
+			int n = strlen(pval);
+
+			seq_printf(f, "%s", (char *) pval);
+
+			/* Skip over the NULL byte too.  */
+			pval += n + 1;
+			len -= n + 1;
+
+			if (len > 0)
+				seq_printf(f, " + ");
+		}
 	} else {
-		i = (op->len << 1) + 1;
-	}
-	k = *ppos;
-	if (k >= i) return 0;
-	if (count > i - k) count = i - k;
-	if (op->flag & OPP_STRING) {
-		if (!k) {
-			if (put_user('\'', buf))
-				return -EFAULT;
-			k++;
-			count--;
-		}
-
-		if (k + count >= i - 2)
-			j = i - 2 - k;
-		else
-			j = count;
-
-		if (j >= 0) {
-			if (copy_to_user(buf + k - *ppos,
-					 op->value + k - 1, j))
-				return -EFAULT;
-			count -= j;
-			k += j;
-		}
-
-		if (count) {
-			if (put_user('\'', &buf [k++ - *ppos]))
-				return -EFAULT;
-		}
-		if (count > 1) {
-			if (put_user('\n', &buf [k++ - *ppos]))
-				return -EFAULT;
-		}
-	} else if (op->flag & OPP_STRINGLIST) {
-		char *tmp;
-
-		tmp = kmalloc (i, GFP_KERNEL);
-		if (!tmp)
-			return -ENOMEM;
-
-		s = tmp;
-		*s++ = '\'';
-		for (p = op->value; p < op->value + op->len; p++) {
-			if (!*p) {
-				strcpy(s, "' + '");
-				s += 5;
-				continue;
-			}
-			*s++ = *p;
-		}
-		strcpy(s, "'\n");
-
-		if (copy_to_user(buf, tmp + k, count))
-			return -EFAULT;
-
-		kfree(tmp);
-		k += count;
-
-	} else if (op->flag & OPP_BINARY) {
-		char buffer[10];
-		u32 *first, *last;
-		int first_off, last_cnt;
-
-		first = ((u32 *)op->value) + k / 9;
-		first_off = k % 9;
-		last = ((u32 *)op->value) + (k + count - 1) / 9;
-		last_cnt = (k + count) % 9;
-		if (!last_cnt) last_cnt = 9;
-
-		if (first == last) {
-			sprintf (buffer, "%08x.", *first);
-			if (copy_to_user(buf, buffer + first_off,
-					 last_cnt - first_off))
-				return -EFAULT;
-			buf += last_cnt - first_off;
-		} else {		
-			for (q = first; q <= last; q++) {
-				sprintf (buffer, "%08x.", *q);
-				if (q == first) {
-					if (copy_to_user(buf, buffer + first_off,
-							 9 - first_off))
-						return -EFAULT;
-					buf += 9 - first_off;
-				} else if (q == last) {
-					if (copy_to_user(buf, buffer, last_cnt))
-						return -EFAULT;
-					buf += last_cnt;
-				} else {
-					if (copy_to_user(buf, buffer, 9))
-						return -EFAULT;
-					buf += 9;
-				}
-			}
-		}
-
-		if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9) {
-			if (put_user('\n', (buf - 1)))
-				return -EFAULT;
-		}
-
-		k += count;
-
-	} else if (op->flag & OPP_HEXSTRING) {
-		char buffer[3];
-
-		if ((k < i - 1) && (k & 1)) {
-			sprintf (buffer, "%02x",
-				 (unsigned char) *(op->value + (k >> 1)) & 0xff);
-			if (put_user(buffer[1], &buf[k++ - *ppos]))
-				return -EFAULT;
-			count--;
-		}
-
-		for (; (count > 1) && (k < i - 1); k += 2) {
-			sprintf (buffer, "%02x",
-				 (unsigned char) *(op->value + (k >> 1)) & 0xff);
-			if (copy_to_user(buf + k - *ppos, buffer, 2))
-				return -EFAULT;
-			count -= 2;
-		}
-
-		if (count && (k < i - 1)) {
-			sprintf (buffer, "%02x",
-				 (unsigned char) *(op->value + (k >> 1)) & 0xff);
-			if (put_user(buffer[0], &buf[k++ - *ppos]))
-				return -EFAULT;
-			count--;
-		}
-
-		if (count) {
-			if (put_user('\n', &buf [k++ - *ppos]))
-				return -EFAULT;
-		}
-	}
-	count = k - *ppos;
-	*ppos = k;
-	return count;
-}
-
-static ssize_t property_write(struct file *filp, const char __user *buf,
-			      size_t count, loff_t *ppos)
-{
-	int i, j, k;
-	char *p;
-	u32 *q;
-	void *b;
-	openprom_property *op;
-	
-	if (*ppos >= 0xffffff || count >= 0xffffff)
-		return -EINVAL;
-	if (!filp->private_data) {
-		i = property_read (filp, NULL, 0, NULL);
-		if (i)
-			return i;
-	}
-	k = *ppos;
-	op = (openprom_property *)filp->private_data;
-	if (!(op->flag & OPP_STRING)) {
-		u32 *first, *last;
-		int first_off, last_cnt;
-		u32 mask, mask2;
-		char tmp [9];
-		int forcelen = 0;
-		
-		j = k % 9;
-		for (i = 0; i < count; i++, j++) {
-			if (j == 9) j = 0;
-			if (!j) {
-				char ctmp;
-				if (get_user(ctmp, &buf[i]))
-					return -EFAULT;
-				if (ctmp != '.') {
-					if (ctmp != '\n') {
-						if (op->flag & OPP_BINARY)
-							return -EINVAL;
-						else
-							goto write_try_string;
-					} else {
-						count = i + 1;
-						forcelen = 1;
-						break;
-					}
-				}
-			} else {
-				char ctmp;
-				if (get_user(ctmp, &buf[i]))
-					return -EFAULT;
-				if (ctmp < '0' || 
-				    (ctmp > '9' && ctmp < 'A') ||
-				    (ctmp > 'F' && ctmp < 'a') ||
-				    ctmp > 'f') {
-					if (op->flag & OPP_BINARY)
-						return -EINVAL;
-					else
-						goto write_try_string;
-				}
-			}
-		}
-		op->flag |= OPP_BINARY;
-		tmp [8] = 0;
-		i = ((count + k + 8) / 9) << 2;
-		if (op->alloclen <= i) {
-			b = kmalloc (sizeof (openprom_property) + 2 * i,
-				     GFP_KERNEL);
-			if (!b)
-				return -ENOMEM;
-			memcpy (b, filp->private_data,
-				sizeof (openprom_property)
-				+ strlen (op->name) + op->alloclen);
-			memset (((char *)b) + sizeof (openprom_property)
-				+ strlen (op->name) + op->alloclen, 
-				0, 2 * i - op->alloclen);
-			op = (openprom_property *)b;
-			op->alloclen = 2*i;
-			b = filp->private_data;
-			filp->private_data = (void *)op;
-			kfree (b);
-		}
-		first = ((u32 *)op->value) + (k / 9);
-		first_off = k % 9;
-		last = (u32 *)(op->value + i);
-		last_cnt = (k + count) % 9;
-		if (first + 1 == last) {
-			memset (tmp, '0', 8);
-			if (copy_from_user(tmp + first_off, buf,
-					   (count + first_off > 8) ?
-					   8 - first_off : count))
-				return -EFAULT;
-			mask = 0xffffffff;
-			mask2 = 0xffffffff;
-			for (j = 0; j < first_off; j++)
-				mask >>= 1;
-			for (j = 8 - count - first_off; j > 0; j--)
-				mask2 <<= 1;
-			mask &= mask2;
-			if (mask) {
-				*first &= ~mask;
-				*first |= simple_strtoul (tmp, NULL, 16);
-				op->flag |= OPP_DIRTY;
+		if (len & 3) {
+			while (len) {
+				len--;
+				if (len)
+					seq_printf(f, "%02x.",
+						   *(unsigned char *) pval);
+				else
+					seq_printf(f, "%02x",
+						   *(unsigned char *) pval);
+				pval++;
 			}
 		} else {
-			op->flag |= OPP_DIRTY;
-			for (q = first; q < last; q++) {
-				if (q == first) {
-					if (first_off < 8) {
-						memset (tmp, '0', 8);
-						if (copy_from_user(tmp + first_off,
-								   buf,
-								   8 - first_off))
-							return -EFAULT;
-						mask = 0xffffffff;
-						for (j = 0; j < first_off; j++)
-							mask >>= 1;
-						*q &= ~mask;
-						*q |= simple_strtoul (tmp,NULL,16);
-					}
-					buf += 9;
-				} else if ((q == last - 1) && last_cnt
-					   && (last_cnt < 8)) {
-					memset (tmp, '0', 8);
-					if (copy_from_user(tmp, buf, last_cnt))
-						return -EFAULT;
-					mask = 0xffffffff;
-					for (j = 0; j < 8 - last_cnt; j++)
-						mask <<= 1;
-					*q &= ~mask;
-					*q |= simple_strtoul (tmp, NULL, 16);
-					buf += last_cnt;
-				} else {
-					char tchars[17]; /* XXX yuck... */
+			while (len >= 4) {
+				len -= 4;
 
-					if (copy_from_user(tchars, buf, 16))
-						return -EFAULT;
-					*q = simple_strtoul (tchars, NULL, 16);
-					buf += 9;
-				}
+				if (len)
+					seq_printf(f, "%08x.",
+						   *(unsigned int *) pval);
+				else
+					seq_printf(f, "%08x",
+						   *(unsigned int *) pval);
+				pval += 4;
 			}
 		}
-		if (!forcelen) {
-			if (op->len < i)
-				op->len = i;
-		} else
-			op->len = i;
-		*ppos += count;
 	}
-write_try_string:
-	if (!(op->flag & OPP_BINARY)) {
-		if (!(op->flag & (OPP_QUOTED | OPP_NOTQUOTED))) {
-			char ctmp;
+	seq_printf(f, "\n");
 
-			/* No way, if somebody starts writing from the middle, 
-			 * we don't know whether he uses quotes around or not 
-			 */
-			if (k > 0)
-				return -EINVAL;
-			if (get_user(ctmp, buf))
-				return -EFAULT;
-			if (ctmp == '\'') {
-				op->flag |= OPP_QUOTED;
-				buf++;
-				count--;
-				(*ppos)++;
-				if (!count) {
-					op->flag |= OPP_STRING;
-					return 1;
-				}
-			} else
-				op->flag |= OPP_NOTQUOTED;
-		}
-		op->flag |= OPP_STRING;
-		if (op->alloclen <= count + *ppos) {
-			b = kmalloc (sizeof (openprom_property)
-				     + 2 * (count + *ppos), GFP_KERNEL);
-			if (!b)
-				return -ENOMEM;
-			memcpy (b, filp->private_data,
-				sizeof (openprom_property)
-				+ strlen (op->name) + op->alloclen);
-			memset (((char *)b) + sizeof (openprom_property)
-				+ strlen (op->name) + op->alloclen, 
-				0, 2*(count - *ppos) - op->alloclen);
-			op = (openprom_property *)b;
-			op->alloclen = 2*(count + *ppos);
-			b = filp->private_data;
-			filp->private_data = (void *)op;
-			kfree (b);
-		}
-		p = op->value + *ppos - ((op->flag & OPP_QUOTED) ? 1 : 0);
-		if (copy_from_user(p, buf, count))
-			return -EFAULT;
-		op->flag |= OPP_DIRTY;
-		for (i = 0; i < count; i++, p++)
-			if (*p == '\n') {
-				*p = 0;
-				break;
-			}
-		if (i < count) {
-			op->len = p - op->value;
-			*ppos += i + 1;
-			if ((p > op->value) && (op->flag & OPP_QUOTED)
-			    && (*(p - 1) == '\''))
-				op->len--;
-		} else {
-			if (p - op->value > op->len)
-				op->len = p - op->value;
-			*ppos += count;
-		}
-	}
-	return *ppos - k;
-}
-
-int property_release (struct inode *inode, struct file *filp)
-{
-	openprom_property *op = (openprom_property *)filp->private_data;
-	int error;
-	u32 node;
-	
-	if (!op)
-		return 0;
-	lock_kernel();
-	node = nodes[(u16)((long)inode->u.generic_ip)].node;
-	if ((u16)((long)inode->u.generic_ip) == aliases) {
-		if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) {
-			char *p = op->name;
-			int i = (op->value - op->name) - strlen (op->name) - 1;
-			op->value [op->len] = 0;
-			*(op->value - 1) = ' ';
-			if (i) {
-				for (p = op->value - i - 2; p >= op->name; p--)
-					p[i] = *p;
-				p = op->name + i;
-			}
-			memcpy (p - 8, "nvalias ", 8);
-			prom_feval (p - 8);
-		}
-	} else if (op->flag & OPP_DIRTY) {
-		if (op->flag & OPP_STRING) {
-			op->value [op->len] = 0;
-			error = prom_setprop (node, op->name,
-					      op->value, op->len + 1);
-			if (error <= 0)
-				printk (KERN_WARNING "openpromfs: "
-					"Couldn't write property %s\n",
-					op->name);
-		} else if ((op->flag & OPP_BINARY) || !op->len) {
-			error = prom_setprop (node, op->name,
-					      op->value, op->len);
-			if (error <= 0)
-				printk (KERN_WARNING "openpromfs: "
-					"Couldn't write property %s\n",
-					op->name);
-		} else {
-			printk (KERN_WARNING "openpromfs: "
-				"Unknown property type of %s\n",
-				op->name);
-		}
-	}
-	unlock_kernel();
-	kfree (filp->private_data);
 	return 0;
 }
 
-static const struct file_operations openpromfs_prop_ops = {
-	.read		= property_read,
-	.write		= property_write,
-	.release	= property_release,
+static void *property_start(struct seq_file *f, loff_t *pos)
+{
+	if (*pos == 0)
+		return pos;
+	return NULL;
+}
+
+static void *property_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return NULL;
+}
+
+static void property_stop(struct seq_file *f, void *v)
+{
+	/* Nothing to do */
+}
+
+static struct seq_operations property_op = {
+	.start		= property_start,
+	.next		= property_next,
+	.stop		= property_stop,
+	.show		= property_show
 };
 
-static const struct file_operations openpromfs_nodenum_ops = {
-	.read		= nodenum_read,
+static int property_open(struct inode *inode, struct file *file)
+{
+	struct op_inode_info *oi = OP_I(inode);
+	int ret;
+
+	BUG_ON(oi->type != op_inode_prop);
+
+	ret = seq_open(file, &property_op);
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		m->private = oi->u.prop;
+	}
+	return ret;
+}
+
+static const struct file_operations openpromfs_prop_ops = {
+	.open		= property_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
+static int openpromfs_readdir(struct file *, void *, filldir_t);
+
 static const struct file_operations openprom_operations = {
 	.read		= generic_read_dir,
 	.readdir	= openpromfs_readdir,
 };
 
-static struct inode_operations openprom_alias_inode_operations = {
-	.create		= openpromfs_create,
-	.lookup		= openpromfs_lookup,
-	.unlink		= openpromfs_unlink,
-};
+static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *);
 
 static struct inode_operations openprom_inode_operations = {
 	.lookup		= openpromfs_lookup,
 };
 
-static int lookup_children(u16 n, const char * name, int len)
+static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
-	int ret;
-	u16 node;
-	for (; n != 0xffff; n = nodes[n].next) {
-		node = nodes[n].child;
-		if (node != 0xffff) {
-			char buffer[128];
-			int i;
-			char *p;
-			
-			while (node != 0xffff) {
-				if (prom_getname (nodes[node].node,
-						  buffer, 128) >= 0) {
-					i = strlen (buffer);
-					if ((len == i)
-					    && !strncmp (buffer, name, len))
-						return NODE2INO(node);
-					p = strchr (buffer, '@');
-					if (p && (len == p - buffer)
-					    && !strncmp (buffer, name, len))
-						return NODE2INO(node);
-				}
-				node = nodes[node].next;
-			}
-		} else
-			continue;
-		ret = lookup_children (nodes[n].child, name, len);
-		if (ret) return ret;
-	}
-	return 0;
-}
-
-static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
-{
-	int ino = 0;
-#define OPFSL_DIR	0
-#define OPFSL_PROPERTY	1
-#define OPFSL_NODENUM	2
-	int type = 0;
-	char buffer[128];
-	char *p;
+	struct op_inode_info *ent_oi, *oi = OP_I(dir);
+	struct device_node *dp, *child;
+	struct property *prop;
+	enum op_inode_type ent_type;
+	union op_inode_data ent_data;
 	const char *name;
-	u32 n;
-	u16 dirnode;
-	unsigned int len;
-	int i;
 	struct inode *inode;
-	char buffer2[64];
+	unsigned int ino;
+	int len;
 	
-	inode = NULL;
+	BUG_ON(oi->type != op_inode_node);
+
+	dp = oi->u.node;
+
 	name = dentry->d_name.name;
 	len = dentry->d_name.len;
-	lock_kernel();
-	if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) {
-		ino = NODEP2INO(NODE(dir->i_ino).first_prop);
-		type = OPFSL_NODENUM;
-	}
-	if (!ino) {
-		u16 node = NODE(dir->i_ino).child;
-		while (node != 0xffff) {
-			if (prom_getname (nodes[node].node, buffer, 128) >= 0) {
-				i = strlen (buffer);
-				if (len == i && !strncmp (buffer, name, len)) {
-					ino = NODE2INO(node);
-					type = OPFSL_DIR;
-					break;
-				}
-				p = strchr (buffer, '@');
-				if (p && (len == p - buffer)
-				    && !strncmp (buffer, name, len)) {
-					ino = NODE2INO(node);
-					type = OPFSL_DIR;
-					break;
-				}
-			}
-			node = nodes[node].next;
+
+	mutex_lock(&op_mutex);
+
+	child = dp->child;
+	while (child) {
+		int n = strlen(child->path_component_name);
+
+		if (len == n &&
+		    !strncmp(child->path_component_name, name, len)) {
+			ent_type = op_inode_node;
+			ent_data.node = child;
+			ino = child->unique_id;
+			goto found;
 		}
+		child = child->sibling;
 	}
-	n = NODE(dir->i_ino).node;
-	dirnode = dir->i_ino - OPENPROM_FIRST_INO;
-	if (!ino) {
-		int j = NODEP2INO(NODE(dir->i_ino).first_prop);
-		if (dirnode != aliases) {
-			for (p = prom_firstprop (n, buffer2);
-			     p && *p;
-			     p = prom_nextprop (n, p, buffer2)) {
-				j++;
-				if ((len == strlen (p))
-				    && !strncmp (p, name, len)) {
-					ino = j;
-					type = OPFSL_PROPERTY;
-					break;
-				}
-			}
-		} else {
-			int k;
-			for (k = 0; k < aliases_nodes; k++) {
-				j++;
-				if (alias_names [k]
-				    && (len == strlen (alias_names [k]))
-				    && !strncmp (alias_names [k], name, len)) {
-					ino = j;
-					type = OPFSL_PROPERTY;
-					break;
-				}
-			}
+
+	prop = dp->properties;
+	while (prop) {
+		int n = strlen(prop->name);
+
+		if (len == n && !strncmp(prop->name, name, len)) {
+			ent_type = op_inode_prop;
+			ent_data.prop = prop;
+			ino = prop->unique_id;
+			goto found;
 		}
+
+		prop = prop->next;
 	}
-	if (!ino) {
-		ino = lookup_children (NODE(dir->i_ino).child, name, len);
-		if (ino)
-			type = OPFSL_DIR;
-		else {
-			unlock_kernel();
-			return ERR_PTR(-ENOENT);
-		}
-	}
-	inode = iget (dir->i_sb, ino);
-	unlock_kernel();
+
+	mutex_unlock(&op_mutex);
+	return ERR_PTR(-ENOENT);
+
+found:
+	inode = iget(dir->i_sb, ino);
+	mutex_unlock(&op_mutex);
 	if (!inode)
 		return ERR_PTR(-EINVAL);
-	switch (type) {
-	case OPFSL_DIR:
+	ent_oi = OP_I(inode);
+	ent_oi->type = ent_type;
+	ent_oi->u = ent_data;
+
+	switch (ent_type) {
+	case op_inode_node:
 		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-		if (ino == OPENPROM_FIRST_INO + aliases) {
-			inode->i_mode |= S_IWUSR;
-			inode->i_op = &openprom_alias_inode_operations;
-		} else
-			inode->i_op = &openprom_inode_operations;
+		inode->i_op = &openprom_inode_operations;
 		inode->i_fop = &openprom_operations;
 		inode->i_nlink = 2;
 		break;
-	case OPFSL_NODENUM:
-		inode->i_mode = S_IFREG | S_IRUGO;
-		inode->i_fop = &openpromfs_nodenum_ops;
-		inode->i_nlink = 1;
-		inode->u.generic_ip = (void *)(long)(n);
-		break;
-	case OPFSL_PROPERTY:
-		if ((dirnode == options) && (len == 17)
-		    && !strncmp (name, "security-password", 17))
+	case op_inode_prop:
+		if (!strcmp(dp->name, "options") && (len == 17) &&
+		    !strncmp (name, "security-password", 17))
 			inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
-		else {
+		else
 			inode->i_mode = S_IFREG | S_IRUGO;
-			if (dirnode == options || dirnode == aliases) {
-				if (len != 4 || strncmp (name, "name", 4))
-					inode->i_mode |= S_IWUSR;
-			}
-		}
 		inode->i_fop = &openpromfs_prop_ops;
 		inode->i_nlink = 1;
-		if (inode->i_size < 0)
-			inode->i_size = 0;
-		inode->u.generic_ip = (void *)(long)(((u16)dirnode) | 
-			(((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16));
+		inode->i_size = ent_oi->u.prop->length;
 		break;
 	}
 
@@ -775,237 +263,89 @@
 static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
+	struct op_inode_info *oi = OP_I(inode);
+	struct device_node *dp = oi->u.node;
+	struct device_node *child;
+	struct property *prop;
 	unsigned int ino;
-	u32 n;
-	int i, j;
-	char buffer[128];
-	u16 node;
-	char *p;
-	char buffer2[64];
+	int i;
 
-	lock_kernel();
+	mutex_lock(&op_mutex);
 	
 	ino = inode->i_ino;
 	i = filp->f_pos;
 	switch (i) {
 	case 0:
-		if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) goto out;
+		if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+			goto out;
 		i++;
 		filp->f_pos++;
 		/* fall thru */
 	case 1:
-		if (filldir(dirent, "..", 2, i, 
-			(NODE(ino).parent == 0xffff) ? 
-			OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0) 
+		if (filldir(dirent, "..", 2, i,
+			    (dp->parent == NULL ?
+			     OPENPROM_ROOT_INO :
+			     dp->parent->unique_id), DT_DIR) < 0) 
 			goto out;
 		i++;
 		filp->f_pos++;
 		/* fall thru */
 	default:
 		i -= 2;
-		node = NODE(ino).child;
-		while (i && node != 0xffff) {
-			node = nodes[node].next;
+
+		/* First, the children nodes as directories.  */
+		child = dp->child;
+		while (i && child) {
+			child = child->sibling;
 			i--;
 		}
-		while (node != 0xffff) {
-			if (prom_getname (nodes[node].node, buffer, 128) < 0)
+		while (child) {
+			if (filldir(dirent,
+				    child->path_component_name,
+				    strlen(child->path_component_name),
+				    filp->f_pos, child->unique_id, DT_DIR) < 0)
 				goto out;
-			if (filldir(dirent, buffer, strlen(buffer),
-				    filp->f_pos, NODE2INO(node), DT_DIR) < 0)
-				goto out;
+
 			filp->f_pos++;
-			node = nodes[node].next;
+			child = child->sibling;
 		}
-		j = NODEP2INO(NODE(ino).first_prop);
-		if (!i) {
-			if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0)
-				goto out;
-			filp->f_pos++;
-		} else
+
+		/* Next, the properties as files.  */
+		prop = dp->properties;
+		while (i && prop) {
+			prop = prop->next;
 			i--;
-		n = NODE(ino).node;
-		if (ino == OPENPROM_FIRST_INO + aliases) {
-			for (j++; i < aliases_nodes; i++, j++) {
-				if (alias_names [i]) {
-					if (filldir (dirent, alias_names [i], 
-						strlen (alias_names [i]), 
-						filp->f_pos, j, DT_REG) < 0) goto out; 
-					filp->f_pos++;
-				}
-			}
-		} else {
-			for (p = prom_firstprop (n, buffer2);
-			     p && *p;
-			     p = prom_nextprop (n, p, buffer2)) {
-				j++;
-				if (i) i--;
-				else {
-					if (filldir(dirent, p, strlen(p),
-						    filp->f_pos, j, DT_REG) < 0)
-						goto out;
-					filp->f_pos++;
-				}
-			}
+		}
+		while (prop) {
+			if (filldir(dirent, prop->name, strlen(prop->name),
+				    filp->f_pos, prop->unique_id, DT_REG) < 0)
+				goto out;
+
+			filp->f_pos++;
+			prop = prop->next;
 		}
 	}
 out:
-	unlock_kernel();
+	mutex_unlock(&op_mutex);
 	return 0;
 }
 
-static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode,
-		struct nameidata *nd)
+static kmem_cache_t *op_inode_cachep;
+
+static struct inode *openprom_alloc_inode(struct super_block *sb)
 {
-	char *p;
-	struct inode *inode;
-	
-	if (!dir)
-		return -ENOENT;
-	if (dentry->d_name.len > 256)
-		return -EINVAL;
-	p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
-	if (!p)
-		return -ENOMEM;
-	strncpy (p, dentry->d_name.name, dentry->d_name.len);
-	p [dentry->d_name.len] = 0;
-	lock_kernel();
-	if (aliases_nodes == ALIASES_NNODES) {
-		kfree(p);
-		unlock_kernel();
-		return -EIO;
-	}
-	alias_names [aliases_nodes++] = p;
-	inode = iget (dir->i_sb,
-			NODEP2INO(NODE(dir->i_ino).first_prop) + aliases_nodes);
-	if (!inode) {
-		unlock_kernel();
-		return -EINVAL;
-	}
-	inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
-	inode->i_fop = &openpromfs_prop_ops;
-	inode->i_nlink = 1;
-	if (inode->i_size < 0) inode->i_size = 0;
-	inode->u.generic_ip = (void *)(long)(((u16)aliases) | 
-			(((u16)(aliases_nodes - 1)) << 16));
-	unlock_kernel();
-	d_instantiate(dentry, inode);
-	return 0;
+	struct op_inode_info *oi;
+
+	oi = kmem_cache_alloc(op_inode_cachep, SLAB_KERNEL);
+	if (!oi)
+		return NULL;
+
+	return &oi->vfs_inode;
 }
 
-static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
+static void openprom_destroy_inode(struct inode *inode)
 {
-	unsigned int len;
-	char *p;
-	const char *name;
-	int i;
-	
-	name = dentry->d_name.name;
-	len = dentry->d_name.len;
-	lock_kernel();
-	for (i = 0; i < aliases_nodes; i++)
-		if ((strlen (alias_names [i]) == len)
-		    && !strncmp (name, alias_names[i], len)) {
-			char buffer[512];
-			
-			p = alias_names [i];
-			alias_names [i] = NULL;
-			kfree (p);
-			strcpy (buffer, "nvunalias ");
-			memcpy (buffer + 10, name, len);
-			buffer [10 + len] = 0;
-			prom_feval (buffer);
-		}
-	unlock_kernel();
-	return 0;
-}
-
-/* {{{ init section */
-static int __init check_space (u16 n)
-{
-	unsigned long pages;
-
-	if ((1 << alloced) * PAGE_SIZE < (n + 2) * sizeof(openpromfs_node)) {
-		pages = __get_free_pages (GFP_KERNEL, alloced + 1);
-		if (!pages)
-			return -1;
-
-		if (nodes) {
-			memcpy ((char *)pages, (char *)nodes,
-				(1 << alloced) * PAGE_SIZE);
-			free_pages ((unsigned long)nodes, alloced);
-		}
-		alloced++;
-		nodes = (openpromfs_node *)pages;
-	}
-	return 0;
-}
-
-static u16 __init get_nodes (u16 parent, u32 node)
-{
-	char *p;
-	u16 n = last_node++, i;
-	char buffer[64];
-
-	if (check_space (n) < 0)
-		return 0xffff;
-	nodes[n].parent = parent;
-	nodes[n].node = node;
-	nodes[n].next = 0xffff;
-	nodes[n].child = 0xffff;
-	nodes[n].first_prop = first_prop++;
-	if (!parent) {
-		char buffer[8];
-		int j;
-		
-		if ((j = prom_getproperty (node, "name", buffer, 8)) >= 0) {
-		    buffer[j] = 0;
-		    if (!strcmp (buffer, "options"))
-			options = n;
-		    else if (!strcmp (buffer, "aliases"))
-		        aliases = n;
-		}
-	}
-	if (n != aliases)
-		for (p = prom_firstprop (node, buffer);
-		     p && p != (char *)-1 && *p;
-		     p = prom_nextprop (node, p, buffer))
-			first_prop++;
-	else {
-		char *q;
-		for (p = prom_firstprop (node, buffer);
-		     p && p != (char *)-1 && *p;
-		     p = prom_nextprop (node, p, buffer)) {
-			if (aliases_nodes == ALIASES_NNODES)
-				break;
-			for (i = 0; i < aliases_nodes; i++)
-				if (!strcmp (p, alias_names [i]))
-					break;
-			if (i < aliases_nodes)
-				continue;
-			q = kmalloc (strlen (p) + 1, GFP_KERNEL);
-			if (!q)
-				return 0xffff;
-			strcpy (q, p);
-			alias_names [aliases_nodes++] = q;
-		}
-		first_prop += ALIASES_NNODES;
-	}
-	node = prom_getchild (node);
-	if (node) {
-		parent = get_nodes (n, node);
-		if (parent == 0xffff)
-			return 0xffff;
-		nodes[n].child = parent;
-		while ((node = prom_getsibling (node)) != 0) {
-			i = get_nodes (n, node);
-			if (i == 0xffff)
-				return 0xffff;
-			nodes[parent].next = i;
-			parent = i;
-		}
-	}
-	return n;
+	kmem_cache_free(op_inode_cachep, OP_I(inode));
 }
 
 static void openprom_read_inode(struct inode * inode)
@@ -1025,6 +365,8 @@
 }
 
 static struct super_operations openprom_sops = { 
+	.alloc_inode	= openprom_alloc_inode,
+	.destroy_inode	= openprom_destroy_inode,
 	.read_inode	= openprom_read_inode,
 	.statfs		= simple_statfs,
 	.remount_fs	= openprom_remount,
@@ -1032,7 +374,8 @@
 
 static int openprom_fill_super(struct super_block *s, void *data, int silent)
 {
-	struct inode * root_inode;
+	struct inode *root_inode;
+	struct op_inode_info *oi;
 
 	s->s_flags |= MS_NOATIME;
 	s->s_blocksize = 1024;
@@ -1043,6 +386,11 @@
 	root_inode = iget(s, OPENPROM_ROOT_INO);
 	if (!root_inode)
 		goto out_no_root;
+
+	oi = OP_I(root_inode);
+	oi->type = op_inode_node;
+	oi->u.node = of_find_node_by_path("/");
+
 	s->s_root = d_alloc_root(root_inode);
 	if (!s->s_root)
 		goto out_no_root;
@@ -1067,29 +415,39 @@
 	.kill_sb	= kill_anon_super,
 };
 
+static void op_inode_init_once(void *data, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct op_inode_info *oi = (struct op_inode_info *) data;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&oi->vfs_inode);
+}
+
 static int __init init_openprom_fs(void)
 {
-	nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0);
-	if (!nodes) {
-		printk (KERN_WARNING "openpromfs: can't get free page\n");
-		return -EIO;
-	}
-	if (get_nodes (0xffff, prom_root_node) == 0xffff) {
-		printk (KERN_WARNING "openpromfs: couldn't setup tree\n");
-		return -EIO;
-	}
-	nodes[last_node].first_prop = first_prop;
-	return register_filesystem(&openprom_fs_type);
+	int err;
+
+	op_inode_cachep = kmem_cache_create("op_inode_cache",
+					    sizeof(struct op_inode_info),
+					    0,
+					    (SLAB_RECLAIM_ACCOUNT |
+					     SLAB_MEM_SPREAD),
+					    op_inode_init_once, NULL);
+	if (!op_inode_cachep)
+		return -ENOMEM;
+
+	err = register_filesystem(&openprom_fs_type);
+	if (err)
+		kmem_cache_destroy(op_inode_cachep);
+
+	return err;
 }
 
 static void __exit exit_openprom_fs(void)
 {
-	int i;
 	unregister_filesystem(&openprom_fs_type);
-	free_pages ((unsigned long)nodes, alloced);
-	for (i = 0; i < aliases_nodes; i++)
-		kfree (alias_names [i]);
-	nodes = NULL;
+	kmem_cache_destroy(op_inode_cachep);
 }
 
 module_init(init_openprom_fs)
diff --git a/fs/pnode.c b/fs/pnode.c
index 37b568e..da42ee6 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -53,8 +53,7 @@
 	if (master) {
 		list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave)
 			slave_mnt->mnt_master = master;
-		list_del(&mnt->mnt_slave);
-		list_add(&mnt->mnt_slave, &master->mnt_slave_list);
+		list_move(&mnt->mnt_slave, &master->mnt_slave_list);
 		list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
 		INIT_LIST_HEAD(&mnt->mnt_slave_list);
 	} else {
@@ -283,10 +282,8 @@
 		 * umount the child only if the child has no
 		 * other children
 		 */
-		if (child && list_empty(&child->mnt_mounts)) {
-			list_del(&child->mnt_hash);
-			list_add_tail(&child->mnt_hash, &mnt->mnt_hash);
-		}
+		if (child && list_empty(&child->mnt_mounts))
+			list_move_tail(&child->mnt_hash, &mnt->mnt_hash);
 	}
 }
 
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6afff72..6ba7785 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -74,6 +74,16 @@
 #include <linux/poll.h>
 #include "internal.h"
 
+/* NOTE:
+ *	Implementing inode permission operations in /proc is almost
+ *	certainly an error.  Permission checks need to happen during
+ *	each system call not at open time.  The reason is that most of
+ *	what we wish to check for permissions in /proc varies at runtime.
+ *
+ *	The classic example of a problem is opening file descriptors
+ *	in /proc for a task before it execs a suid executable.
+ */
+
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
  * Feel free to change the macro below - just keep the range distinct from
@@ -121,6 +131,8 @@
 	PROC_TGID_ATTR_PREV,
 	PROC_TGID_ATTR_EXEC,
 	PROC_TGID_ATTR_FSCREATE,
+	PROC_TGID_ATTR_KEYCREATE,
+	PROC_TGID_ATTR_SOCKCREATE,
 #endif
 #ifdef CONFIG_AUDITSYSCALL
 	PROC_TGID_LOGINUID,
@@ -162,6 +174,8 @@
 	PROC_TID_ATTR_PREV,
 	PROC_TID_ATTR_EXEC,
 	PROC_TID_ATTR_FSCREATE,
+	PROC_TID_ATTR_KEYCREATE,
+	PROC_TID_ATTR_SOCKCREATE,
 #endif
 #ifdef CONFIG_AUDITSYSCALL
 	PROC_TID_LOGINUID,
@@ -173,6 +187,9 @@
 	PROC_TID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
 
+/* Worst case buffer size needed for holding an integer. */
+#define PROC_NUMBUF 10
+
 struct pid_entry {
 	int type;
 	int len;
@@ -275,6 +292,8 @@
 	E(PROC_TGID_ATTR_PREV,     "prev",     S_IFREG|S_IRUGO),
 	E(PROC_TGID_ATTR_EXEC,     "exec",     S_IFREG|S_IRUGO|S_IWUGO),
 	E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
+	E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
+	E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
 	{0,0,NULL,0}
 };
 static struct pid_entry tid_attr_stuff[] = {
@@ -282,6 +301,8 @@
 	E(PROC_TID_ATTR_PREV,      "prev",     S_IFREG|S_IRUGO),
 	E(PROC_TID_ATTR_EXEC,      "exec",     S_IFREG|S_IRUGO|S_IWUGO),
 	E(PROC_TID_ATTR_FSCREATE,  "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
+	E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
+	E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
 	{0,0,NULL,0}
 };
 #endif
@@ -290,12 +311,15 @@
 
 static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	struct task_struct *task = proc_task(inode);
-	struct files_struct *files;
+	struct task_struct *task = get_proc_task(inode);
+	struct files_struct *files = NULL;
 	struct file *file;
-	int fd = proc_type(inode) - PROC_TID_FD_DIR;
+	int fd = proc_fd(inode);
 
-	files = get_files_struct(task);
+	if (task) {
+		files = get_files_struct(task);
+		put_task_struct(task);
+	}
 	if (files) {
 		/*
 		 * We are not taking a ref to the file structure, so we must
@@ -327,10 +351,29 @@
 	return fs;
 }
 
+static int get_nr_threads(struct task_struct *tsk)
+{
+	/* Must be called with the rcu_read_lock held */
+	unsigned long flags;
+	int count = 0;
+
+	if (lock_task_sighand(tsk, &flags)) {
+		count = atomic_read(&tsk->signal->count);
+		unlock_task_sighand(tsk, &flags);
+	}
+	return count;
+}
+
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	struct fs_struct *fs = get_fs_struct(proc_task(inode));
+	struct task_struct *task = get_proc_task(inode);
+	struct fs_struct *fs = NULL;
 	int result = -ENOENT;
+
+	if (task) {
+		fs = get_fs_struct(task);
+		put_task_struct(task);
+	}
 	if (fs) {
 		read_lock(&fs->lock);
 		*mnt = mntget(fs->pwdmnt);
@@ -344,8 +387,14 @@
 
 static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-	struct fs_struct *fs = get_fs_struct(proc_task(inode));
+	struct task_struct *task = get_proc_task(inode);
+	struct fs_struct *fs = NULL;
 	int result = -ENOENT;
+
+	if (task) {
+		fs = get_fs_struct(task);
+		put_task_struct(task);
+	}
 	if (fs) {
 		read_lock(&fs->lock);
 		*mnt = mntget(fs->rootmnt);
@@ -357,54 +406,6 @@
 	return result;
 }
 
-
-/* Same as proc_root_link, but this addionally tries to get fs from other
- * threads in the group */
-static int proc_task_root_link(struct inode *inode, struct dentry **dentry,
-				struct vfsmount **mnt)
-{
-	struct fs_struct *fs;
-	int result = -ENOENT;
-	struct task_struct *leader = proc_task(inode);
-
-	task_lock(leader);
-	fs = leader->fs;
-	if (fs) {
-		atomic_inc(&fs->count);
-		task_unlock(leader);
-	} else {
-		/* Try to get fs from other threads */
-		task_unlock(leader);
-		read_lock(&tasklist_lock);
-		if (pid_alive(leader)) {
-			struct task_struct *task = leader;
-
-			while ((task = next_thread(task)) != leader) {
-				task_lock(task);
-				fs = task->fs;
-				if (fs) {
-					atomic_inc(&fs->count);
-					task_unlock(task);
-					break;
-				}
-				task_unlock(task);
-			}
-		}
-		read_unlock(&tasklist_lock);
-	}
-
-	if (fs) {
-		read_lock(&fs->lock);
-		*mnt = mntget(fs->rootmnt);
-		*dentry = dget(fs->root);
-		read_unlock(&fs->lock);
-		result = 0;
-		put_fs_struct(fs);
-	}
-	return result;
-}
-
-
 #define MAY_PTRACE(task) \
 	(task == current || \
 	(task->parent == current && \
@@ -535,142 +536,22 @@
 /************************************************************************/
 
 /* permission checks */
-
-/* If the process being read is separated by chroot from the reading process,
- * don't let the reader access the threads.
- *
- * note: this does dput(root) and mntput(vfsmnt) on exit.
- */
-static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
+static int proc_fd_access_allowed(struct inode *inode)
 {
-	struct dentry *de, *base;
-	struct vfsmount *our_vfsmnt, *mnt;
-	int res = 0;
-
-	read_lock(&current->fs->lock);
-	our_vfsmnt = mntget(current->fs->rootmnt);
-	base = dget(current->fs->root);
-	read_unlock(&current->fs->lock);
-
-	spin_lock(&vfsmount_lock);
-	de = root;
-	mnt = vfsmnt;
-
-	while (mnt != our_vfsmnt) {
-		if (mnt == mnt->mnt_parent)
-			goto out;
-		de = mnt->mnt_mountpoint;
-		mnt = mnt->mnt_parent;
+	struct task_struct *task;
+	int allowed = 0;
+	/* Allow access to a task's file descriptors if it is us or we
+	 * may use ptrace attach to the process and find out that
+	 * information.
+	 */
+	task = get_proc_task(inode);
+	if (task) {
+		allowed = ptrace_may_attach(task);
+		put_task_struct(task);
 	}
-
-	if (!is_subdir(de, base))
-		goto out;
-	spin_unlock(&vfsmount_lock);
-
-exit:
-	dput(base);
-	mntput(our_vfsmnt);
-	dput(root);
-	mntput(vfsmnt);
-	return res;
-out:
-	spin_unlock(&vfsmount_lock);
-	res = -EACCES;
-	goto exit;
+	return allowed;
 }
 
-static int proc_check_root(struct inode *inode)
-{
-	struct dentry *root;
-	struct vfsmount *vfsmnt;
-
-	if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
-		return -ENOENT;
-	return proc_check_chroot(root, vfsmnt);
-}
-
-static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-	if (generic_permission(inode, mask, NULL) != 0)
-		return -EACCES;
-	return proc_check_root(inode);
-}
-
-static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-	struct dentry *root;
-	struct vfsmount *vfsmnt;
-
-	if (generic_permission(inode, mask, NULL) != 0)
-		return -EACCES;
-
-	if (proc_task_root_link(inode, &root, &vfsmnt))
-		return -ENOENT;
-
-	return proc_check_chroot(root, vfsmnt);
-}
-
-extern struct seq_operations proc_pid_maps_op;
-static int maps_open(struct inode *inode, struct file *file)
-{
-	struct task_struct *task = proc_task(inode);
-	int ret = seq_open(file, &proc_pid_maps_op);
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		m->private = task;
-	}
-	return ret;
-}
-
-static struct file_operations proc_maps_operations = {
-	.open		= maps_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-#ifdef CONFIG_NUMA
-extern struct seq_operations proc_pid_numa_maps_op;
-static int numa_maps_open(struct inode *inode, struct file *file)
-{
-	struct task_struct *task = proc_task(inode);
-	int ret = seq_open(file, &proc_pid_numa_maps_op);
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		m->private = task;
-	}
-	return ret;
-}
-
-static struct file_operations proc_numa_maps_operations = {
-	.open		= numa_maps_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-#endif
-
-#ifdef CONFIG_MMU
-extern struct seq_operations proc_pid_smaps_op;
-static int smaps_open(struct inode *inode, struct file *file)
-{
-	struct task_struct *task = proc_task(inode);
-	int ret = seq_open(file, &proc_pid_smaps_op);
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		m->private = task;
-	}
-	return ret;
-}
-
-static struct file_operations proc_smaps_operations = {
-	.open		= smaps_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-#endif
-
 extern struct seq_operations mounts_op;
 struct proc_mounts {
 	struct seq_file m;
@@ -679,16 +560,19 @@
 
 static int mounts_open(struct inode *inode, struct file *file)
 {
-	struct task_struct *task = proc_task(inode);
-	struct namespace *namespace;
+	struct task_struct *task = get_proc_task(inode);
+	struct namespace *namespace = NULL;
 	struct proc_mounts *p;
 	int ret = -EINVAL;
 
-	task_lock(task);
-	namespace = task->namespace;
-	if (namespace)
-		get_namespace(namespace);
-	task_unlock(task);
+	if (task) {
+		task_lock(task);
+		namespace = task->namespace;
+		if (namespace)
+			get_namespace(namespace);
+		task_unlock(task);
+		put_task_struct(task);
+	}
 
 	if (namespace) {
 		ret = -ENOMEM;
@@ -745,17 +629,21 @@
 extern struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-	struct task_struct *task = proc_task(inode);
 	int ret = seq_open(file, &mountstats_op);
 
 	if (!ret) {
 		struct seq_file *m = file->private_data;
-		struct namespace *namespace;
-		task_lock(task);
-		namespace = task->namespace;
-		if (namespace)
-			get_namespace(namespace);
-		task_unlock(task);
+		struct namespace *namespace = NULL;
+		struct task_struct *task = get_proc_task(inode);
+
+		if (task) {
+			task_lock(task);
+			namespace = task->namespace;
+			if (namespace)
+				get_namespace(namespace);
+			task_unlock(task);
+			put_task_struct(task);
+		}
 
 		if (namespace)
 			m->private = namespace;
@@ -782,18 +670,27 @@
 	struct inode * inode = file->f_dentry->d_inode;
 	unsigned long page;
 	ssize_t length;
-	struct task_struct *task = proc_task(inode);
+	struct task_struct *task = get_proc_task(inode);
+
+	length = -ESRCH;
+	if (!task)
+		goto out_no_task;
 
 	if (count > PROC_BLOCK_SIZE)
 		count = PROC_BLOCK_SIZE;
+
+	length = -ENOMEM;
 	if (!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
+		goto out;
 
 	length = PROC_I(inode)->op.proc_read(task, (char*)page);
 
 	if (length >= 0)
 		length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
 	free_page(page);
+out:
+	put_task_struct(task);
+out_no_task:
 	return length;
 }
 
@@ -810,12 +707,15 @@
 static ssize_t mem_read(struct file * file, char __user * buf,
 			size_t count, loff_t *ppos)
 {
-	struct task_struct *task = proc_task(file->f_dentry->d_inode);
+	struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
 	char *page;
 	unsigned long src = *ppos;
 	int ret = -ESRCH;
 	struct mm_struct *mm;
 
+	if (!task)
+		goto out_no_task;
+
 	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
 		goto out;
 
@@ -865,6 +765,8 @@
 out_free:
 	free_page((unsigned long) page);
 out:
+	put_task_struct(task);
+out_no_task:
 	return ret;
 }
 
@@ -877,15 +779,20 @@
 {
 	int copied = 0;
 	char *page;
-	struct task_struct *task = proc_task(file->f_dentry->d_inode);
+	struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
 	unsigned long dst = *ppos;
 
-	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
-		return -ESRCH;
+	copied = -ESRCH;
+	if (!task)
+		goto out_no_task;
 
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		goto out;
+
+	copied = -ENOMEM;
 	page = (char *)__get_free_page(GFP_USER);
 	if (!page)
-		return -ENOMEM;
+		goto out;
 
 	while (count > 0) {
 		int this_len, retval;
@@ -908,6 +815,9 @@
 	}
 	*ppos = dst;
 	free_page((unsigned long) page);
+out:
+	put_task_struct(task);
+out_no_task:
 	return copied;
 }
 #endif
@@ -938,13 +848,18 @@
 static ssize_t oom_adjust_read(struct file *file, char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	struct task_struct *task = proc_task(file->f_dentry->d_inode);
-	char buffer[8];
+	struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+	char buffer[PROC_NUMBUF];
 	size_t len;
-	int oom_adjust = task->oomkilladj;
+	int oom_adjust;
 	loff_t __ppos = *ppos;
 
-	len = sprintf(buffer, "%i\n", oom_adjust);
+	if (!task)
+		return -ESRCH;
+	oom_adjust = task->oomkilladj;
+	put_task_struct(task);
+
+	len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
 	if (__ppos >= len)
 		return 0;
 	if (count > len-__ppos)
@@ -958,15 +873,15 @@
 static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	struct task_struct *task = proc_task(file->f_dentry->d_inode);
-	char buffer[8], *end;
+	struct task_struct *task;
+	char buffer[PROC_NUMBUF], *end;
 	int oom_adjust;
 
 	if (!capable(CAP_SYS_RESOURCE))
 		return -EPERM;
-	memset(buffer, 0, 8);
-	if (count > 6)
-		count = 6;
+	memset(buffer, 0, sizeof(buffer));
+	if (count > sizeof(buffer) - 1)
+		count = sizeof(buffer) - 1;
 	if (copy_from_user(buffer, buf, count))
 		return -EFAULT;
 	oom_adjust = simple_strtol(buffer, &end, 0);
@@ -974,7 +889,11 @@
 		return -EINVAL;
 	if (*end == '\n')
 		end++;
+	task = get_proc_task(file->f_dentry->d_inode);
+	if (!task)
+		return -ESRCH;
 	task->oomkilladj = oom_adjust;
+	put_task_struct(task);
 	if (end - buffer == 0)
 		return -EIO;
 	return end - buffer;
@@ -985,22 +904,21 @@
 	.write		= oom_adjust_write,
 };
 
-static struct inode_operations proc_mem_inode_operations = {
-	.permission	= proc_permission,
-};
-
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
 				  size_t count, loff_t *ppos)
 {
 	struct inode * inode = file->f_dentry->d_inode;
-	struct task_struct *task = proc_task(inode);
+	struct task_struct *task = get_proc_task(inode);
 	ssize_t length;
 	char tmpbuf[TMPBUFLEN];
 
+	if (!task)
+		return -ESRCH;
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
 				audit_get_loginuid(task->audit_context));
+	put_task_struct(task);
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
@@ -1010,13 +928,12 @@
 	struct inode * inode = file->f_dentry->d_inode;
 	char *page, *tmp;
 	ssize_t length;
-	struct task_struct *task = proc_task(inode);
 	uid_t loginuid;
 
 	if (!capable(CAP_AUDIT_CONTROL))
 		return -EPERM;
 
-	if (current != task)
+	if (current != pid_task(proc_pid(inode), PIDTYPE_PID))
 		return -EPERM;
 
 	if (count >= PAGE_SIZE)
@@ -1040,7 +957,7 @@
 		goto out_free_page;
 
 	}
-	length = audit_set_loginuid(task, loginuid);
+	length = audit_set_loginuid(current, loginuid);
 	if (likely(length == 0))
 		length = count;
 
@@ -1059,13 +976,16 @@
 static ssize_t seccomp_read(struct file *file, char __user *buf,
 			    size_t count, loff_t *ppos)
 {
-	struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+	struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
 	char __buf[20];
 	loff_t __ppos = *ppos;
 	size_t len;
 
+	if (!tsk)
+		return -ESRCH;
 	/* no need to print the trailing zero, so use only len */
 	len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
+	put_task_struct(tsk);
 	if (__ppos >= len)
 		return 0;
 	if (count > len - __ppos)
@@ -1079,29 +999,43 @@
 static ssize_t seccomp_write(struct file *file, const char __user *buf,
 			     size_t count, loff_t *ppos)
 {
-	struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+	struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
 	char __buf[20], *end;
 	unsigned int seccomp_mode;
+	ssize_t result;
+
+	result = -ESRCH;
+	if (!tsk)
+		goto out_no_task;
 
 	/* can set it only once to be even more secure */
+	result = -EPERM;
 	if (unlikely(tsk->seccomp.mode))
-		return -EPERM;
+		goto out;
 
+	result = -EFAULT;
 	memset(__buf, 0, sizeof(__buf));
 	count = min(count, sizeof(__buf) - 1);
 	if (copy_from_user(__buf, buf, count))
-		return -EFAULT;
+		goto out;
+
 	seccomp_mode = simple_strtoul(__buf, &end, 0);
 	if (*end == '\n')
 		end++;
+	result = -EINVAL;
 	if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
 		tsk->seccomp.mode = seccomp_mode;
 		set_tsk_thread_flag(tsk, TIF_SECCOMP);
 	} else
-		return -EINVAL;
+		goto out;
+	result = -EIO;
 	if (unlikely(!(end - __buf)))
-		return -EIO;
-	return end - __buf;
+		goto out;
+	result = end - __buf;
+out:
+	put_task_struct(tsk);
+out_no_task:
+	return result;
 }
 
 static struct file_operations proc_seccomp_operations = {
@@ -1118,10 +1052,8 @@
 	/* We don't need a base pointer in the /proc filesystem */
 	path_release(nd);
 
-	if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
-		goto out;
-	error = proc_check_root(inode);
-	if (error)
+	/* Are we allowed to snoop on the tasks file descriptors? */
+	if (!proc_fd_access_allowed(inode))
 		goto out;
 
 	error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
@@ -1163,12 +1095,8 @@
 	struct dentry *de;
 	struct vfsmount *mnt = NULL;
 
-	lock_kernel();
-
-	if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
-		goto out;
-	error = proc_check_root(inode);
-	if (error)
+	/* Are we allowed to snoop on the tasks file descriptors? */
+	if (!proc_fd_access_allowed(inode))
 		goto out;
 
 	error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt);
@@ -1179,7 +1107,6 @@
 	dput(de);
 	mntput(mnt);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -1188,21 +1115,20 @@
 	.follow_link	= proc_pid_follow_link
 };
 
-#define NUMBUF 10
-
 static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	struct task_struct *p = proc_task(inode);
+	struct dentry *dentry = filp->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	struct task_struct *p = get_proc_task(inode);
 	unsigned int fd, tid, ino;
 	int retval;
-	char buf[NUMBUF];
+	char buf[PROC_NUMBUF];
 	struct files_struct * files;
 	struct fdtable *fdt;
 
 	retval = -ENOENT;
-	if (!pid_alive(p))
-		goto out;
+	if (!p)
+		goto out_no_task;
 	retval = 0;
 	tid = p->pid;
 
@@ -1213,7 +1139,7 @@
 				goto out;
 			filp->f_pos++;
 		case 1:
-			ino = fake_ino(tid, PROC_TID_INO);
+			ino = parent_ino(dentry);
 			if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
 				goto out;
 			filp->f_pos++;
@@ -1232,7 +1158,7 @@
 					continue;
 				rcu_read_unlock();
 
-				j = NUMBUF;
+				j = PROC_NUMBUF;
 				i = fd;
 				do {
 					j--;
@@ -1241,7 +1167,7 @@
 				} while (i);
 
 				ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
-				if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
+				if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
 					rcu_read_lock();
 					break;
 				}
@@ -1251,6 +1177,8 @@
 			put_files_struct(files);
 	}
 out:
+	put_task_struct(p);
+out_no_task:
 	return retval;
 }
 
@@ -1262,16 +1190,18 @@
 	int pid;
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
+	struct task_struct *task = get_proc_task(inode);
 	struct pid_entry *p;
 	ino_t ino;
 	int ret;
 
 	ret = -ENOENT;
-	if (!pid_alive(proc_task(inode)))
+	if (!task)
 		goto out;
 
 	ret = 0;
-	pid = proc_task(inode)->pid;
+	pid = task->pid;
+	put_task_struct(task);
 	i = filp->f_pos;
 	switch (i) {
 	case 0:
@@ -1354,22 +1284,19 @@
 
 	/* Common stuff */
 	ei = PROC_I(inode);
-	ei->task = NULL;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_ino = fake_ino(task->pid, ino);
 
-	if (!pid_alive(task))
-		goto out_unlock;
-
 	/*
 	 * grab the reference to task.
 	 */
-	get_task_struct(task);
-	ei->task = task;
-	ei->type = ino;
+	ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
+	if (!ei->pid)
+		goto out_unlock;
+
 	inode->i_uid = 0;
 	inode->i_gid = 0;
-	if (ino == PROC_TGID_INO || ino == PROC_TID_INO || task_dumpable(task)) {
+	if (task_dumpable(task)) {
 		inode->i_uid = task->euid;
 		inode->i_gid = task->egid;
 	}
@@ -1379,7 +1306,6 @@
 	return inode;
 
 out_unlock:
-	ei->pde = NULL;
 	iput(inode);
 	return NULL;
 }
@@ -1393,13 +1319,21 @@
  *
  * Rewrite the inode's ownerships here because the owning task may have
  * performed a setuid(), etc.
+ *
+ * Before the /proc/pid/status file was created the only way to read
+ * the effective uid of a /process was to stat /proc/pid.  Reading
+ * /proc/pid/status is slow enough that procps and other packages
+ * kept stating /proc/pid.  To keep the rules in /proc simple I have
+ * made this apply to all per process world readable and executable
+ * directories.
  */
 static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
-	struct task_struct *task = proc_task(inode);
-	if (pid_alive(task)) {
-		if (proc_type(inode) == PROC_TGID_INO || proc_type(inode) == PROC_TID_INO || task_dumpable(task)) {
+	struct task_struct *task = get_proc_task(inode);
+	if (task) {
+		if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+		    task_dumpable(task)) {
 			inode->i_uid = task->euid;
 			inode->i_gid = task->egid;
 		} else {
@@ -1407,50 +1341,66 @@
 			inode->i_gid = 0;
 		}
 		security_task_to_inode(task, inode);
+		put_task_struct(task);
 		return 1;
 	}
 	d_drop(dentry);
 	return 0;
 }
 
-static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
 	struct inode *inode = dentry->d_inode;
-	struct task_struct *task = proc_task(inode);
-	int fd = proc_type(inode) - PROC_TID_FD_DIR;
-	struct files_struct *files;
+	struct task_struct *task;
+	generic_fillattr(inode, stat);
 
-	files = get_files_struct(task);
-	if (files) {
-		rcu_read_lock();
-		if (fcheck_files(files, fd)) {
-			rcu_read_unlock();
-			put_files_struct(files);
-			if (task_dumpable(task)) {
-				inode->i_uid = task->euid;
-				inode->i_gid = task->egid;
-			} else {
-				inode->i_uid = 0;
-				inode->i_gid = 0;
-			}
-			security_task_to_inode(task, inode);
-			return 1;
+	rcu_read_lock();
+	stat->uid = 0;
+	stat->gid = 0;
+	task = pid_task(proc_pid(inode), PIDTYPE_PID);
+	if (task) {
+		if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+		    task_dumpable(task)) {
+			stat->uid = task->euid;
+			stat->gid = task->egid;
 		}
-		rcu_read_unlock();
-		put_files_struct(files);
 	}
-	d_drop(dentry);
+	rcu_read_unlock();
 	return 0;
 }
 
-static void pid_base_iput(struct dentry *dentry, struct inode *inode)
+static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-	struct task_struct *task = proc_task(inode);
-	spin_lock(&task->proc_lock);
-	if (task->proc_dentry == dentry)
-		task->proc_dentry = NULL;
-	spin_unlock(&task->proc_lock);
-	iput(inode);
+	struct inode *inode = dentry->d_inode;
+	struct task_struct *task = get_proc_task(inode);
+	int fd = proc_fd(inode);
+	struct files_struct *files;
+
+	if (task) {
+		files = get_files_struct(task);
+		if (files) {
+			rcu_read_lock();
+			if (fcheck_files(files, fd)) {
+				rcu_read_unlock();
+				put_files_struct(files);
+				if (task_dumpable(task)) {
+					inode->i_uid = task->euid;
+					inode->i_gid = task->egid;
+				} else {
+					inode->i_uid = 0;
+					inode->i_gid = 0;
+				}
+				security_task_to_inode(task, inode);
+				put_task_struct(task);
+				return 1;
+			}
+			rcu_read_unlock();
+			put_files_struct(files);
+		}
+		put_task_struct(task);
+	}
+	d_drop(dentry);
+	return 0;
 }
 
 static int pid_delete_dentry(struct dentry * dentry)
@@ -1459,7 +1409,7 @@
 	 * If so, then don't put the dentry on the lru list,
 	 * kill it immediately.
 	 */
-	return !pid_alive(proc_task(dentry->d_inode));
+	return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
 }
 
 static struct dentry_operations tid_fd_dentry_operations =
@@ -1474,13 +1424,6 @@
 	.d_delete	= pid_delete_dentry,
 };
 
-static struct dentry_operations pid_base_dentry_operations =
-{
-	.d_revalidate	= pid_revalidate,
-	.d_iput		= pid_base_iput,
-	.d_delete	= pid_delete_dentry,
-};
-
 /* Lookups */
 
 static unsigned name_to_int(struct dentry *dentry)
@@ -1508,22 +1451,24 @@
 /* SMP-safe */
 static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
 {
-	struct task_struct *task = proc_task(dir);
+	struct task_struct *task = get_proc_task(dir);
 	unsigned fd = name_to_int(dentry);
+	struct dentry *result = ERR_PTR(-ENOENT);
 	struct file * file;
 	struct files_struct * files;
 	struct inode *inode;
 	struct proc_inode *ei;
 
+	if (!task)
+		goto out_no_task;
 	if (fd == ~0U)
 		goto out;
-	if (!pid_alive(task))
-		goto out;
 
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
 	if (!inode)
 		goto out;
 	ei = PROC_I(inode);
+	ei->fd = fd;
 	files = get_files_struct(task);
 	if (!files)
 		goto out_unlock;
@@ -1548,19 +1493,25 @@
 	ei->op.proc_get_link = proc_fd_link;
 	dentry->d_op = &tid_fd_dentry_operations;
 	d_add(dentry, inode);
-	return NULL;
+	/* Close the race of the process dying before we return the dentry */
+	if (tid_fd_revalidate(dentry, NULL))
+		result = NULL;
+out:
+	put_task_struct(task);
+out_no_task:
+	return result;
 
 out_unlock2:
 	spin_unlock(&files->file_lock);
 	put_files_struct(files);
 out_unlock:
 	iput(inode);
-out:
-	return ERR_PTR(-ENOENT);
+	goto out;
 }
 
 static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd);
+static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
 
 static struct file_operations proc_fd_operations = {
 	.read		= generic_read_dir,
@@ -1577,12 +1528,11 @@
  */
 static struct inode_operations proc_fd_inode_operations = {
 	.lookup		= proc_lookupfd,
-	.permission	= proc_permission,
 };
 
 static struct inode_operations proc_task_inode_operations = {
 	.lookup		= proc_task_lookup,
-	.permission	= proc_task_permission,
+	.getattr	= proc_task_getattr,
 };
 
 #ifdef CONFIG_SECURITY
@@ -1592,12 +1542,17 @@
 	struct inode * inode = file->f_dentry->d_inode;
 	unsigned long page;
 	ssize_t length;
-	struct task_struct *task = proc_task(inode);
+	struct task_struct *task = get_proc_task(inode);
+
+	length = -ESRCH;
+	if (!task)
+		goto out_no_task;
 
 	if (count > PAGE_SIZE)
 		count = PAGE_SIZE;
+	length = -ENOMEM;
 	if (!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
+		goto out;
 
 	length = security_getprocattr(task, 
 				      (char*)file->f_dentry->d_name.name, 
@@ -1605,6 +1560,9 @@
 	if (length >= 0)
 		length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
 	free_page(page);
+out:
+	put_task_struct(task);
+out_no_task:
 	return length;
 }
 
@@ -1614,26 +1572,36 @@
 	struct inode * inode = file->f_dentry->d_inode;
 	char *page; 
 	ssize_t length; 
-	struct task_struct *task = proc_task(inode); 
+	struct task_struct *task = get_proc_task(inode);
 
+	length = -ESRCH;
+	if (!task)
+		goto out_no_task;
 	if (count > PAGE_SIZE) 
 		count = PAGE_SIZE; 
-	if (*ppos != 0) {
-		/* No partial writes. */
-		return -EINVAL;
-	}
+
+	/* No partial writes. */
+	length = -EINVAL;
+	if (*ppos != 0)
+		goto out;
+
+	length = -ENOMEM;
 	page = (char*)__get_free_page(GFP_USER); 
 	if (!page) 
-		return -ENOMEM;
+		goto out;
+
 	length = -EFAULT; 
 	if (copy_from_user(page, buf, count)) 
-		goto out;
+		goto out_free;
 
 	length = security_setprocattr(task, 
 				      (char*)file->f_dentry->d_name.name, 
 				      (void*)page, count);
-out:
+out_free:
 	free_page((unsigned long) page);
+out:
+	put_task_struct(task);
+out_no_task:
 	return length;
 } 
 
@@ -1648,24 +1616,22 @@
 static struct inode_operations proc_tgid_attr_inode_operations;
 #endif
 
-static int get_tid_list(int index, unsigned int *tids, struct inode *dir);
-
 /* SMP-safe */
 static struct dentry *proc_pident_lookup(struct inode *dir, 
 					 struct dentry *dentry,
 					 struct pid_entry *ents)
 {
 	struct inode *inode;
-	int error;
-	struct task_struct *task = proc_task(dir);
+	struct dentry *error;
+	struct task_struct *task = get_proc_task(dir);
 	struct pid_entry *p;
 	struct proc_inode *ei;
 
-	error = -ENOENT;
+	error = ERR_PTR(-ENOENT);
 	inode = NULL;
 
-	if (!pid_alive(task))
-		goto out;
+	if (!task)
+		goto out_no_task;
 
 	for (p = ents; p->name; p++) {
 		if (p->len != dentry->d_name.len)
@@ -1676,7 +1642,7 @@
 	if (!p->name)
 		goto out;
 
-	error = -EINVAL;
+	error = ERR_PTR(-EINVAL);
 	inode = proc_pid_make_inode(dir->i_sb, task, p->type);
 	if (!inode)
 		goto out;
@@ -1689,7 +1655,7 @@
 	 */
 	switch(p->type) {
 		case PROC_TGID_TASK:
-			inode->i_nlink = 2 + get_tid_list(2, NULL, dir);
+			inode->i_nlink = 2;
 			inode->i_op = &proc_task_inode_operations;
 			inode->i_fop = &proc_task_operations;
 			break;
@@ -1759,7 +1725,6 @@
 #endif
 		case PROC_TID_MEM:
 		case PROC_TGID_MEM:
-			inode->i_op = &proc_mem_inode_operations;
 			inode->i_fop = &proc_mem_operations;
 			break;
 #ifdef CONFIG_SECCOMP
@@ -1801,6 +1766,10 @@
 		case PROC_TGID_ATTR_EXEC:
 		case PROC_TID_ATTR_FSCREATE:
 		case PROC_TGID_ATTR_FSCREATE:
+		case PROC_TID_ATTR_KEYCREATE:
+		case PROC_TGID_ATTR_KEYCREATE:
+		case PROC_TID_ATTR_SOCKCREATE:
+		case PROC_TGID_ATTR_SOCKCREATE:
 			inode->i_fop = &proc_pid_attr_operations;
 			break;
 #endif
@@ -1842,14 +1811,18 @@
 		default:
 			printk("procfs: impossible type (%d)",p->type);
 			iput(inode);
-			return ERR_PTR(-EINVAL);
+			error = ERR_PTR(-EINVAL);
+			goto out;
 	}
 	dentry->d_op = &pid_dentry_operations;
 	d_add(dentry, inode);
-	return NULL;
-
+	/* Close the race of the process dying before we return the dentry */
+	if (pid_revalidate(dentry, NULL))
+		error = NULL;
 out:
-	return ERR_PTR(error);
+	put_task_struct(task);
+out_no_task:
+	return error;
 }
 
 static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
@@ -1872,10 +1845,12 @@
 
 static struct inode_operations proc_tgid_base_inode_operations = {
 	.lookup		= proc_tgid_base_lookup,
+	.getattr	= pid_getattr,
 };
 
 static struct inode_operations proc_tid_base_inode_operations = {
 	.lookup		= proc_tid_base_lookup,
+	.getattr	= pid_getattr,
 };
 
 #ifdef CONFIG_SECURITY
@@ -1917,10 +1892,12 @@
 
 static struct inode_operations proc_tgid_attr_inode_operations = {
 	.lookup		= proc_tgid_attr_lookup,
+	.getattr	= pid_getattr,
 };
 
 static struct inode_operations proc_tid_attr_inode_operations = {
 	.lookup		= proc_tid_attr_lookup,
+	.getattr	= pid_getattr,
 };
 #endif
 
@@ -1930,14 +1907,14 @@
 static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
 			      int buflen)
 {
-	char tmp[30];
+	char tmp[PROC_NUMBUF];
 	sprintf(tmp, "%d", current->tgid);
 	return vfs_readlink(dentry,buffer,buflen,tmp);
 }
 
 static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char tmp[30];
+	char tmp[PROC_NUMBUF];
 	sprintf(tmp, "%d", current->tgid);
 	return ERR_PTR(vfs_follow_link(nd,tmp));
 }	
@@ -1948,67 +1925,80 @@
 };
 
 /**
- * proc_pid_unhash -  Unhash /proc/@pid entry from the dcache.
- * @p: task that should be flushed.
+ * proc_flush_task -  Remove dcache entries for @task from the /proc dcache.
  *
- * Drops the /proc/@pid dcache entry from the hash chains.
+ * @task: task that should be flushed.
  *
- * Dropping /proc/@pid entries and detach_pid must be synchroneous,
- * otherwise e.g. /proc/@pid/exe might point to the wrong executable,
- * if the pid value is immediately reused. This is enforced by
- * - caller must acquire spin_lock(p->proc_lock)
- * - must be called before detach_pid()
- * - proc_pid_lookup acquires proc_lock, and checks that
- *   the target is not dead by looking at the attach count
- *   of PIDTYPE_PID.
+ * Looks in the dcache for
+ * /proc/@pid
+ * /proc/@tgid/task/@pid
+ * if either directory is present flushes it and all of it'ts children
+ * from the dcache.
+ *
+ * It is safe and reasonable to cache /proc entries for a task until
+ * that task exits.  After that they just clog up the dcache with
+ * useless entries, possibly causing useful dcache entries to be
+ * flushed instead.  This routine is proved to flush those useless
+ * dcache entries at process exit time.
+ *
+ * NOTE: This routine is just an optimization so it does not guarantee
+ *       that no dcache entries will exist at process exit time it
+ *       just makes it very unlikely that any will persist.
  */
-
-struct dentry *proc_pid_unhash(struct task_struct *p)
+void proc_flush_task(struct task_struct *task)
 {
-	struct dentry *proc_dentry;
+	struct dentry *dentry, *leader, *dir;
+	char buf[PROC_NUMBUF];
+	struct qstr name;
 
-	proc_dentry = p->proc_dentry;
-	if (proc_dentry != NULL) {
-
-		spin_lock(&dcache_lock);
-		spin_lock(&proc_dentry->d_lock);
-		if (!d_unhashed(proc_dentry)) {
-			dget_locked(proc_dentry);
-			__d_drop(proc_dentry);
-			spin_unlock(&proc_dentry->d_lock);
-		} else {
-			spin_unlock(&proc_dentry->d_lock);
-			proc_dentry = NULL;
-		}
-		spin_unlock(&dcache_lock);
+	name.name = buf;
+	name.len = snprintf(buf, sizeof(buf), "%d", task->pid);
+	dentry = d_hash_and_lookup(proc_mnt->mnt_root, &name);
+	if (dentry) {
+		shrink_dcache_parent(dentry);
+		d_drop(dentry);
+		dput(dentry);
 	}
-	return proc_dentry;
-}
 
-/**
- * proc_pid_flush - recover memory used by stale /proc/@pid/x entries
- * @proc_dentry: directoy to prune.
- *
- * Shrink the /proc directory that was used by the just killed thread.
- */
-	
-void proc_pid_flush(struct dentry *proc_dentry)
-{
-	might_sleep();
-	if(proc_dentry != NULL) {
-		shrink_dcache_parent(proc_dentry);
-		dput(proc_dentry);
+	if (thread_group_leader(task))
+		goto out;
+
+	name.name = buf;
+	name.len = snprintf(buf, sizeof(buf), "%d", task->tgid);
+	leader = d_hash_and_lookup(proc_mnt->mnt_root, &name);
+	if (!leader)
+		goto out;
+
+	name.name = "task";
+	name.len = strlen(name.name);
+	dir = d_hash_and_lookup(leader, &name);
+	if (!dir)
+		goto out_put_leader;
+
+	name.name = buf;
+	name.len = snprintf(buf, sizeof(buf), "%d", task->pid);
+	dentry = d_hash_and_lookup(dir, &name);
+	if (dentry) {
+		shrink_dcache_parent(dentry);
+		d_drop(dentry);
+		dput(dentry);
 	}
+
+	dput(dir);
+out_put_leader:
+	dput(leader);
+out:
+	return;
 }
 
 /* SMP-safe */
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
+	struct dentry *result = ERR_PTR(-ENOENT);
 	struct task_struct *task;
 	struct inode *inode;
 	struct proc_inode *ei;
 	unsigned tgid;
-	int died;
 
 	if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) {
 		inode = new_inode(dir->i_sb);
@@ -2029,21 +2019,18 @@
 	if (tgid == ~0U)
 		goto out;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 	task = find_task_by_pid(tgid);
 	if (task)
 		get_task_struct(task);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 	if (!task)
 		goto out;
 
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
+	if (!inode)
+		goto out_put_task;
 
-
-	if (!inode) {
-		put_task_struct(task);
-		goto out;
-	}
 	inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
 	inode->i_op = &proc_tgid_base_inode_operations;
 	inode->i_fop = &proc_tgid_base_operations;
@@ -2054,45 +2041,40 @@
 	inode->i_nlink = 4;
 #endif
 
-	dentry->d_op = &pid_base_dentry_operations;
+	dentry->d_op = &pid_dentry_operations;
 
-	died = 0;
 	d_add(dentry, inode);
-	spin_lock(&task->proc_lock);
-	task->proc_dentry = dentry;
-	if (!pid_alive(task)) {
-		dentry = proc_pid_unhash(task);
-		died = 1;
-	}
-	spin_unlock(&task->proc_lock);
+	/* Close the race of the process dying before we return the dentry */
+	if (pid_revalidate(dentry, NULL))
+		result = NULL;
 
+out_put_task:
 	put_task_struct(task);
-	if (died) {
-		proc_pid_flush(dentry);
-		goto out;
-	}
-	return NULL;
 out:
-	return ERR_PTR(-ENOENT);
+	return result;
 }
 
 /* SMP-safe */
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
+	struct dentry *result = ERR_PTR(-ENOENT);
 	struct task_struct *task;
-	struct task_struct *leader = proc_task(dir);
+	struct task_struct *leader = get_proc_task(dir);
 	struct inode *inode;
 	unsigned tid;
 
+	if (!leader)
+		goto out_no_task;
+
 	tid = name_to_int(dentry);
 	if (tid == ~0U)
 		goto out;
 
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 	task = find_task_by_pid(tid);
 	if (task)
 		get_task_struct(task);
-	read_unlock(&tasklist_lock);
+	rcu_read_unlock();
 	if (!task)
 		goto out;
 	if (leader->tgid != task->tgid)
@@ -2113,101 +2095,95 @@
 	inode->i_nlink = 3;
 #endif
 
-	dentry->d_op = &pid_base_dentry_operations;
+	dentry->d_op = &pid_dentry_operations;
 
 	d_add(dentry, inode);
+	/* Close the race of the process dying before we return the dentry */
+	if (pid_revalidate(dentry, NULL))
+		result = NULL;
 
-	put_task_struct(task);
-	return NULL;
 out_drop_task:
 	put_task_struct(task);
 out:
-	return ERR_PTR(-ENOENT);
-}
-
-#define PROC_NUMBUF 10
-#define PROC_MAXPIDS 20
-
-/*
- * Get a few tgid's to return for filldir - we need to hold the
- * tasklist lock while doing this, and we must release it before
- * we actually do the filldir itself, so we use a temp buffer..
- */
-static int get_tgid_list(int index, unsigned long version, unsigned int *tgids)
-{
-	struct task_struct *p;
-	int nr_tgids = 0;
-
-	index--;
-	read_lock(&tasklist_lock);
-	p = NULL;
-	if (version) {
-		p = find_task_by_pid(version);
-		if (p && !thread_group_leader(p))
-			p = NULL;
-	}
-
-	if (p)
-		index = 0;
-	else
-		p = next_task(&init_task);
-
-	for ( ; p != &init_task; p = next_task(p)) {
-		int tgid = p->pid;
-		if (!pid_alive(p))
-			continue;
-		if (--index >= 0)
-			continue;
-		tgids[nr_tgids] = tgid;
-		nr_tgids++;
-		if (nr_tgids >= PROC_MAXPIDS)
-			break;
-	}
-	read_unlock(&tasklist_lock);
-	return nr_tgids;
+	put_task_struct(leader);
+out_no_task:
+	return result;
 }
 
 /*
- * Get a few tid's to return for filldir - we need to hold the
- * tasklist lock while doing this, and we must release it before
- * we actually do the filldir itself, so we use a temp buffer..
+ * Find the first tgid to return to user space.
+ *
+ * Usually this is just whatever follows &init_task, but if the users
+ * buffer was too small to hold the full list or there was a seek into
+ * the middle of the directory we have more work to do.
+ *
+ * In the case of a short read we start with find_task_by_pid.
+ *
+ * In the case of a seek we start with &init_task and walk nr
+ * threads past it.
  */
-static int get_tid_list(int index, unsigned int *tids, struct inode *dir)
+static struct task_struct *first_tgid(int tgid, unsigned int nr)
 {
-	struct task_struct *leader_task = proc_task(dir);
-	struct task_struct *task = leader_task;
-	int nr_tids = 0;
+	struct task_struct *pos;
+	rcu_read_lock();
+	if (tgid && nr) {
+		pos = find_task_by_pid(tgid);
+		if (pos && thread_group_leader(pos))
+			goto found;
+	}
+	/* If nr exceeds the number of processes get out quickly */
+	pos = NULL;
+	if (nr && nr >= nr_processes())
+		goto done;
 
-	index -= 2;
-	read_lock(&tasklist_lock);
-	/*
-	 * The starting point task (leader_task) might be an already
-	 * unlinked task, which cannot be used to access the task-list
-	 * via next_thread().
+	/* If we haven't found our starting place yet start with
+	 * the init_task and walk nr tasks forward.
 	 */
-	if (pid_alive(task)) do {
-		int tid = task->pid;
+	for (pos = next_task(&init_task); nr > 0; --nr) {
+		pos = next_task(pos);
+		if (pos == &init_task) {
+			pos = NULL;
+			goto done;
+		}
+	}
+found:
+	get_task_struct(pos);
+done:
+	rcu_read_unlock();
+	return pos;
+}
 
-		if (--index >= 0)
-			continue;
-		if (tids != NULL)
-			tids[nr_tids] = tid;
-		nr_tids++;
-		if (nr_tids >= PROC_MAXPIDS)
-			break;
-	} while ((task = next_thread(task)) != leader_task);
-	read_unlock(&tasklist_lock);
-	return nr_tids;
+/*
+ * Find the next task in the task list.
+ * Return NULL if we loop or there is any error.
+ *
+ * The reference to the input task_struct is released.
+ */
+static struct task_struct *next_tgid(struct task_struct *start)
+{
+	struct task_struct *pos;
+	rcu_read_lock();
+	pos = start;
+	if (pid_alive(start))
+		pos = next_task(start);
+	if (pid_alive(pos) && (pos != &init_task)) {
+		get_task_struct(pos);
+		goto done;
+	}
+	pos = NULL;
+done:
+	rcu_read_unlock();
+	put_task_struct(start);
+	return pos;
 }
 
 /* for the /proc/ directory itself, after non-process stuff has been done */
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-	unsigned int tgid_array[PROC_MAXPIDS];
 	char buf[PROC_NUMBUF];
 	unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
-	unsigned int nr_tgids, i;
-	int next_tgid;
+	struct task_struct *task;
+	int tgid;
 
 	if (!nr) {
 		ino_t ino = fake_ino(0,PROC_TGID_INO);
@@ -2216,63 +2192,116 @@
 		filp->f_pos++;
 		nr++;
 	}
+	nr -= 1;
 
 	/* f_version caches the tgid value that the last readdir call couldn't
 	 * return. lseek aka telldir automagically resets f_version to 0.
 	 */
-	next_tgid = filp->f_version;
+	tgid = filp->f_version;
 	filp->f_version = 0;
-	for (;;) {
-		nr_tgids = get_tgid_list(nr, next_tgid, tgid_array);
-		if (!nr_tgids) {
-			/* no more entries ! */
+	for (task = first_tgid(tgid, nr);
+	     task;
+	     task = next_tgid(task), filp->f_pos++) {
+		int len;
+		ino_t ino;
+		tgid = task->pid;
+		len = snprintf(buf, sizeof(buf), "%d", tgid);
+		ino = fake_ino(tgid, PROC_TGID_INO);
+		if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
+			/* returning this tgid failed, save it as the first
+			 * pid for the next readir call */
+			filp->f_version = tgid;
+			put_task_struct(task);
 			break;
 		}
-		next_tgid = 0;
+	}
+	return 0;
+}
 
-		/* do not use the last found pid, reserve it for next_tgid */
-		if (nr_tgids == PROC_MAXPIDS) {
-			nr_tgids--;
-			next_tgid = tgid_array[nr_tgids];
-		}
+/*
+ * Find the first tid of a thread group to return to user space.
+ *
+ * Usually this is just the thread group leader, but if the users
+ * buffer was too small or there was a seek into the middle of the
+ * directory we have more work todo.
+ *
+ * In the case of a short read we start with find_task_by_pid.
+ *
+ * In the case of a seek we start with the leader and walk nr
+ * threads past it.
+ */
+static struct task_struct *first_tid(struct task_struct *leader,
+					int tid, int nr)
+{
+	struct task_struct *pos;
 
-		for (i=0;i<nr_tgids;i++) {
-			int tgid = tgid_array[i];
-			ino_t ino = fake_ino(tgid,PROC_TGID_INO);
-			unsigned long j = PROC_NUMBUF;
+	rcu_read_lock();
+	/* Attempt to start with the pid of a thread */
+	if (tid && (nr > 0)) {
+		pos = find_task_by_pid(tid);
+		if (pos && (pos->group_leader == leader))
+			goto found;
+	}
 
-			do
-				buf[--j] = '0' + (tgid % 10);
-			while ((tgid /= 10) != 0);
+	/* If nr exceeds the number of threads there is nothing todo */
+	pos = NULL;
+	if (nr && nr >= get_nr_threads(leader))
+		goto out;
 
-			if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino, DT_DIR) < 0) {
-				/* returning this tgid failed, save it as the first
-				 * pid for the next readir call */
-				filp->f_version = tgid_array[i];
-				goto out;
-			}
-			filp->f_pos++;
-			nr++;
+	/* If we haven't found our starting place yet start
+	 * with the leader and walk nr threads forward.
+	 */
+	for (pos = leader; nr > 0; --nr) {
+		pos = next_thread(pos);
+		if (pos == leader) {
+			pos = NULL;
+			goto out;
 		}
 	}
+found:
+	get_task_struct(pos);
 out:
-	return 0;
+	rcu_read_unlock();
+	return pos;
+}
+
+/*
+ * Find the next thread in the thread list.
+ * Return NULL if there is an error or no next thread.
+ *
+ * The reference to the input task_struct is released.
+ */
+static struct task_struct *next_tid(struct task_struct *start)
+{
+	struct task_struct *pos = NULL;
+	rcu_read_lock();
+	if (pid_alive(start)) {
+		pos = next_thread(start);
+		if (thread_group_leader(pos))
+			pos = NULL;
+		else
+			get_task_struct(pos);
+	}
+	rcu_read_unlock();
+	put_task_struct(start);
+	return pos;
 }
 
 /* for the /proc/TGID/task/ directories */
 static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-	unsigned int tid_array[PROC_MAXPIDS];
 	char buf[PROC_NUMBUF];
-	unsigned int nr_tids, i;
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
+	struct task_struct *leader = get_proc_task(inode);
+	struct task_struct *task;
 	int retval = -ENOENT;
 	ino_t ino;
+	int tid;
 	unsigned long pos = filp->f_pos;  /* avoiding "long long" filp->f_pos */
 
-	if (!pid_alive(proc_task(inode)))
-		goto out;
+	if (!leader)
+		goto out_no_task;
 	retval = 0;
 
 	switch (pos) {
@@ -2290,24 +2319,45 @@
 		/* fall through */
 	}
 
-	nr_tids = get_tid_list(pos, tid_array, inode);
-	inode->i_nlink = pos + nr_tids;
-
-	for (i = 0; i < nr_tids; i++) {
-		unsigned long j = PROC_NUMBUF;
-		int tid = tid_array[i];
-
-		ino = fake_ino(tid,PROC_TID_INO);
-
-		do
-			buf[--j] = '0' + (tid % 10);
-		while ((tid /= 10) != 0);
-
-		if (filldir(dirent, buf+j, PROC_NUMBUF-j, pos, ino, DT_DIR) < 0)
+	/* f_version caches the tgid value that the last readdir call couldn't
+	 * return. lseek aka telldir automagically resets f_version to 0.
+	 */
+	tid = filp->f_version;
+	filp->f_version = 0;
+	for (task = first_tid(leader, tid, pos - 2);
+	     task;
+	     task = next_tid(task), pos++) {
+		int len;
+		tid = task->pid;
+		len = snprintf(buf, sizeof(buf), "%d", tid);
+		ino = fake_ino(tid, PROC_TID_INO);
+		if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
+			/* returning this tgid failed, save it as the first
+			 * pid for the next readir call */
+			filp->f_version = tid;
+			put_task_struct(task);
 			break;
-		pos++;
+		}
 	}
 out:
 	filp->f_pos = pos;
+	put_task_struct(leader);
+out_no_task:
 	return retval;
 }
+
+static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+	struct inode *inode = dentry->d_inode;
+	struct task_struct *p = get_proc_task(inode);
+	generic_fillattr(inode, stat);
+
+	if (p) {
+		rcu_read_lock();
+		stat->nlink += get_nr_threads(p);
+		rcu_read_unlock();
+		put_task_struct(p);
+	}
+
+	return 0;
+}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 722b9c4..6dcef08 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -58,14 +58,11 @@
 static void proc_delete_inode(struct inode *inode)
 {
 	struct proc_dir_entry *de;
-	struct task_struct *tsk;
 
 	truncate_inode_pages(&inode->i_data, 0);
 
-	/* Let go of any associated process */
-	tsk = PROC_I(inode)->task;
-	if (tsk)
-		put_task_struct(tsk);
+	/* Stop tracking associated processes */
+	put_pid(PROC_I(inode)->pid);
 
 	/* Let go of any associated proc directory entry */
 	de = PROC_I(inode)->pde;
@@ -94,8 +91,8 @@
 	ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL);
 	if (!ei)
 		return NULL;
-	ei->task = NULL;
-	ei->type = 0;
+	ei->pid = NULL;
+	ei->fd = 0;
 	ei->op.proc_get_link = NULL;
 	ei->pde = NULL;
 	inode = &ei->vfs_inode;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 0502f17..146a434 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -37,16 +37,30 @@
 extern int proc_pid_status(struct task_struct *, char *);
 extern int proc_pid_statm(struct task_struct *, char *);
 
+extern struct file_operations proc_maps_operations;
+extern struct file_operations proc_numa_maps_operations;
+extern struct file_operations proc_smaps_operations;
+
+extern struct file_operations proc_maps_operations;
+extern struct file_operations proc_numa_maps_operations;
+extern struct file_operations proc_smaps_operations;
+
+
 void free_proc_entry(struct proc_dir_entry *de);
 
 int proc_init_inodecache(void);
 
-static inline struct task_struct *proc_task(struct inode *inode)
+static inline struct pid *proc_pid(struct inode *inode)
 {
-	return PROC_I(inode)->task;
+	return PROC_I(inode)->pid;
 }
 
-static inline int proc_type(struct inode *inode)
+static inline struct task_struct *get_proc_task(struct inode *inode)
 {
-	return PROC_I(inode)->type;
+	return get_pid_task(proc_pid(inode), PIDTYPE_PID);
+}
+
+static inline int proc_fd(struct inode *inode)
+{
+	return PROC_I(inode)->fd;
 }
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 91b7c15..0137ec4 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -75,9 +75,13 @@
 {
 	struct vm_area_struct * vma;
 	int result = -ENOENT;
-	struct task_struct *task = proc_task(inode);
-	struct mm_struct * mm = get_task_mm(task);
+	struct task_struct *task = get_proc_task(inode);
+	struct mm_struct * mm = NULL;
 
+	if (task) {
+		mm = get_task_mm(task);
+		put_task_struct(task);
+	}
 	if (!mm)
 		goto out;
 	down_read(&mm->mmap_sem);
@@ -120,7 +124,8 @@
 
 static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
 {
-	struct task_struct *task = m->private;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
 	struct vm_area_struct *vma = v;
 	struct mm_struct *mm = vma->vm_mm;
 	struct file *file = vma->vm_file;
@@ -295,12 +300,16 @@
 
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
-	struct task_struct *task = m->private;
+	struct proc_maps_private *priv = m->private;
 	unsigned long last_addr = m->version;
 	struct mm_struct *mm;
-	struct vm_area_struct *vma, *tail_vma;
+	struct vm_area_struct *vma, *tail_vma = NULL;
 	loff_t l = *pos;
 
+	/* Clear the per syscall fields in priv */
+	priv->task = NULL;
+	priv->tail_vma = NULL;
+
 	/*
 	 * We remember last_addr rather than next_addr to hit with
 	 * mmap_cache most of the time. We have zero last_addr at
@@ -311,11 +320,15 @@
 	if (last_addr == -1UL)
 		return NULL;
 
-	mm = get_task_mm(task);
+	priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
+	if (!priv->task)
+		return NULL;
+
+	mm = get_task_mm(priv->task);
 	if (!mm)
 		return NULL;
 
-	tail_vma = get_gate_vma(task);
+	priv->tail_vma = tail_vma = get_gate_vma(priv->task);
 	down_read(&mm->mmap_sem);
 
 	/* Start with last addr hint */
@@ -350,11 +363,9 @@
 	return tail_vma;
 }
 
-static void m_stop(struct seq_file *m, void *v)
+static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
 {
-	struct task_struct *task = m->private;
-	struct vm_area_struct *vma = v;
-	if (vma && vma != get_gate_vma(task)) {
+	if (vma && vma != priv->tail_vma) {
 		struct mm_struct *mm = vma->vm_mm;
 		up_read(&mm->mmap_sem);
 		mmput(mm);
@@ -363,38 +374,103 @@
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	struct task_struct *task = m->private;
+	struct proc_maps_private *priv = m->private;
 	struct vm_area_struct *vma = v;
-	struct vm_area_struct *tail_vma = get_gate_vma(task);
+	struct vm_area_struct *tail_vma = priv->tail_vma;
 
 	(*pos)++;
 	if (vma && (vma != tail_vma) && vma->vm_next)
 		return vma->vm_next;
-	m_stop(m, v);
+	vma_stop(priv, vma);
 	return (vma != tail_vma)? tail_vma: NULL;
 }
 
-struct seq_operations proc_pid_maps_op = {
+static void m_stop(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct vm_area_struct *vma = v;
+
+	vma_stop(priv, vma);
+	if (priv->task)
+		put_task_struct(priv->task);
+}
+
+static struct seq_operations proc_pid_maps_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
 	.show	= show_map
 };
 
-struct seq_operations proc_pid_smaps_op = {
+static struct seq_operations proc_pid_smaps_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
 	.show	= show_smap
 };
 
+static int do_maps_open(struct inode *inode, struct file *file,
+			struct seq_operations *ops)
+{
+	struct proc_maps_private *priv;
+	int ret = -ENOMEM;
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (priv) {
+		priv->pid = proc_pid(inode);
+		ret = seq_open(file, ops);
+		if (!ret) {
+			struct seq_file *m = file->private_data;
+			m->private = priv;
+		} else {
+			kfree(priv);
+		}
+	}
+	return ret;
+}
+
+static int maps_open(struct inode *inode, struct file *file)
+{
+	return do_maps_open(inode, file, &proc_pid_maps_op);
+}
+
+struct file_operations proc_maps_operations = {
+	.open		= maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
-struct seq_operations proc_pid_numa_maps_op = {
+static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
         .show   = show_numa_map
 };
+
+static int numa_maps_open(struct inode *inode, struct file *file)
+{
+	return do_maps_open(inode, file, &proc_pid_numa_maps_op);
+}
+
+struct file_operations proc_numa_maps_operations = {
+	.open		= numa_maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
 #endif
+
+static int smaps_open(struct inode *inode, struct file *file)
+{
+	return do_maps_open(inode, file, &proc_pid_smaps_op);
+}
+
+struct file_operations proc_smaps_operations = {
+	.open		= smaps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 8f68827..af69f28 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -156,9 +156,28 @@
 {
 	return NULL;
 }
-struct seq_operations proc_pid_maps_op = {
+static struct seq_operations proc_pid_maps_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
 	.show	= show_map
 };
+
+static int maps_open(struct inode *inode, struct file *file)
+{
+	int ret;
+	ret = seq_open(file, &proc_pid_maps_op);
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		m->private = NULL;
+	}
+	return ret;
+}
+
+struct file_operations proc_maps_operations = {
+	.open		= maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index cf6e1cf..752cea1 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1560,12 +1560,6 @@
 	return res;
 }
 
-static ssize_t reiserfs_aio_write(struct kiocb *iocb, const char __user * buf,
-				  size_t count, loff_t pos)
-{
-	return generic_file_aio_write(iocb, buf, count, pos);
-}
-
 const struct file_operations reiserfs_file_operations = {
 	.read = generic_file_read,
 	.write = reiserfs_file_write,
@@ -1575,7 +1569,7 @@
 	.fsync = reiserfs_sync_file,
 	.sendfile = generic_file_sendfile,
 	.aio_read = generic_file_aio_read,
-	.aio_write = reiserfs_aio_write,
+	.aio_write = generic_file_aio_write,
 	.splice_read = generic_file_splice_read,
 	.splice_write = generic_file_splice_write,
 };
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 1b73529..49d1a53 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -834,8 +834,7 @@
 		get_bh(bh);
 		if (test_set_buffer_locked(bh)) {
 			if (!buffer_dirty(bh)) {
-				list_del_init(&jh->list);
-				list_add(&jh->list, &tmp);
+				list_move(&jh->list, &tmp);
 				goto loop_next;
 			}
 			spin_unlock(lock);
@@ -855,8 +854,7 @@
 			ret = -EIO;
 		}
 		if (buffer_dirty(bh)) {
-			list_del_init(&jh->list);
-			list_add(&jh->list, &tmp);
+			list_move(&jh->list, &tmp);
 			add_to_chunk(&chunk, bh, lock, write_ordered_chunk);
 		} else {
 			reiserfs_free_jh(bh);
diff --git a/fs/select.c b/fs/select.c
index 9c4f0f2..33b72ba 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -746,9 +746,9 @@
 asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
 			long timeout_msecs)
 {
-	s64 timeout_jiffies = 0;
+	s64 timeout_jiffies;
 
-	if (timeout_msecs) {
+	if (timeout_msecs > 0) {
 #if HZ > 1000
 		/* We can only overflow if HZ > 1000 */
 		if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ)
@@ -756,6 +756,9 @@
 		else
 #endif
 			timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+	} else {
+		/* Infinite (< 0) or no (0) timeout */
+		timeout_jiffies = timeout_msecs;
 	}
 
 	return do_sys_poll(ufds, nfds, &timeout_jiffies);
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
index c71dd27..c8e9619 100644
--- a/fs/smbfs/request.c
+++ b/fs/smbfs/request.c
@@ -400,8 +400,7 @@
 	if (!(req->rq_flags & SMB_REQ_TRANSMITTED))
 		goto out;
 
-	list_del_init(&req->rq_queue);
-	list_add_tail(&req->rq_queue, &server->recvq);
+	list_move_tail(&req->rq_queue, &server->recvq);
 	result = 1;
 out:
 	return result;
@@ -435,8 +434,7 @@
 	result = smb_request_send_req(req);
 	if (result < 0) {
 		server->conn_error = result;
-		list_del_init(&req->rq_queue);
-		list_add(&req->rq_queue, &server->xmitq);
+		list_move(&req->rq_queue, &server->xmitq);
 		result = -EIO;
 		goto out;
 	}
diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
index 481a97a..24577e2 100644
--- a/fs/smbfs/smbiod.c
+++ b/fs/smbfs/smbiod.c
@@ -20,6 +20,7 @@
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/net.h>
+#include <linux/kthread.h>
 #include <net/ip.h>
 
 #include <linux/smb_fs.h>
@@ -40,7 +41,7 @@
 };
 
 static enum smbiod_state smbiod_state = SMBIOD_DEAD;
-static pid_t smbiod_pid;
+static struct task_struct *smbiod_thread;
 static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
 static LIST_HEAD(smb_servers);
 static DEFINE_SPINLOCK(servers_lock);
@@ -67,20 +68,29 @@
  */
 static int smbiod_start(void)
 {
-	pid_t pid;
+	struct task_struct *tsk;
+	int err = 0;
+
 	if (smbiod_state != SMBIOD_DEAD)
 		return 0;
 	smbiod_state = SMBIOD_STARTING;
 	__module_get(THIS_MODULE);
 	spin_unlock(&servers_lock);
-	pid = kernel_thread(smbiod, NULL, 0);
-	if (pid < 0)
+	tsk = kthread_run(smbiod, NULL, "smbiod");
+	if (IS_ERR(tsk)) {
+		err = PTR_ERR(tsk);
 		module_put(THIS_MODULE);
+	}
 
 	spin_lock(&servers_lock);
-	smbiod_state = pid < 0 ? SMBIOD_DEAD : SMBIOD_RUNNING;
-	smbiod_pid = pid;
-	return pid;
+	if (err < 0) {
+		smbiod_state = SMBIOD_DEAD;
+		smbiod_thread = NULL;
+	} else {
+		smbiod_state = SMBIOD_RUNNING;
+		smbiod_thread = tsk;
+	}
+	return err;
 }
 
 /*
@@ -183,8 +193,7 @@
 		if (req->rq_flags & SMB_REQ_RETRY) {
 			/* must move the request to the xmitq */
 			VERBOSE("retrying request %p on recvq\n", req);
-			list_del(&req->rq_queue);
-			list_add(&req->rq_queue, &server->xmitq);
+			list_move(&req->rq_queue, &server->xmitq);
 			continue;
 		}
 #endif
@@ -290,8 +299,6 @@
  */
 static int smbiod(void *unused)
 {
-	daemonize("smbiod");
-
 	allow_signal(SIGKILL);
 
 	VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
diff --git a/fs/super.c b/fs/super.c
index 057b5325..8a669f6 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -871,8 +871,6 @@
 	return mnt;
 }
 
-EXPORT_SYMBOL_GPL(do_kern_mount);
-
 struct vfsmount *kern_mount(struct file_system_type *type)
 {
 	return vfs_kern_mount(type, 0, type->name, NULL);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 610b5bd..61c4243 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -430,10 +430,9 @@
 			i++;
 			/* fallthrough */
 		default:
-			if (filp->f_pos == 2) {
-				list_del(q);
-				list_add(q, &parent_sd->s_children);
-			}
+			if (filp->f_pos == 2)
+				list_move(q, &parent_sd->s_children);
+
 			for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
 				struct sysfs_dirent *next;
 				const char * name;
@@ -455,8 +454,7 @@
 						 dt_type(next)) < 0)
 					return 0;
 
-				list_del(q);
-				list_add(q, p);
+				list_move(q, p);
 				p = q;
 				filp->f_pos++;
 			}
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 3ada9dc..95b878e 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -21,14 +21,6 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_BALLOC_DEBUG
-
-#ifdef UFS_BALLOC_DEBUG
-#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
 static unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
 static unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
 static unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
@@ -39,7 +31,8 @@
 /*
  * Free 'count' fragments from fragment number 'fragment'
  */
-void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) {
+void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count)
+{
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
@@ -51,7 +44,7 @@
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(uspi);
 	
-	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+	UFSD("ENTER, fragment %u, count %u\n", fragment, count);
 	
 	if (ufs_fragnum(fragment) + count > uspi->s_fpg)
 		ufs_error (sb, "ufs_free_fragments", "internal error");
@@ -68,7 +61,7 @@
 	ucpi = ufs_load_cylinder (sb, cgno);
 	if (!ucpi) 
 		goto failed;
-	ucg = ubh_get_ucg (UCPI_UBH);
+	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
 	if (!ufs_cg_chkmagic(sb, ucg)) {
 		ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
 		goto failed;
@@ -76,11 +69,11 @@
 
 	end_bit = bit + count;
 	bbase = ufs_blknum (bit);
-	blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+	blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
 	ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
 	for (i = bit; i < end_bit; i++) {
-		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
-			ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
+		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
+			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
 		else 
 			ufs_error (sb, "ufs_free_fragments",
 				   "bit already cleared for fragment %u", i);
@@ -90,51 +83,52 @@
 
 	
 	fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
-	fs32_add(sb, &usb1->fs_cstotal.cs_nffree, count);
+	uspi->cs_total.cs_nffree += count;
 	fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
-	blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+	blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
 	ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
 
 	/*
 	 * Trying to reassemble free fragments into block
 	 */
 	blkno = ufs_fragstoblks (bbase);
-	if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+	if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
 		fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
-		fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
+		uspi->cs_total.cs_nffree -= uspi->s_fpb;
 		fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
 		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
 		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
-		fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+		uspi->cs_total.cs_nbfree++;
 		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
 		cylno = ufs_cbtocylno (bbase);
 		fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1);
 		fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
 	}
 	
-	ubh_mark_buffer_dirty (USPI_UBH);
-	ubh_mark_buffer_dirty (UCPI_UBH);
+	ubh_mark_buffer_dirty (USPI_UBH(uspi));
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-		ubh_wait_on_buffer (UCPI_UBH);
+		ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+		ubh_wait_on_buffer (UCPI_UBH(ucpi));
 	}
 	sb->s_dirt = 1;
 	
 	unlock_super (sb);
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return;
 
 failed:
 	unlock_super (sb);
-	UFSD(("EXIT (FAILED)\n"))
+	UFSD("EXIT (FAILED)\n");
 	return;
 }
 
 /*
  * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
  */
-void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
+void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count)
+{
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
@@ -146,7 +140,7 @@
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(uspi);
 
-	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+	UFSD("ENTER, fragment %u, count %u\n", fragment, count);
 	
 	if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
 		ufs_error (sb, "ufs_free_blocks", "internal error, "
@@ -162,7 +156,7 @@
 	bit = ufs_dtogd (fragment);
 	if (cgno >= uspi->s_ncg) {
 		ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
-		goto failed;
+		goto failed_unlock;
 	}
 	end_bit = bit + count;
 	if (end_bit > uspi->s_fpg) {
@@ -173,36 +167,36 @@
 
 	ucpi = ufs_load_cylinder (sb, cgno);
 	if (!ucpi) 
-		goto failed;
-	ucg = ubh_get_ucg (UCPI_UBH);
+		goto failed_unlock;
+	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
 	if (!ufs_cg_chkmagic(sb, ucg)) {
 		ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
-		goto failed;
+		goto failed_unlock;
 	}
 
 	for (i = bit; i < end_bit; i += uspi->s_fpb) {
 		blkno = ufs_fragstoblks(i);
-		if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+		if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
 			ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
 		}
-		ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+		ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
 		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 			ufs_clusteracct (sb, ucpi, blkno, 1);
 		DQUOT_FREE_BLOCK(inode, uspi->s_fpb);
 
 		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
-		fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+		uspi->cs_total.cs_nbfree++;
 		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
 		cylno = ufs_cbtocylno(i);
 		fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1);
 		fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
 	}
 
-	ubh_mark_buffer_dirty (USPI_UBH);
-	ubh_mark_buffer_dirty (UCPI_UBH);
+	ubh_mark_buffer_dirty (USPI_UBH(uspi));
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-		ubh_wait_on_buffer (UCPI_UBH);
+		ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+		ubh_wait_on_buffer (UCPI_UBH(ucpi));
 	}
 
 	if (overflow) {
@@ -213,38 +207,127 @@
 
 	sb->s_dirt = 1;
 	unlock_super (sb);
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return;
 
-failed:
+failed_unlock:
 	unlock_super (sb);
-	UFSD(("EXIT (FAILED)\n"))
+failed:
+	UFSD("EXIT (FAILED)\n");
 	return;
 }
 
+static struct page *ufs_get_locked_page(struct address_space *mapping,
+				  unsigned long index)
+{
+	struct page *page;
 
+try_again:
+	page = find_lock_page(mapping, index);
+	if (!page) {
+		page = read_cache_page(mapping, index,
+				       (filler_t*)mapping->a_ops->readpage,
+				       NULL);
+		if (IS_ERR(page)) {
+			printk(KERN_ERR "ufs_change_blocknr: "
+			       "read_cache_page error: ino %lu, index: %lu\n",
+			       mapping->host->i_ino, index);
+			goto out;
+		}
 
-#define NULLIFY_FRAGMENTS \
-	for (i = oldcount; i < newcount; i++) { \
-		bh = sb_getblk(sb, result + i); \
-		memset (bh->b_data, 0, sb->s_blocksize); \
-		set_buffer_uptodate(bh); \
-		mark_buffer_dirty (bh); \
-		if (IS_SYNC(inode)) \
-			sync_dirty_buffer(bh); \
-		brelse (bh); \
+		lock_page(page);
+
+		if (!PageUptodate(page) || PageError(page)) {
+			unlock_page(page);
+			page_cache_release(page);
+
+			printk(KERN_ERR "ufs_change_blocknr: "
+			       "can not read page: ino %lu, index: %lu\n",
+			       mapping->host->i_ino, index);
+
+			page = ERR_PTR(-EIO);
+			goto out;
+		}
 	}
 
-unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
-	unsigned goal, unsigned count, int * err )
+	if (unlikely(!page->mapping || !page_has_buffers(page))) {
+		unlock_page(page);
+		page_cache_release(page);
+		goto try_again;/*we really need these buffers*/
+	}
+out:
+	return page;
+}
+
+/*
+ * Modify inode page cache in such way:
+ * have - blocks with b_blocknr equal to oldb...oldb+count-1
+ * get - blocks with b_blocknr equal to newb...newb+count-1
+ * also we suppose that oldb...oldb+count-1 blocks
+ * situated at the end of file.
+ *
+ * We can come here from ufs_writepage or ufs_prepare_write,
+ * locked_page is argument of these functions, so we already lock it.
+ */
+static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
+			       unsigned int count, unsigned int oldb,
+			       unsigned int newb, struct page *locked_page)
+{
+	unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	struct address_space *mapping = inode->i_mapping;
+	pgoff_t index, cur_index = locked_page->index;
+	unsigned int i, j;
+	struct page *page;
+	struct buffer_head *head, *bh;
+
+	UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n",
+	      inode->i_ino, count, oldb, newb);
+
+	BUG_ON(!PageLocked(locked_page));
+
+	for (i = 0; i < count; i += blk_per_page) {
+		index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+		if (likely(cur_index != index)) {
+			page = ufs_get_locked_page(mapping, index);
+			if (IS_ERR(page))
+				continue;
+		} else
+			page = locked_page;
+
+		j = i;
+		head = page_buffers(page);
+		bh = head;
+		do {
+			if (likely(bh->b_blocknr == j + oldb && j < count)) {
+				unmap_underlying_metadata(bh->b_bdev,
+							  bh->b_blocknr);
+				bh->b_blocknr = newb + j++;
+				mark_buffer_dirty(bh);
+			}
+
+			bh = bh->b_this_page;
+		} while (bh != head);
+
+		set_page_dirty(page);
+
+		if (likely(cur_index != index)) {
+			unlock_page(page);
+			page_cache_release(page);
+		}
+ 	}
+	UFSD("EXIT\n");
+}
+
+unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
+			   unsigned goal, unsigned count, int * err, struct page *locked_page)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
-	struct buffer_head * bh;
-	unsigned cgno, oldcount, newcount, tmp, request, i, result;
+	unsigned cgno, oldcount, newcount, tmp, request, result;
 	
-	UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
+	UFSD("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count);
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -273,14 +356,14 @@
 			return (unsigned)-1;
 		}
 		if (fragment < UFS_I(inode)->i_lastfrag) {
-			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+			UFSD("EXIT (ALREADY ALLOCATED)\n");
 			unlock_super (sb);
 			return 0;
 		}
 	}
 	else {
 		if (tmp) {
-			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+			UFSD("EXIT (ALREADY ALLOCATED)\n");
 			unlock_super(sb);
 			return 0;
 		}
@@ -289,9 +372,9 @@
 	/*
 	 * There is not enough space for user on the device
 	 */
-	if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
+	if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
 		unlock_super (sb);
-		UFSD(("EXIT (FAILED)\n"))
+		UFSD("EXIT (FAILED)\n");
 		return 0;
 	}
 
@@ -310,12 +393,10 @@
 		if (result) {
 			*p = cpu_to_fs32(sb, result);
 			*err = 0;
-			inode->i_blocks += count << uspi->s_nspfshift;
 			UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
-			NULLIFY_FRAGMENTS
 		}
 		unlock_super(sb);
-		UFSD(("EXIT, result %u\n", result))
+		UFSD("EXIT, result %u\n", result);
 		return result;
 	}
 
@@ -325,11 +406,9 @@
 	result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
 	if (result) {
 		*err = 0;
-		inode->i_blocks += count << uspi->s_nspfshift;
 		UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
-		NULLIFY_FRAGMENTS
 		unlock_super(sb);
-		UFSD(("EXIT, result %u\n", result))
+		UFSD("EXIT, result %u\n", result);
 		return result;
 	}
 
@@ -339,8 +418,8 @@
 	switch (fs32_to_cpu(sb, usb1->fs_optim)) {
 	    case UFS_OPTSPACE:
 		request = newcount;
-		if (uspi->s_minfree < 5 || fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) 
-		    > uspi->s_dsize * uspi->s_minfree / (2 * 100) )
+		if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
+		    > uspi->s_dsize * uspi->s_minfree / (2 * 100))
 			break;
 		usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
 		break;
@@ -349,7 +428,7 @@
 	
 	    case UFS_OPTTIME:
 		request = uspi->s_fpb;
-		if (fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) < uspi->s_dsize *
+		if (uspi->cs_total.cs_nffree < uspi->s_dsize *
 		    (uspi->s_minfree - 2) / 100)
 			break;
 		usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
@@ -357,39 +436,22 @@
 	}
 	result = ufs_alloc_fragments (inode, cgno, goal, request, err);
 	if (result) {
-		for (i = 0; i < oldcount; i++) {
-			bh = sb_bread(sb, tmp + i);
-			if(bh)
-			{
-				clear_buffer_dirty(bh);
-				bh->b_blocknr = result + i;
-				mark_buffer_dirty (bh);
-				if (IS_SYNC(inode))
-					sync_dirty_buffer(bh);
-				brelse (bh);
-			}
-			else
-			{
-				printk(KERN_ERR "ufs_new_fragments: bread fail\n");
-				unlock_super(sb);
-				return 0;
-			}
-		}
+		ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp,
+				   result, locked_page);
+
 		*p = cpu_to_fs32(sb, result);
 		*err = 0;
-		inode->i_blocks += count << uspi->s_nspfshift;
 		UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
-		NULLIFY_FRAGMENTS
 		unlock_super(sb);
 		if (newcount < request)
 			ufs_free_fragments (inode, result + newcount, request - newcount);
 		ufs_free_fragments (inode, tmp, oldcount);
-		UFSD(("EXIT, result %u\n", result))
+		UFSD("EXIT, result %u\n", result);
 		return result;
 	}
 
 	unlock_super(sb);
-	UFSD(("EXIT (FAILED)\n"))
+	UFSD("EXIT (FAILED)\n");
 	return 0;
 }		
 
@@ -404,7 +466,7 @@
 	struct ufs_cylinder_group * ucg;
 	unsigned cgno, fragno, fragoff, count, fragsize, i;
 	
-	UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount))
+	UFSD("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount);
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -419,7 +481,7 @@
 	ucpi = ufs_load_cylinder (sb, cgno);
 	if (!ucpi)
 		return 0;
-	ucg = ubh_get_ucg (UCPI_UBH);
+	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
 	if (!ufs_cg_chkmagic(sb, ucg)) {
 		ufs_panic (sb, "ufs_add_fragments",
 			"internal error, bad magic number on cg %u", cgno);
@@ -429,14 +491,14 @@
 	fragno = ufs_dtogd (fragment);
 	fragoff = ufs_fragnum (fragno);
 	for (i = oldcount; i < newcount; i++)
-		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
 			return 0;
 	/*
 	 * Block can be extended
 	 */
 	ucg->cg_time = cpu_to_fs32(sb, get_seconds());
 	for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
-		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
 			break;
 	fragsize = i - oldcount;
 	if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
@@ -446,7 +508,7 @@
 	if (fragsize != count)
 		fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
 	for (i = oldcount; i < newcount; i++)
-		ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i);
+		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
 	if(DQUOT_ALLOC_BLOCK(inode, count)) {
 		*err = -EDQUOT;
 		return 0;
@@ -454,17 +516,17 @@
 
 	fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
 	fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
-	fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
+	uspi->cs_total.cs_nffree -= count;
 	
-	ubh_mark_buffer_dirty (USPI_UBH);
-	ubh_mark_buffer_dirty (UCPI_UBH);
+	ubh_mark_buffer_dirty (USPI_UBH(uspi));
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-		ubh_wait_on_buffer (UCPI_UBH);
+		ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+		ubh_wait_on_buffer (UCPI_UBH(ucpi));
 	}
 	sb->s_dirt = 1;
 
-	UFSD(("EXIT, fragment %u\n", fragment))
+	UFSD("EXIT, fragment %u\n", fragment);
 	
 	return fragment;
 }
@@ -487,7 +549,7 @@
 	struct ufs_cylinder_group * ucg;
 	unsigned oldcg, i, j, k, result, allocsize;
 	
-	UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count))
+	UFSD("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count);
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -521,14 +583,14 @@
 		UFS_TEST_FREE_SPACE_CG
 	}
 	
-	UFSD(("EXIT (FAILED)\n"))
+	UFSD("EXIT (FAILED)\n");
 	return 0;
 
 cg_found:
 	ucpi = ufs_load_cylinder (sb, cgno);
 	if (!ucpi)
 		return 0;
-	ucg = ubh_get_ucg (UCPI_UBH);
+	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
 	if (!ufs_cg_chkmagic(sb, ucg)) 
 		ufs_panic (sb, "ufs_alloc_fragments",
 			"internal error, bad magic number on cg %u", cgno);
@@ -551,12 +613,12 @@
 			return 0;
 		goal = ufs_dtogd (result);
 		for (i = count; i < uspi->s_fpb; i++)
-			ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i);
+			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
 		i = uspi->s_fpb - count;
 		DQUOT_FREE_BLOCK(inode, i);
 
 		fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
-		fs32_add(sb, &usb1->fs_cstotal.cs_nffree, i);
+		uspi->cs_total.cs_nffree += i;
 		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
 		fs32_add(sb, &ucg->cg_frsum[i], 1);
 		goto succed;
@@ -570,10 +632,10 @@
 		return 0;
 	}
 	for (i = 0; i < count; i++)
-		ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i);
+		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
 	
 	fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
-	fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count);
+	uspi->cs_total.cs_nffree -= count;
 	fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
 	fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
 
@@ -581,16 +643,16 @@
 		fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
 
 succed:
-	ubh_mark_buffer_dirty (USPI_UBH);
-	ubh_mark_buffer_dirty (UCPI_UBH);
+	ubh_mark_buffer_dirty (USPI_UBH(uspi));
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi);
-		ubh_wait_on_buffer (UCPI_UBH);
+		ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+		ubh_wait_on_buffer (UCPI_UBH(ucpi));
 	}
 	sb->s_dirt = 1;
 
 	result += cgno * uspi->s_fpg;
-	UFSD(("EXIT3, result %u\n", result))
+	UFSD("EXIT3, result %u\n", result);
 	return result;
 }
 
@@ -603,12 +665,12 @@
 	struct ufs_cylinder_group * ucg;
 	unsigned result, cylno, blkno;
 
-	UFSD(("ENTER, goal %u\n", goal))
+	UFSD("ENTER, goal %u\n", goal);
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(uspi);
-	ucg = ubh_get_ucg(UCPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
 	if (goal == 0) {
 		goal = ucpi->c_rotor;
@@ -620,7 +682,7 @@
 	/*
 	 * If the requested block is available, use it.
 	 */
-	if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+	if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
 		result = goal;
 		goto gotit;
 	}
@@ -632,7 +694,7 @@
 	ucpi->c_rotor = result;
 gotit:
 	blkno = ufs_fragstoblks(result);
-	ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno);
+	ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
 	if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
 		ufs_clusteracct (sb, ucpi, blkno, -1);
 	if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) {
@@ -641,31 +703,76 @@
 	}
 
 	fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
-	fs32_sub(sb, &usb1->fs_cstotal.cs_nbfree, 1);
+	uspi->cs_total.cs_nbfree--;
 	fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
 	cylno = ufs_cbtocylno(result);
 	fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1);
 	fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
 	
-	UFSD(("EXIT, result %u\n", result))
+	UFSD("EXIT, result %u\n", result);
 
 	return result;
 }
 
-static unsigned ufs_bitmap_search (struct super_block * sb,
-	struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count)
+static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
+			  struct ufs_buffer_head *ubh,
+			  unsigned begin, unsigned size,
+			  unsigned char *table, unsigned char mask)
 {
-	struct ufs_sb_private_info * uspi;
-	struct ufs_super_block_first * usb1;
-	struct ufs_cylinder_group * ucg;
-	unsigned start, length, location, result;
-	unsigned possition, fragsize, blockmap, mask;
+	unsigned rest, offset;
+	unsigned char *cp;
 	
-	UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
 
-	uspi = UFS_SB(sb)->s_uspi;
+	offset = begin & ~uspi->s_fmask;
+	begin >>= uspi->s_fshift;
+	for (;;) {
+		if ((offset + size) < uspi->s_fsize)
+			rest = size;
+		else
+			rest = uspi->s_fsize - offset;
+		size -= rest;
+		cp = ubh->bh[begin]->b_data + offset;
+		while ((table[*cp++] & mask) == 0 && --rest)
+			;
+		if (rest || !size)
+			break;
+		begin++;
+		offset = 0;
+	}
+	return (size + rest);
+}
+
+/*
+ * Find a block of the specified size in the specified cylinder group.
+ * @sp: pointer to super block
+ * @ucpi: pointer to cylinder group info
+ * @goal: near which block we want find new one
+ * @count: specified size
+ */
+static unsigned ufs_bitmap_search(struct super_block *sb,
+				  struct ufs_cg_private_info *ucpi,
+				  unsigned goal, unsigned count)
+{
+	/*
+	 * Bit patterns for identifying fragments in the block map
+	 * used as ((map & mask_arr) == want_arr)
+	 */
+	static const int mask_arr[9] = {
+		0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
+	};
+	static const int want_arr[9] = {
+		0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
+	};
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+	struct ufs_super_block_first *usb1;
+	struct ufs_cylinder_group *ucg;
+	unsigned start, length, loc, result;
+	unsigned pos, want, blockmap, mask, end;
+
+	UFSD("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count);
+
 	usb1 = ubh_get_usb_first (uspi);
-	ucg = ubh_get_ucg(UCPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
 	if (goal)
 		start = ufs_dtogd(goal) >> 3;
@@ -673,53 +780,50 @@
 		start = ucpi->c_frotor >> 3;
 		
 	length = ((uspi->s_fpg + 7) >> 3) - start;
-	location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
+	loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
 		(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
 		1 << (count - 1 + (uspi->s_fpb & 7))); 
-	if (location == 0) {
+	if (loc == 0) {
 		length = start + 1;
-		location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length, 
-			(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
-			1 << (count - 1 + (uspi->s_fpb & 7)));
-		if (location == 0) {
-			ufs_error (sb, "ufs_bitmap_search",
-			"bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n",
-			ucpi->c_cgx, start, length, count, ucpi->c_freeoff);
+		loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
+				(uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
+				ufs_fragtable_other,
+				1 << (count - 1 + (uspi->s_fpb & 7)));
+		if (loc == 0) {
+			ufs_error(sb, "ufs_bitmap_search",
+				  "bitmap corrupted on cg %u, start %u,"
+				  " length %u, count %u, freeoff %u\n",
+				  ucpi->c_cgx, start, length, count,
+				  ucpi->c_freeoff);
 			return (unsigned)-1;
 		}
 		start = 0;
 	}
-	result = (start + length - location) << 3;
+	result = (start + length - loc) << 3;
 	ucpi->c_frotor = result;
 
 	/*
 	 * found the byte in the map
 	 */
-	blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result);
-	fragsize = 0;
-	for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) {
-		if (blockmap & mask) {
-			if (!(possition & uspi->s_fpbmask))
-				fragsize = 1;
-			else 
-				fragsize++;
-		}
-		else {
-			if (fragsize == count) {
-				result += possition - count;
-				UFSD(("EXIT, result %u\n", result))
-				return result;
-			}
-			fragsize = 0;
-		}
-	}
-	if (fragsize == count) {
-		result += possition - count;
-		UFSD(("EXIT, result %u\n", result))
-		return result;
-	}
-	ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx);
-	UFSD(("EXIT (FAILED)\n"))
+
+	for (end = result + 8; result < end; result += uspi->s_fpb) {
+		blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
+		blockmap <<= 1;
+		mask = mask_arr[count];
+		want = want_arr[count];
+		for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
+			if ((blockmap & mask) == want) {
+				UFSD("EXIT, result %u\n", result);
+				return result + pos;
+ 			}
+			mask <<= 1;
+			want <<= 1;
+ 		}
+ 	}
+
+	ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
+		  ucpi->c_cgx);
+	UFSD("EXIT (FAILED)\n");
 	return (unsigned)-1;
 }
 
@@ -734,9 +838,9 @@
 		return;
 
 	if (cnt > 0)
-		ubh_setbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+		ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
 	else
-		ubh_clrbit(UCPI_UBH, ucpi->c_clusteroff, blkno);
+		ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
 
 	/*
 	 * Find the size of the cluster going forward.
@@ -745,7 +849,7 @@
 	end = start + uspi->s_contigsumsize;
 	if ( end >= ucpi->c_nclusterblks)
 		end = ucpi->c_nclusterblks;
-	i = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_clusteroff, end, start);
+	i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
 	if (i > end)
 		i = end;
 	forw = i - start;
@@ -757,7 +861,7 @@
 	end = start - uspi->s_contigsumsize;
 	if (end < 0 ) 
 		end = -1;
-	i = ubh_find_last_zero_bit (UCPI_UBH, ucpi->c_clusteroff, start, end);
+	i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
 	if ( i < end) 
 		i = end;
 	back = start - i;
@@ -769,11 +873,11 @@
 	i = back + forw + 1;
 	if (i > uspi->s_contigsumsize)
 		i = uspi->s_contigsumsize;
-	fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (i << 2)), cnt);
+	fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
 	if (back > 0)
-		fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (back << 2)), cnt);
+		fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
 	if (forw > 0)
-		fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (forw << 2)), cnt);
+		fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
 }
 
 
diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c
index 14abb8b..09c39e5 100644
--- a/fs/ufs/cylinder.c
+++ b/fs/ufs/cylinder.c
@@ -20,15 +20,6 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_CYLINDER_DEBUG
-
-#ifdef UFS_CYLINDER_DEBUG
-#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-
 /*
  * Read cylinder group into cache. The memory space for ufs_cg_private_info
  * structure is already allocated during ufs_read_super.
@@ -42,19 +33,19 @@
 	struct ufs_cylinder_group * ucg;
 	unsigned i, j;
 
-	UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr))
+	UFSD("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr);
 	uspi = sbi->s_uspi;
 	ucpi = sbi->s_ucpi[bitmap_nr];
 	ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data;
 
-	UCPI_UBH->fragment = ufs_cgcmin(cgno);
-	UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
+	UCPI_UBH(ucpi)->fragment = ufs_cgcmin(cgno);
+	UCPI_UBH(ucpi)->count = uspi->s_cgsize >> sb->s_blocksize_bits;
 	/*
 	 * We have already the first fragment of cylinder group block in buffer
 	 */
-	UCPI_UBH->bh[0] = sbi->s_ucg[cgno];
-	for (i = 1; i < UCPI_UBH->count; i++)
-		if (!(UCPI_UBH->bh[i] = sb_bread(sb, UCPI_UBH->fragment + i)))
+	UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno];
+	for (i = 1; i < UCPI_UBH(ucpi)->count; i++)
+		if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i)))
 			goto failed;
 	sbi->s_cgno[bitmap_nr] = cgno;
 			
@@ -73,7 +64,7 @@
 	ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff);
 	ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff);
 	ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks);
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return;	
 	
 failed:
@@ -95,15 +86,15 @@
 	struct ufs_cylinder_group * ucg;
 	unsigned i;
 
-	UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr))
+	UFSD("ENTER, bitmap_nr %u\n", bitmap_nr);
 
 	uspi = sbi->s_uspi;
 	if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
-		UFSD(("EXIT\n"))
+		UFSD("EXIT\n");
 		return;
 	}
 	ucpi = sbi->s_ucpi[bitmap_nr];
-	ucg = ubh_get_ucg(UCPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
 	if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) {
 		ufs_panic (sb, "ufs_put_cylinder", "internal error");
@@ -116,13 +107,13 @@
 	ucg->cg_rotor = cpu_to_fs32(sb, ucpi->c_rotor);
 	ucg->cg_frotor = cpu_to_fs32(sb, ucpi->c_frotor);
 	ucg->cg_irotor = cpu_to_fs32(sb, ucpi->c_irotor);
-	ubh_mark_buffer_dirty (UCPI_UBH);
-	for (i = 1; i < UCPI_UBH->count; i++) {
-		brelse (UCPI_UBH->bh[i]);
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
+	for (i = 1; i < UCPI_UBH(ucpi)->count; i++) {
+		brelse (UCPI_UBH(ucpi)->bh[i]);
 	}
 
 	sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 }
 
 /*
@@ -139,7 +130,7 @@
 	struct ufs_cg_private_info * ucpi;
 	unsigned cg, i, j;
 
-	UFSD(("ENTER, cgno %u\n", cgno))
+	UFSD("ENTER, cgno %u\n", cgno);
 
 	uspi = sbi->s_uspi;
 	if (cgno >= uspi->s_ncg) {
@@ -150,7 +141,7 @@
 	 * Cylinder group number cg it in cache and it was last used
 	 */
 	if (sbi->s_cgno[0] == cgno) {
-		UFSD(("EXIT\n"))
+		UFSD("EXIT\n");
 		return sbi->s_ucpi[0];
 	}
 	/*
@@ -160,16 +151,16 @@
 		if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) {
 			if (sbi->s_cgno[cgno] != cgno) {
 				ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache");
-				UFSD(("EXIT (FAILED)\n"))
+				UFSD("EXIT (FAILED)\n");
 				return NULL;
 			}
 			else {
-				UFSD(("EXIT\n"))
+				UFSD("EXIT\n");
 				return sbi->s_ucpi[cgno];
 			}
 		} else {
 			ufs_read_cylinder (sb, cgno, cgno);
-			UFSD(("EXIT\n"))
+			UFSD("EXIT\n");
 			return sbi->s_ucpi[cgno];
 		}
 	}
@@ -204,6 +195,6 @@
 		sbi->s_ucpi[0] = ucpi;
 		ufs_read_cylinder (sb, cgno, 0);
 	}
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return sbi->s_ucpi[0];
 }
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 1a56120..7f0a0aa 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -11,31 +11,20 @@
  * 4.4BSD (FreeBSD) support added on February 1st 1998 by
  * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
  * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * Migration to usage of "page cache" on May 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
  */
 
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
 #include <linux/sched.h>
 
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_DIR_DEBUG
-
-#ifdef UFS_DIR_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-static int
-ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *,
-		     struct buffer_head *, unsigned long);
-
-
 /*
  * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
  *
@@ -51,495 +40,541 @@
 	return !memcmp(name, de->d_name, len);
 }
 
-/*
- * This is blatantly stolen from ext2fs
- */
-static int
-ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+static int ufs_commit_chunk(struct page *page, unsigned from, unsigned to)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	int error = 0;
-	unsigned long offset, lblk;
-	int i, stored;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de;
-	struct super_block * sb;
-	int de_reclen;
-	unsigned flags;
-	u64     blk= 0L;
+	struct inode *dir = page->mapping->host;
+	int err = 0;
+	dir->i_version++;
+	page->mapping->a_ops->commit_write(NULL, page, from, to);
+	if (IS_DIRSYNC(dir))
+		err = write_one_page(page, 1);
+	else
+		unlock_page(page);
+	return err;
+}
 
-	lock_kernel();
+static inline void ufs_put_page(struct page *page)
+{
+	kunmap(page);
+	page_cache_release(page);
+}
 
-	sb = inode->i_sb;
-	flags = UFS_SB(sb)->s_flags;
+static inline unsigned long ufs_dir_pages(struct inode *inode)
+{
+	return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
+}
 
-	UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
-
-	stored = 0;
-	bh = NULL;
-	offset = filp->f_pos & (sb->s_blocksize - 1);
-
-	while (!error && !stored && filp->f_pos < inode->i_size) {
-		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
-		blk = ufs_frag_map(inode, lblk);
-		if (!blk || !(bh = sb_bread(sb, blk))) {
-			/* XXX - error - skip to the next block */
-			printk("ufs_readdir: "
-			       "dir inode %lu has a hole at offset %lu\n",
-			       inode->i_ino, (unsigned long int)filp->f_pos);
-			filp->f_pos += sb->s_blocksize - offset;
-			continue;
-		}
-
-revalidate:
-		/* If the dir block has changed since the last call to
-		 * readdir(2), then we might be pointing to an invalid
-		 * dirent right now.  Scan from the start of the block
-		 * to make sure. */
-		if (filp->f_version != inode->i_version) {
-			for (i = 0; i < sb->s_blocksize && i < offset; ) {
-				de = (struct ufs_dir_entry *)(bh->b_data + i);
-				/* It's too expensive to do a full
-				 * dirent test each time round this
-				 * loop, but we do have to test at
-				 * least that it is non-zero.  A
-				 * failure will be detected in the
-				 * dirent test below. */
-				de_reclen = fs16_to_cpu(sb, de->d_reclen);
-				if (de_reclen < 1)
-					break;
-				i += de_reclen;
-			}
-			offset = i;
-			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
-				| offset;
-			filp->f_version = inode->i_version;
-		}
-
-		while (!error && filp->f_pos < inode->i_size
-		       && offset < sb->s_blocksize) {
-			de = (struct ufs_dir_entry *) (bh->b_data + offset);
-			/* XXX - put in a real ufs_check_dir_entry() */
-			if ((de->d_reclen == 0) || (ufs_get_de_namlen(sb, de) == 0)) {
-				filp->f_pos = (filp->f_pos &
-				              (sb->s_blocksize - 1)) +
-				               sb->s_blocksize;
-				brelse(bh);
-				unlock_kernel();
-				return stored;
-			}
-			if (!ufs_check_dir_entry ("ufs_readdir", inode, de,
-						   bh, offset)) {
-				/* On error, skip the f_pos to the
-				   next block. */
-				filp->f_pos = (filp->f_pos |
-				              (sb->s_blocksize - 1)) +
-					       1;
-				brelse (bh);
-				unlock_kernel();
-				return stored;
-			}
-			offset += fs16_to_cpu(sb, de->d_reclen);
-			if (de->d_ino) {
-				/* We might block in the next section
-				 * if the data destination is
-				 * currently swapped out.  So, use a
-				 * version stamp to detect whether or
-				 * not the directory has been modified
-				 * during the copy operation. */
-				unsigned long version = filp->f_version;
-				unsigned char d_type = DT_UNKNOWN;
-
-				UFSD(("filldir(%s,%u)\n", de->d_name,
-							fs32_to_cpu(sb, de->d_ino)))
-				UFSD(("namlen %u\n", ufs_get_de_namlen(sb, de)))
-
-				if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
-					d_type = de->d_u.d_44.d_type;
-				error = filldir(dirent, de->d_name,
-						ufs_get_de_namlen(sb, de), filp->f_pos,
-						fs32_to_cpu(sb, de->d_ino), d_type);
-				if (error)
-					break;
-				if (version != filp->f_version)
-					goto revalidate;
-				stored ++;
-			}
-			filp->f_pos += fs16_to_cpu(sb, de->d_reclen);
-		}
-		offset = 0;
-		brelse (bh);
+ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry)
+{
+	ino_t res = 0;
+	struct ufs_dir_entry *de;
+	struct page *page;
+	
+	de = ufs_find_entry(dir, dentry, &page);
+	if (de) {
+		res = fs32_to_cpu(dir->i_sb, de->d_ino);
+		ufs_put_page(page);
 	}
-	unlock_kernel();
-	return 0;
+	return res;
+}
+
+
+/* Releases the page */
+void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+		  struct page *page, struct inode *inode)
+{
+	unsigned from = (char *) de - (char *) page_address(page);
+	unsigned to = from + fs16_to_cpu(dir->i_sb, de->d_reclen);
+	int err;
+
+	lock_page(page);
+	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+	BUG_ON(err);
+	de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
+	ufs_set_de_type(dir->i_sb, de, inode->i_mode);
+	err = ufs_commit_chunk(page, from, to);
+	ufs_put_page(page);
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+	mark_inode_dirty(dir);
+}
+
+
+static void ufs_check_page(struct page *page)
+{
+	struct inode *dir = page->mapping->host;
+	struct super_block *sb = dir->i_sb;
+	char *kaddr = page_address(page);
+	unsigned offs, rec_len;
+	unsigned limit = PAGE_CACHE_SIZE;
+	struct ufs_dir_entry *p;
+	char *error;
+
+	if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
+		limit = dir->i_size & ~PAGE_CACHE_MASK;
+		if (limit & (UFS_SECTOR_SIZE - 1))
+			goto Ebadsize;
+		if (!limit)
+			goto out;
+	}
+	for (offs = 0; offs <= limit - UFS_DIR_REC_LEN(1); offs += rec_len) {
+		p = (struct ufs_dir_entry *)(kaddr + offs);
+		rec_len = fs16_to_cpu(sb, p->d_reclen);
+
+		if (rec_len < UFS_DIR_REC_LEN(1))
+			goto Eshort;
+		if (rec_len & 3)
+			goto Ealign;
+		if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p)))
+			goto Enamelen;
+		if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1))
+			goto Espan;
+		if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
+						  UFS_SB(sb)->s_uspi->s_ncg))
+			goto Einumber;
+	}
+	if (offs != limit)
+		goto Eend;
+out:
+	SetPageChecked(page);
+	return;
+
+	/* Too bad, we had an error */
+
+Ebadsize:
+	ufs_error(sb, "ufs_check_page",
+		  "size of directory #%lu is not a multiple of chunk size",
+		  dir->i_ino
+	);
+	goto fail;
+Eshort:
+	error = "rec_len is smaller than minimal";
+	goto bad_entry;
+Ealign:
+	error = "unaligned directory entry";
+	goto bad_entry;
+Enamelen:
+	error = "rec_len is too small for name_len";
+	goto bad_entry;
+Espan:
+	error = "directory entry across blocks";
+	goto bad_entry;
+Einumber:
+	error = "inode out of bounds";
+bad_entry:
+	ufs_error (sb, "ufs_check_page", "bad entry in directory #%lu: %s - "
+		   "offset=%lu, rec_len=%d, name_len=%d",
+		   dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+		   rec_len, ufs_get_de_namlen(sb, p));
+	goto fail;
+Eend:
+	p = (struct ufs_dir_entry *)(kaddr + offs);
+	ufs_error (sb, "ext2_check_page",
+		   "entry in directory #%lu spans the page boundary"
+		   "offset=%lu",
+		   dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs);
+fail:
+	SetPageChecked(page);
+	SetPageError(page);
+}
+
+static struct page *ufs_get_page(struct inode *dir, unsigned long n)
+{
+	struct address_space *mapping = dir->i_mapping;
+	struct page *page = read_cache_page(mapping, n,
+				(filler_t*)mapping->a_ops->readpage, NULL);
+	if (!IS_ERR(page)) {
+		wait_on_page_locked(page);
+		kmap(page);
+		if (!PageUptodate(page))
+			goto fail;
+		if (!PageChecked(page))
+			ufs_check_page(page);
+		if (PageError(page))
+			goto fail;
+	}
+	return page;
+
+fail:
+	ufs_put_page(page);
+	return ERR_PTR(-EIO);
 }
 
 /*
- * define how far ahead to read directories while searching them.
+ * Return the offset into page `page_nr' of the last valid
+ * byte in that page, plus one.
  */
-#define NAMEI_RA_CHUNKS  2
-#define NAMEI_RA_BLOCKS  4
-#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+static unsigned
+ufs_last_byte(struct inode *inode, unsigned long page_nr)
+{
+	unsigned last_byte = inode->i_size;
+
+	last_byte -= page_nr << PAGE_CACHE_SHIFT;
+	if (last_byte > PAGE_CACHE_SIZE)
+		last_byte = PAGE_CACHE_SIZE;
+	return last_byte;
+}
+
+static inline struct ufs_dir_entry *
+ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p)
+{
+	return (struct ufs_dir_entry *)((char *)p +
+					fs16_to_cpu(sb, p->d_reclen));
+}
+
+struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
+{
+	struct page *page = ufs_get_page(dir, 0);
+	struct ufs_dir_entry *de = NULL;
+
+	if (!IS_ERR(page)) {
+		de = ufs_next_entry(dir->i_sb,
+				    (struct ufs_dir_entry *)page_address(page));
+		*p = page;
+	}
+	return de;
+}
 
 /*
  *	ufs_find_entry()
  *
  * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as a parameter - res_bh). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
+ * returns the page in which the entry was found, and the entry itself
+ * (as a parameter - res_dir). Page is returned mapped and unlocked.
+ * Entry is guaranteed to be valid.
  */
-struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry,
-	struct buffer_head ** res_bh)
-{
-	struct super_block * sb;
-	struct buffer_head * bh_use[NAMEI_RA_SIZE];
-	struct buffer_head * bh_read[NAMEI_RA_SIZE];
-	unsigned long offset;
-	int block, toread, i, err;
-	struct inode *dir = dentry->d_parent->d_inode;
-	const char *name = dentry->d_name.name;
-	int namelen = dentry->d_name.len;
-
-	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
-	
-	*res_bh = NULL;
-	
-	sb = dir->i_sb;
-	
-	if (namelen > UFS_MAXNAMLEN)
-		return NULL;
-
-	memset (bh_use, 0, sizeof (bh_use));
-	toread = 0;
-	for (block = 0; block < NAMEI_RA_SIZE; ++block) {
-		struct buffer_head * bh;
-
-		if ((block << sb->s_blocksize_bits) >= dir->i_size)
-			break;
-		bh = ufs_getfrag (dir, block, 0, &err);
-		bh_use[block] = bh;
-		if (bh && !buffer_uptodate(bh))
-			bh_read[toread++] = bh;
-	}
-
-	for (block = 0, offset = 0; offset < dir->i_size; block++) {
-		struct buffer_head * bh;
-		struct ufs_dir_entry * de;
-		char * dlimit;
-
-		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
-			ll_rw_block (READ, toread, bh_read);
-			toread = 0;
-		}
-		bh = bh_use[block % NAMEI_RA_SIZE];
-		if (!bh) {
-			ufs_error (sb, "ufs_find_entry", 
-				"directory #%lu contains a hole at offset %lu",
-				dir->i_ino, offset);
-			offset += sb->s_blocksize;
-			continue;
-		}
-		wait_on_buffer (bh);
-		if (!buffer_uptodate(bh)) {
-			/*
-			 * read error: all bets are off
-			 */
-			break;
-		}
-
-		de = (struct ufs_dir_entry *) bh->b_data;
-		dlimit = bh->b_data + sb->s_blocksize;
-		while ((char *) de < dlimit && offset < dir->i_size) {
-			/* this code is executed quadratically often */
-			/* do minimal checking by hand */
-			int de_len;
-
-			if ((char *) de + namelen <= dlimit &&
-			    ufs_match(sb, namelen, name, de)) {
-				/* found a match -
-				just to be sure, do a full check */
-				if (!ufs_check_dir_entry("ufs_find_entry",
-				    dir, de, bh, offset))
-					goto failed;
-				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
-					if (bh_use[i] != bh)
-						brelse (bh_use[i]);
-				}
-				*res_bh = bh;
-				return de;
-			}
-                        /* prevent looping on a bad block */
-			de_len = fs16_to_cpu(sb, de->d_reclen);
-			if (de_len <= 0)
-				goto failed;
-			offset += de_len;
-			de = (struct ufs_dir_entry *) ((char *) de + de_len);
-		}
-
-		brelse (bh);
-		if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
-		    dir->i_size)
-			bh = NULL;
-		else
-			bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
-		bh_use[block % NAMEI_RA_SIZE] = bh;
-		if (bh && !buffer_uptodate(bh))
-			bh_read[toread++] = bh;
-	}
-
-failed:
-	for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
-	UFSD(("EXIT\n"))
-	return NULL;
-}
-
-static int
-ufs_check_dir_entry (const char *function, struct inode *dir,
-		     struct ufs_dir_entry *de, struct buffer_head *bh,
-		     unsigned long offset)
+struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry,
+				     struct page **res_page)
 {
 	struct super_block *sb = dir->i_sb;
-	const char *error_msg = NULL;
-	int rlen = fs16_to_cpu(sb, de->d_reclen);
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
+	unsigned reclen = UFS_DIR_REC_LEN(namelen);
+	unsigned long start, n;
+	unsigned long npages = ufs_dir_pages(dir);
+	struct page *page = NULL;
+	struct ufs_inode_info *ui = UFS_I(dir);
+	struct ufs_dir_entry *de;
 
-	if (rlen < UFS_DIR_REC_LEN(1))
-		error_msg = "reclen is smaller than minimal";
-	else if (rlen % 4 != 0)
-		error_msg = "reclen % 4 != 0";
-	else if (rlen < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)))
-		error_msg = "reclen is too small for namlen";
-	else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
-		error_msg = "directory entry across blocks";
-	else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg *
-				      UFS_SB(sb)->s_uspi->s_ncg))
-		error_msg = "inode out of bounds";
+	UFSD("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen);
 
-	if (error_msg != NULL)
-		ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - "
-			    "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
-			    dir->i_ino, dir->i_size, error_msg, offset,
-			    (unsigned long)fs32_to_cpu(sb, de->d_ino),
-			    rlen, ufs_get_de_namlen(sb, de));
-	
-	return (error_msg == NULL ? 1 : 0);
-}
+	if (npages == 0 || namelen > UFS_MAXNAMLEN)
+		goto out;
 
-struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p)
-{
-	int err;
-	struct buffer_head *bh = ufs_bread (dir, 0, 0, &err);
-	struct ufs_dir_entry *res = NULL;
+	/* OFFSET_CACHE */
+	*res_page = NULL;
 
-	if (bh) {
-		res = (struct ufs_dir_entry *) bh->b_data;
-		res = (struct ufs_dir_entry *)((char *)res +
-			fs16_to_cpu(dir->i_sb, res->d_reclen));
-	}
-	*p = bh;
-	return res;
-}
-ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry)
-{
-	ino_t res = 0;
-	struct ufs_dir_entry * de;
-	struct buffer_head *bh;
+	start = ui->i_dir_start_lookup;
 
-	de = ufs_find_entry (dentry, &bh);
-	if (de) {
-		res = fs32_to_cpu(dir->i_sb, de->d_ino);
-		brelse(bh);
-	}
-	return res;
-}
+	if (start >= npages)
+		start = 0;
+	n = start;
+	do {
+		char *kaddr;
+		page = ufs_get_page(dir, n);
+		if (!IS_ERR(page)) {
+			kaddr = page_address(page);
+			de = (struct ufs_dir_entry *) kaddr;
+			kaddr += ufs_last_byte(dir, n) - reclen;
+			while ((char *) de <= kaddr) {
+				if (de->d_reclen == 0) {
+					ufs_error(dir->i_sb, __FUNCTION__,
+						  "zero-length directory entry");
+					ufs_put_page(page);
+					goto out;
+				}
+				if (ufs_match(sb, namelen, name, de))
+					goto found;
+				de = ufs_next_entry(sb, de);
+			}
+			ufs_put_page(page);
+		}
+		if (++n >= npages)
+			n = 0;
+	} while (n != start);
+out:
+	return NULL;
 
-void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
-		struct buffer_head *bh, struct inode *inode)
-{
-	dir->i_version++;
-	de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
-	mark_buffer_dirty(bh);
-	if (IS_DIRSYNC(dir))
-		sync_dirty_buffer(bh);
-	brelse (bh);
+found:
+	*res_page = page;
+	ui->i_dir_start_lookup = n;
+	return de;
 }
 
 /*
- *	ufs_add_entry()
- *
- * adds a file entry to the specified directory, using the same
- * semantics as ufs_find_entry(). It returns NULL if it failed.
+ *	Parent is locked.
  */
 int ufs_add_link(struct dentry *dentry, struct inode *inode)
 {
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
-	unsigned long offset;
-	unsigned fragoff;
-	unsigned short rec_len;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de, * de1;
 	struct inode *dir = dentry->d_parent->d_inode;
 	const char *name = dentry->d_name.name;
 	int namelen = dentry->d_name.len;
+	struct super_block *sb = dir->i_sb;
+	unsigned reclen = UFS_DIR_REC_LEN(namelen);
+	unsigned short rec_len, name_len;
+	struct page *page = NULL;
+	struct ufs_dir_entry *de;
+	unsigned long npages = ufs_dir_pages(dir);
+	unsigned long n;
+	char *kaddr;
+	unsigned from, to;
 	int err;
 
-	UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
-	
-	sb = dir->i_sb;
-	uspi = UFS_SB(sb)->s_uspi;
+	UFSD("ENTER, name %s, namelen %u\n", name, namelen);
 
-	if (!namelen)
-		return -EINVAL;
-	bh = ufs_bread (dir, 0, 0, &err);
-	if (!bh)
-		return err;
-	rec_len = UFS_DIR_REC_LEN(namelen);
-	offset = 0;
-	de = (struct ufs_dir_entry *) bh->b_data;
-	while (1) {
-		if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) {
-			fragoff = offset & ~uspi->s_fmask;
-			if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE)
-				ufs_error (sb, "ufs_add_entry", "internal error"
-					" fragoff %u", fragoff);
-			if (!fragoff) {
-				brelse (bh);
-				bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err);
-				if (!bh)
-					return err;
-			}
-			if (dir->i_size <= offset) {
-				if (dir->i_size == 0) {
-					brelse(bh);
-					return -ENOENT;
-				}
-				de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
-				de->d_ino = 0;
+	/*
+	 * We take care of directory expansion in the same loop.
+	 * This code plays outside i_size, so it locks the page
+	 * to protect that region.
+	 */
+	for (n = 0; n <= npages; n++) {
+		char *dir_end;
+
+		page = ufs_get_page(dir, n);
+		err = PTR_ERR(page);
+		if (IS_ERR(page))
+			goto out;
+		lock_page(page);
+		kaddr = page_address(page);
+		dir_end = kaddr + ufs_last_byte(dir, n);
+		de = (struct ufs_dir_entry *)kaddr;
+		kaddr += PAGE_CACHE_SIZE - reclen;
+		while ((char *)de <= kaddr) {
+			if ((char *)de == dir_end) {
+				/* We hit i_size */
+				name_len = 0;
+				rec_len = UFS_SECTOR_SIZE;
 				de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE);
-				ufs_set_de_namlen(sb, de, 0);
-				dir->i_size = offset + UFS_SECTOR_SIZE;
-				mark_inode_dirty(dir);
-			} else {
-				de = (struct ufs_dir_entry *) bh->b_data;
+				de->d_ino = 0;
+				goto got_it;
 			}
+			if (de->d_reclen == 0) {
+				ufs_error(dir->i_sb, __FUNCTION__,
+					  "zero-length directory entry");
+				err = -EIO;
+				goto out_unlock;
+			}
+			err = -EEXIST;
+			if (ufs_match(sb, namelen, name, de))
+				goto out_unlock;
+			name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de));
+			rec_len = fs16_to_cpu(sb, de->d_reclen);
+			if (!de->d_ino && rec_len >= reclen)
+				goto got_it;
+			if (rec_len >= name_len + reclen)
+				goto got_it;
+			de = (struct ufs_dir_entry *) ((char *) de + rec_len);
 		}
-		if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
-			brelse (bh);
-			return -ENOENT;
-		}
-		if (ufs_match(sb, namelen, name, de)) {
-			brelse (bh);
-			return -EEXIST;
-		}
-		if (de->d_ino == 0 && fs16_to_cpu(sb, de->d_reclen) >= rec_len)
-			break;
-			
-		if (fs16_to_cpu(sb, de->d_reclen) >=
-		     UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)) + rec_len)
-			break;
-		offset += fs16_to_cpu(sb, de->d_reclen);
-		de = (struct ufs_dir_entry *) ((char *) de + fs16_to_cpu(sb, de->d_reclen));
+		unlock_page(page);
+		ufs_put_page(page);
 	}
+	BUG();
+	return -EINVAL;
 
+got_it:
+	from = (char*)de - (char*)page_address(page);
+	to = from + rec_len;
+	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
+	if (err)
+		goto out_unlock;
 	if (de->d_ino) {
-		de1 = (struct ufs_dir_entry *) ((char *) de +
-			UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
-		de1->d_reclen =
-			cpu_to_fs16(sb, fs16_to_cpu(sb, de->d_reclen) -
-				UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
-		de->d_reclen =
-			cpu_to_fs16(sb, UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)));
+		struct ufs_dir_entry *de1 =
+			(struct ufs_dir_entry *) ((char *) de + name_len);
+		de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len);
+		de->d_reclen = cpu_to_fs16(sb, name_len);
+
 		de = de1;
 	}
-	de->d_ino = 0;
+
 	ufs_set_de_namlen(sb, de, namelen);
-	memcpy (de->d_name, name, namelen + 1);
+	memcpy(de->d_name, name, namelen + 1);
 	de->d_ino = cpu_to_fs32(sb, inode->i_ino);
 	ufs_set_de_type(sb, de, inode->i_mode);
-	mark_buffer_dirty(bh);
-	if (IS_DIRSYNC(dir))
-		sync_dirty_buffer(bh);
-	brelse (bh);
-	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
-	dir->i_version++;
-	mark_inode_dirty(dir);
 
-	UFSD(("EXIT\n"))
+	err = ufs_commit_chunk(page, from, to);
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+
+	mark_inode_dirty(dir);
+	/* OFFSET_CACHE */
+out_put:
+	ufs_put_page(page);
+out:
+	return err;
+out_unlock:
+	unlock_page(page);
+	goto out_put;
+}
+
+static inline unsigned
+ufs_validate_entry(struct super_block *sb, char *base,
+		   unsigned offset, unsigned mask)
+{
+	struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset);
+	struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask));
+	while ((char*)p < (char*)de) {
+		if (p->d_reclen == 0)
+			break;
+		p = ufs_next_entry(sb, p);
+	}
+	return (char *)p - base;
+}
+
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	loff_t pos = filp->f_pos;
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	unsigned int offset = pos & ~PAGE_CACHE_MASK;
+	unsigned long n = pos >> PAGE_CACHE_SHIFT;
+	unsigned long npages = ufs_dir_pages(inode);
+	unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1);
+	int need_revalidate = filp->f_version != inode->i_version;
+	unsigned flags = UFS_SB(sb)->s_flags;
+
+	UFSD("BEGIN\n");
+
+	if (pos > inode->i_size - UFS_DIR_REC_LEN(1))
+		return 0;
+
+	for ( ; n < npages; n++, offset = 0) {
+		char *kaddr, *limit;
+		struct ufs_dir_entry *de;
+
+		struct page *page = ufs_get_page(inode, n);
+
+		if (IS_ERR(page)) {
+			ufs_error(sb, __FUNCTION__,
+				  "bad page in #%lu",
+				  inode->i_ino);
+			filp->f_pos += PAGE_CACHE_SIZE - offset;
+			return -EIO;
+		}
+		kaddr = page_address(page);
+		if (unlikely(need_revalidate)) {
+			if (offset) {
+				offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask);
+				filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
+			}
+			filp->f_version = inode->i_version;
+			need_revalidate = 0;
+		}
+		de = (struct ufs_dir_entry *)(kaddr+offset);
+		limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1);
+		for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) {
+			if (de->d_reclen == 0) {
+				ufs_error(sb, __FUNCTION__,
+					"zero-length directory entry");
+				ufs_put_page(page);
+				return -EIO;
+			}
+			if (de->d_ino) {
+				int over;
+				unsigned char d_type = DT_UNKNOWN;
+
+				offset = (char *)de - kaddr;
+
+				UFSD("filldir(%s,%u)\n", de->d_name,
+				      fs32_to_cpu(sb, de->d_ino));
+				UFSD("namlen %u\n", ufs_get_de_namlen(sb, de));
+
+				if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
+					d_type = de->d_u.d_44.d_type;
+
+				over = filldir(dirent, de->d_name,
+					       ufs_get_de_namlen(sb, de),
+						(n<<PAGE_CACHE_SHIFT) | offset,
+					       fs32_to_cpu(sb, de->d_ino), d_type);
+				if (over) {
+					ufs_put_page(page);
+					return 0;
+				}
+			}
+			filp->f_pos += fs16_to_cpu(sb, de->d_reclen);
+		}
+		ufs_put_page(page);
+	}
 	return 0;
 }
 
+
 /*
  * ufs_delete_entry deletes a directory entry by merging it with the
  * previous entry.
  */
-int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
-	struct buffer_head * bh )
-	
+int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
+		     struct page * page)
 {
-	struct super_block * sb;
-	struct ufs_dir_entry * de, * pde;
-	unsigned i;
-	
-	UFSD(("ENTER\n"))
+	struct super_block *sb = inode->i_sb;
+	struct address_space *mapping = page->mapping;
+	char *kaddr = page_address(page);
+	unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1);
+	unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
+	struct ufs_dir_entry *pde = NULL;
+	struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from);
+	int err;
 
-	sb = inode->i_sb;
-	i = 0;
-	pde = NULL;
-	de = (struct ufs_dir_entry *) bh->b_data;
-	
-	UFSD(("ino %u, reclen %u, namlen %u, name %s\n",
-		fs32_to_cpu(sb, de->d_ino),
-		fs16_to_cpu(sb, de->d_reclen),
-		ufs_get_de_namlen(sb, de), de->d_name))
+	UFSD("ENTER\n");
 
-	while (i < bh->b_size) {
-		if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) {
-			brelse(bh);
-			return -EIO;
+	UFSD("ino %u, reclen %u, namlen %u, name %s\n",
+	      fs32_to_cpu(sb, de->d_ino),
+	      fs16_to_cpu(sb, de->d_reclen),
+	      ufs_get_de_namlen(sb, de), de->d_name);
+
+	while ((char*)de < (char*)dir) {
+		if (de->d_reclen == 0) {
+			ufs_error(inode->i_sb, __FUNCTION__,
+				  "zero-length directory entry");
+			err = -EIO;
+			goto out;
 		}
-		if (de == dir)  {
-			if (pde)
-				fs16_add(sb, &pde->d_reclen,
-					fs16_to_cpu(sb, dir->d_reclen));
-			dir->d_ino = 0;
-			inode->i_version++;
-			inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
-			mark_inode_dirty(inode);
-			mark_buffer_dirty(bh);
-			if (IS_DIRSYNC(inode))
-				sync_dirty_buffer(bh);
-			brelse(bh);
-			UFSD(("EXIT\n"))
-			return 0;
-		}
-		i += fs16_to_cpu(sb, de->d_reclen);
-		if (i == UFS_SECTOR_SIZE) pde = NULL;
-		else pde = de;
-		de = (struct ufs_dir_entry *)
-		    ((char *) de + fs16_to_cpu(sb, de->d_reclen));
-		if (i == UFS_SECTOR_SIZE && de->d_reclen == 0)
-			break;
+		pde = de;
+		de = ufs_next_entry(sb, de);
 	}
-	UFSD(("EXIT\n"))
-	brelse(bh);
-	return -ENOENT;
+	if (pde)
+		from = (char*)pde - (char*)page_address(page);
+	lock_page(page);
+	err = mapping->a_ops->prepare_write(NULL, page, from, to);
+	BUG_ON(err);
+	if (pde)
+		pde->d_reclen = cpu_to_fs16(sb, to-from);
+	dir->d_ino = 0;
+	err = ufs_commit_chunk(page, from, to);
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+	mark_inode_dirty(inode);
+out:
+	ufs_put_page(page);
+	UFSD("EXIT\n");
+	return err;
 }
 
 int ufs_make_empty(struct inode * inode, struct inode *dir)
 {
 	struct super_block * sb = dir->i_sb;
-	struct buffer_head * dir_block;
+	struct address_space *mapping = inode->i_mapping;
+	struct page *page = grab_cache_page(mapping, 0);
 	struct ufs_dir_entry * de;
+	char *base;
 	int err;
 
-	dir_block = ufs_bread (inode, 0, 1, &err);
-	if (!dir_block)
-		return err;
+	if (!page)
+		return -ENOMEM;
+	kmap(page);
+	err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE);
+	if (err) {
+		unlock_page(page);
+		goto fail;
+	}
 
-	inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE;
-	de = (struct ufs_dir_entry *) dir_block->b_data;
+
+	base = (char*)page_address(page);
+	memset(base, 0, PAGE_CACHE_SIZE);
+
+	de = (struct ufs_dir_entry *) base;
+
 	de->d_ino = cpu_to_fs32(sb, inode->i_ino);
 	ufs_set_de_type(sb, de, inode->i_mode);
 	ufs_set_de_namlen(sb, de, 1);
@@ -552,72 +587,65 @@
 	de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1));
 	ufs_set_de_namlen(sb, de, 2);
 	strcpy (de->d_name, "..");
-	mark_buffer_dirty(dir_block);
-	brelse (dir_block);
-	mark_inode_dirty(inode);
-	return 0;
+
+	err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE);
+fail:
+	kunmap(page);
+	page_cache_release(page);
+	return err;
 }
 
 /*
  * routine to check that the specified directory is empty (for rmdir)
  */
-int ufs_empty_dir (struct inode * inode)
+int ufs_empty_dir(struct inode * inode)
 {
-	struct super_block * sb;
-	unsigned long offset;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de, * de1;
-	int err;
-	
-	sb = inode->i_sb;
+	struct super_block *sb = inode->i_sb;
+	struct page *page = NULL;
+	unsigned long i, npages = ufs_dir_pages(inode);
 
-	if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
-	    !(bh = ufs_bread (inode, 0, 0, &err))) {
-	    	ufs_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no data block",
-			      inode->i_ino);
-		return 1;
-	}
-	de = (struct ufs_dir_entry *) bh->b_data;
-	de1 = (struct ufs_dir_entry *)
-		((char *)de + fs16_to_cpu(sb, de->d_reclen));
-	if (fs32_to_cpu(sb, de->d_ino) != inode->i_ino || de1->d_ino == 0 ||
-	     strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
-	    	ufs_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir #%lu) - no `.' or `..'",
-			      inode->i_ino);
-		return 1;
-	}
-	offset = fs16_to_cpu(sb, de->d_reclen) + fs16_to_cpu(sb, de1->d_reclen);
-	de = (struct ufs_dir_entry *)
-		((char *)de1 + fs16_to_cpu(sb, de1->d_reclen));
-	while (offset < inode->i_size ) {
-		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
-			brelse (bh);
-			bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
-	 		if (!bh) {
-				ufs_error (sb, "empty_dir",
-					    "directory #%lu contains a hole at offset %lu",
-					    inode->i_ino, offset);
-				offset += sb->s_blocksize;
-				continue;
+	for (i = 0; i < npages; i++) {
+		char *kaddr;
+		struct ufs_dir_entry *de;
+		page = ufs_get_page(inode, i);
+
+		if (IS_ERR(page))
+			continue;
+
+		kaddr = page_address(page);
+		de = (struct ufs_dir_entry *)kaddr;
+		kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1);
+
+		while ((char *)de <= kaddr) {
+			if (de->d_reclen == 0) {
+				ufs_error(inode->i_sb, __FUNCTION__,
+					"zero-length directory entry: "
+					"kaddr=%p, de=%p\n", kaddr, de);
+				goto not_empty;
 			}
-			de = (struct ufs_dir_entry *) bh->b_data;
+			if (de->d_ino) {
+				u16 namelen=ufs_get_de_namlen(sb, de);
+				/* check for . and .. */
+				if (de->d_name[0] != '.')
+					goto not_empty;
+				if (namelen > 2)
+					goto not_empty;
+				if (namelen < 2) {
+					if (inode->i_ino !=
+					    fs32_to_cpu(sb, de->d_ino))
+						goto not_empty;
+				} else if (de->d_name[1] != '.')
+					goto not_empty;
+			}
+			de = ufs_next_entry(sb, de);
 		}
-		if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
-			brelse (bh);
-			return 1;
-		}
-		if (de->d_ino) {
-			brelse (bh);
-			return 0;
-		}
-		offset += fs16_to_cpu(sb, de->d_reclen);
-		de = (struct ufs_dir_entry *)
-			((char *)de + fs16_to_cpu(sb, de->d_reclen));
+		ufs_put_page(page);
 	}
-	brelse (bh);
 	return 1;
+
+not_empty:
+	ufs_put_page(page);
+	return 0;
 }
 
 const struct file_operations ufs_dir_operations = {
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index 312fd3f..0e50015 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -25,6 +25,26 @@
 
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
+#include <linux/buffer_head.h>	/* for sync_mapping_buffers() */
+
+static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct inode *inode = dentry->d_inode;
+	int err;
+	int ret;
+
+	ret = sync_mapping_buffers(inode->i_mapping);
+	if (!(inode->i_state & I_DIRTY))
+		return ret;
+	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+		return ret;
+
+	err = ufs_sync_inode(inode);
+	if (ret == 0)
+		ret = err;
+	return ret;
+}
+
 
 /*
  * We have mostly NULL's here: the current defaults are ok for
@@ -37,6 +57,7 @@
 	.write		= generic_file_write,
 	.mmap		= generic_file_mmap,
 	.open           = generic_file_open,
+	.fsync		= ufs_sync_file,
 	.sendfile	= generic_file_sendfile,
 };
 
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index c7a47ed..9501dcd 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -34,14 +34,6 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_IALLOC_DEBUG
-
-#ifdef UFS_IALLOC_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
 /*
  * NOTE! When we get the inode, we're the only people
  * that have access to it, and as such there are no
@@ -68,7 +60,7 @@
 	int is_directory;
 	unsigned ino, cg, bit;
 	
-	UFSD(("ENTER, ino %lu\n", inode->i_ino))
+	UFSD("ENTER, ino %lu\n", inode->i_ino);
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -91,7 +83,7 @@
 		unlock_super (sb);
 		return;
 	}
-	ucg = ubh_get_ucg(UCPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 	if (!ufs_cg_chkmagic(sb, ucg))
 		ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number");
 
@@ -104,33 +96,33 @@
 
 	clear_inode (inode);
 
-	if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+	if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
 		ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino);
 	else {
-		ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit);
 		if (ino < ucpi->c_irotor)
 			ucpi->c_irotor = ino;
 		fs32_add(sb, &ucg->cg_cs.cs_nifree, 1);
-		fs32_add(sb, &usb1->fs_cstotal.cs_nifree, 1);
+		uspi->cs_total.cs_nifree++;
 		fs32_add(sb, &UFS_SB(sb)->fs_cs(cg).cs_nifree, 1);
 
 		if (is_directory) {
 			fs32_sub(sb, &ucg->cg_cs.cs_ndir, 1);
-			fs32_sub(sb, &usb1->fs_cstotal.cs_ndir, 1);
+			uspi->cs_total.cs_ndir--;
 			fs32_sub(sb, &UFS_SB(sb)->fs_cs(cg).cs_ndir, 1);
 		}
 	}
 
-	ubh_mark_buffer_dirty (USPI_UBH);
-	ubh_mark_buffer_dirty (UCPI_UBH);
+	ubh_mark_buffer_dirty (USPI_UBH(uspi));
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
-		ubh_wait_on_buffer (UCPI_UBH);
+		ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+		ubh_wait_on_buffer (UCPI_UBH(ucpi));
 	}
 	
 	sb->s_dirt = 1;
 	unlock_super (sb);
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 }
 
 /*
@@ -155,7 +147,7 @@
 	unsigned cg, bit, i, j, start;
 	struct ufs_inode_info *ufsi;
 
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 	
 	/* Cannot create files in a deleted directory */
 	if (!dir || !dir->i_nlink)
@@ -213,43 +205,43 @@
 	ucpi = ufs_load_cylinder (sb, cg);
 	if (!ucpi)
 		goto failed;
-	ucg = ubh_get_ucg(UCPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 	if (!ufs_cg_chkmagic(sb, ucg)) 
 		ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number");
 
 	start = ucpi->c_irotor;
-	bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start);
+	bit = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, uspi->s_ipg, start);
 	if (!(bit < uspi->s_ipg)) {
-		bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start);
+		bit = ubh_find_first_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, start);
 		if (!(bit < start)) {
 			ufs_error (sb, "ufs_new_inode",
 			    "cylinder group %u corrupted - error in inode bitmap\n", cg);
 			goto failed;
 		}
 	}
-	UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg))
-	if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
-		ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+	UFSD("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg);
+	if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit))
+		ubh_setbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit);
 	else {
 		ufs_panic (sb, "ufs_new_inode", "internal error");
 		goto failed;
 	}
 	
 	fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1);
-	fs32_sub(sb, &usb1->fs_cstotal.cs_nifree, 1);
+	uspi->cs_total.cs_nifree--;
 	fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1);
 	
 	if (S_ISDIR(mode)) {
 		fs32_add(sb, &ucg->cg_cs.cs_ndir, 1);
-		fs32_add(sb, &usb1->fs_cstotal.cs_ndir, 1);
+		uspi->cs_total.cs_ndir++;
 		fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1);
 	}
 
-	ubh_mark_buffer_dirty (USPI_UBH);
-	ubh_mark_buffer_dirty (UCPI_UBH);
+	ubh_mark_buffer_dirty (USPI_UBH(uspi));
+	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
 	if (sb->s_flags & MS_SYNCHRONOUS) {
-		ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi);
-		ubh_wait_on_buffer (UCPI_UBH);
+		ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
+		ubh_wait_on_buffer (UCPI_UBH(ucpi));
 	}
 	sb->s_dirt = 1;
 
@@ -272,6 +264,7 @@
 	ufsi->i_shadow = 0;
 	ufsi->i_osync = 0;
 	ufsi->i_oeftflag = 0;
+	ufsi->i_dir_start_lookup = 0;
 	memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1));
 
 	insert_inode_hash(inode);
@@ -287,14 +280,14 @@
 		return ERR_PTR(-EDQUOT);
 	}
 
-	UFSD(("allocating inode %lu\n", inode->i_ino))
-	UFSD(("EXIT\n"))
+	UFSD("allocating inode %lu\n", inode->i_ino);
+	UFSD("EXIT\n");
 	return inode;
 
 failed:
 	unlock_super (sb);
 	make_bad_inode(inode);
 	iput (inode);
-	UFSD(("EXIT (FAILED)\n"))
+	UFSD("EXIT (FAILED)\n");
 	return ERR_PTR(-ENOSPC);
 }
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 3c3f62c..f2dbdf5 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -41,14 +41,7 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_INODE_DEBUG
-#undef UFS_INODE_DEBUG_MORE
-
-#ifdef UFS_INODE_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
+static u64 ufs_frag_map(struct inode *inode, sector_t frag);
 
 static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4])
 {
@@ -61,7 +54,7 @@
 	int n = 0;
 
 
-	UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks));
+	UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks);
 	if (i_block < 0) {
 		ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
 	} else if (i_block < direct_blocks) {
@@ -89,7 +82,7 @@
  * the begining of the filesystem.
  */
 
-u64  ufs_frag_map(struct inode *inode, sector_t frag)
+static u64 ufs_frag_map(struct inode *inode, sector_t frag)
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block *sb = inode->i_sb;
@@ -104,8 +97,8 @@
 	unsigned flags = UFS_SB(sb)->s_flags;
 	u64 temp = 0L;
 
-	UFSD((": frag = %llu  depth = %d\n", (unsigned long long)frag, depth));
-	UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask));
+	UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
+	UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask);
 
 	if (depth == 0)
 		return 0;
@@ -161,26 +154,64 @@
 	return ret;
 }
 
-static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
-	unsigned int fragment, unsigned int new_fragment,
-	unsigned int required, int *err, int metadata, long *phys, int *new)
+static void ufs_clear_frag(struct inode *inode, struct buffer_head *bh)
+{
+	lock_buffer(bh);
+	memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+	set_buffer_uptodate(bh);
+	mark_buffer_dirty(bh);
+	unlock_buffer(bh);
+	if (IS_SYNC(inode))
+		sync_dirty_buffer(bh);
+}
+
+static struct buffer_head *
+ufs_clear_frags(struct inode *inode, sector_t beg,
+		unsigned int n)
+{
+	struct buffer_head *res, *bh;
+	sector_t end = beg + n;
+
+	res = sb_getblk(inode->i_sb, beg);
+	ufs_clear_frag(inode, res);
+	for (++beg; beg < end; ++beg) {
+		bh = sb_getblk(inode->i_sb, beg);
+		ufs_clear_frag(inode, bh);
+		brelse(bh);
+	}
+	return res;
+}
+
+/**
+ * ufs_inode_getfrag() - allocate new fragment(s)
+ * @inode - pointer to inode
+ * @fragment - number of `fragment' which hold pointer
+ *   to new allocated fragment(s)
+ * @new_fragment - number of new allocated fragment(s)
+ * @required - how many fragment(s) we require
+ * @err - we set it if something wrong
+ * @phys - pointer to where we save physical number of new allocated fragments,
+ *   NULL if we allocate not data(indirect blocks for example).
+ * @new - we set it if we allocate new block
+ * @locked_page - for ufs_new_fragments()
+ */
+static struct buffer_head *
+ufs_inode_getfrag(struct inode *inode, unsigned int fragment,
+		  sector_t new_fragment, unsigned int required, int *err,
+		  long *phys, int *new, struct page *locked_page)
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
+	struct super_block *sb = inode->i_sb;
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
 	struct buffer_head * result;
 	unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
 	unsigned tmp, goal;
 	__fs32 * p, * p2;
-	unsigned flags = 0;
 
-	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
-		inode->i_ino, fragment, new_fragment, required))         
+	UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, required %u, "
+	     "metadata %d\n", inode->i_ino, fragment,
+	     (unsigned long long)new_fragment, required, !phys);
 
-	sb = inode->i_sb;
-	uspi = UFS_SB(sb)->s_uspi;
-
-	flags = UFS_SB(sb)->s_flags;
         /* TODO : to be done for write support
         if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
              goto ufs2;
@@ -195,16 +226,16 @@
 	tmp = fs32_to_cpu(sb, *p);
 	lastfrag = ufsi->i_lastfrag;
 	if (tmp && fragment < lastfrag) {
-		if (metadata) {
+		if (!phys) {
 			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
 			if (tmp == fs32_to_cpu(sb, *p)) {
-				UFSD(("EXIT, result %u\n", tmp + blockoff))
+				UFSD("EXIT, result %u\n", tmp + blockoff);
 				return result;
 			}
 			brelse (result);
 			goto repeat;
 		} else {
-			*phys = tmp;
+			*phys = tmp + blockoff;
 			return NULL;
 		}
 	}
@@ -221,7 +252,8 @@
 		if (lastblockoff) {
 			p2 = ufsi->i_u1.i_data + lastblock;
 			tmp = ufs_new_fragments (inode, p2, lastfrag, 
-				fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err);
+						 fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff,
+						 err, locked_page);
 			if (!tmp) {
 				if (lastfrag != ufsi->i_lastfrag)
 					goto repeat;
@@ -233,14 +265,16 @@
 		}
 		goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb;
 		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
-			goal, required + blockoff, err);
+					 goal, required + blockoff,
+					 err, locked_page);
 	}
 	/*
 	 * We will extend last allocated block
 	 */
 	else if (lastblock == block) {
-		tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff),
-			fs32_to_cpu(sb, *p), required +  (blockoff - lastblockoff), err);
+		tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff),
+					fs32_to_cpu(sb, *p), required +  (blockoff - lastblockoff),
+					err, locked_page);
 	}
 	/*
 	 * We will allocate new block before last allocated block
@@ -248,8 +282,8 @@
 	else /* (lastblock > block) */ {
 		if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1])))
 			goal = tmp + uspi->s_fpb;
-		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
-			goal, uspi->s_fpb, err);
+		tmp = ufs_new_fragments(inode, p, fragment - blockoff,
+					goal, uspi->s_fpb, err, locked_page);
 	}
 	if (!tmp) {
 		if ((!blockoff && *p) || 
@@ -259,14 +293,10 @@
 		return NULL;
 	}
 
-	/* The nullification of framgents done in ufs/balloc.c is
-	 * something I don't have the stomache to move into here right
-	 * now. -DaveM
-	 */
-	if (metadata) {
-		result = sb_getblk(inode->i_sb, tmp + blockoff);
+	if (!phys) {
+		result = ufs_clear_frags(inode, tmp + blockoff, required);
 	} else {
-		*phys = tmp;
+		*phys = tmp + blockoff;
 		result = NULL;
 		*err = 0;
 		*new = 1;
@@ -276,7 +306,7 @@
 	if (IS_SYNC(inode))
 		ufs_sync_inode (inode);
 	mark_inode_dirty(inode);
-	UFSD(("EXIT, result %u\n", tmp + blockoff))
+	UFSD("EXIT, result %u\n", tmp + blockoff);
 	return result;
 
      /* This part : To be implemented ....
@@ -295,22 +325,35 @@
      */
 }
 
-static struct buffer_head * ufs_block_getfrag (struct inode *inode,
-	struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment, 
-	unsigned int blocksize, int * err, int metadata, long *phys, int *new)
+/**
+ * ufs_inode_getblock() - allocate new block
+ * @inode - pointer to inode
+ * @bh - pointer to block which hold "pointer" to new allocated block
+ * @fragment - number of `fragment' which hold pointer
+ *   to new allocated block
+ * @new_fragment - number of new allocated fragment
+ *  (block will hold this fragment and also uspi->s_fpb-1)
+ * @err - see ufs_inode_getfrag()
+ * @phys - see ufs_inode_getfrag()
+ * @new - see ufs_inode_getfrag()
+ * @locked_page - see ufs_inode_getfrag()
+ */
+static struct buffer_head *
+ufs_inode_getblock(struct inode *inode, struct buffer_head *bh,
+		  unsigned int fragment, sector_t new_fragment, int *err,
+		  long *phys, int *new, struct page *locked_page)
 {
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
+	struct super_block *sb = inode->i_sb;
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
 	struct buffer_head * result;
 	unsigned tmp, goal, block, blockoff;
 	__fs32 * p;
 
-	sb = inode->i_sb;
-	uspi = UFS_SB(sb)->s_uspi;
 	block = ufs_fragstoblks (fragment);
 	blockoff = ufs_fragnum (fragment);
 
-	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))	
+	UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, metadata %d\n",
+	     inode->i_ino, fragment, (unsigned long long)new_fragment, !phys);
 
 	result = NULL;
 	if (!bh)
@@ -326,14 +369,14 @@
 repeat:
 	tmp = fs32_to_cpu(sb, *p);
 	if (tmp) {
-		if (metadata) {
+		if (!phys) {
 			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
 			if (tmp == fs32_to_cpu(sb, *p))
 				goto out;
 			brelse (result);
 			goto repeat;
 		} else {
-			*phys = tmp;
+			*phys = tmp + blockoff;
 			goto out;
 		}
 	}
@@ -342,21 +385,19 @@
 		goal = tmp + uspi->s_fpb;
 	else
 		goal = bh->b_blocknr + uspi->s_fpb;
-	tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
+	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
+				uspi->s_fpb, err, locked_page);
 	if (!tmp) {
 		if (fs32_to_cpu(sb, *p))
 			goto repeat;
 		goto out;
 	}		
 
-	/* The nullification of framgents done in ufs/balloc.c is
-	 * something I don't have the stomache to move into here right
-	 * now. -DaveM
-	 */
-	if (metadata) {
-		result = sb_getblk(sb, tmp + blockoff);
+
+	if (!phys) {
+		result = ufs_clear_frags(inode, tmp + blockoff, uspi->s_fpb);
 	} else {
-		*phys = tmp;
+		*phys = tmp + blockoff;
 		*new = 1;
 	}
 
@@ -365,18 +406,19 @@
 		sync_dirty_buffer(bh);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
-	UFSD(("result %u\n", tmp + blockoff));
+	UFSD("result %u\n", tmp + blockoff);
 out:
 	brelse (bh);
-	UFSD(("EXIT\n"));
+	UFSD("EXIT\n");
 	return result;
 }
 
-/*
- * This function gets the block which contains the fragment.
+/**
+ * ufs_getfrag_bloc() - `get_block_t' function, interface between UFS and
+ * readpage, writepage and so on
  */
 
-int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
+int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
 	struct super_block * sb = inode->i_sb;
 	struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
@@ -387,7 +429,7 @@
 	
 	if (!create) {
 		phys64 = ufs_frag_map(inode, fragment);
-		UFSD(("phys64 = %llu \n",phys64));
+		UFSD("phys64 = %llu \n",phys64);
 		if (phys64)
 			map_bh(bh_result, sb, phys64);
 		return 0;
@@ -402,7 +444,7 @@
 
 	lock_kernel();
 
-	UFSD(("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment))
+	UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment);
 	if (fragment < 0)
 		goto abort_negative;
 	if (fragment >
@@ -418,15 +460,15 @@
 	 * it much more readable:
 	 */
 #define GET_INODE_DATABLOCK(x) \
-		ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+	ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page)
 #define GET_INODE_PTR(x) \
-		ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+	ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page)
 #define GET_INDIRECT_DATABLOCK(x) \
-		ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
-				  &err, 0, &phys, &new);
+	ufs_inode_getblock(inode, bh, x, fragment,	\
+			  &err, &phys, &new, bh_result->b_page);
 #define GET_INDIRECT_PTR(x) \
-		ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
-				  &err, 1, NULL, NULL);
+	ufs_inode_getblock(inode, bh, x, fragment,	\
+			  &err, NULL, NULL, bh_result->b_page);
 
 	if (ptr < UFS_NDIR_FRAGMENT) {
 		bh = GET_INODE_DATABLOCK(ptr);
@@ -474,8 +516,9 @@
 	goto abort;
 }
 
-struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
-				int create, int *err)
+static struct buffer_head *ufs_getfrag(struct inode *inode,
+				       unsigned int fragment,
+				       int create, int *err)
 {
 	struct buffer_head dummy;
 	int error;
@@ -502,7 +545,7 @@
 {
 	struct buffer_head * bh;
 
-	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+	UFSD("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment);
 	bh = ufs_getfrag (inode, fragment, create, err);
 	if (!bh || buffer_uptodate(bh)) 		
 		return bh;
@@ -540,6 +583,28 @@
 	.bmap = ufs_bmap
 };
 
+static void ufs_set_inode_ops(struct inode *inode)
+{
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &ufs_file_inode_operations;
+		inode->i_fop = &ufs_file_operations;
+		inode->i_mapping->a_ops = &ufs_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &ufs_dir_inode_operations;
+		inode->i_fop = &ufs_dir_operations;
+		inode->i_mapping->a_ops = &ufs_aops;
+	} else if (S_ISLNK(inode->i_mode)) {
+		if (!inode->i_blocks)
+			inode->i_op = &ufs_fast_symlink_inode_operations;
+		else {
+			inode->i_op = &page_symlink_inode_operations;
+			inode->i_mapping->a_ops = &ufs_aops;
+		}
+	} else
+		init_special_inode(inode, inode->i_mode,
+				   ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
+}
+
 void ufs_read_inode (struct inode * inode)
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
@@ -552,7 +617,7 @@
 	unsigned i;
 	unsigned flags;
 	
-	UFSD(("ENTER, ino %lu\n", inode->i_ino))
+	UFSD("ENTER, ino %lu\n", inode->i_ino);
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -603,38 +668,22 @@
 	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
 	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
 	ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
+	ufsi->i_dir_start_lookup = 0;
 	
 	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
 		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
 			ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
-	}
-	else {
+	} else {
 		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
 			ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
 	}
 	ufsi->i_osync = 0;
 
-	if (S_ISREG(inode->i_mode)) {
-		inode->i_op = &ufs_file_inode_operations;
-		inode->i_fop = &ufs_file_operations;
-		inode->i_mapping->a_ops = &ufs_aops;
-	} else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = &ufs_dir_inode_operations;
-		inode->i_fop = &ufs_dir_operations;
-	} else if (S_ISLNK(inode->i_mode)) {
-		if (!inode->i_blocks)
-			inode->i_op = &ufs_fast_symlink_inode_operations;
-		else {
-			inode->i_op = &page_symlink_inode_operations;
-			inode->i_mapping->a_ops = &ufs_aops;
-		}
-	} else
-		init_special_inode(inode, inode->i_mode,
-			ufs_get_inode_dev(sb, ufsi));
+	ufs_set_inode_ops(inode);
 
 	brelse (bh);
 
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return;
 
 bad_inode:
@@ -642,7 +691,7 @@
 	return;
 
 ufs2_inode :
-	UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino))
+	UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
 
 	ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
 
@@ -690,27 +739,11 @@
 	}
 	ufsi->i_osync = 0;
 
-	if (S_ISREG(inode->i_mode)) {
-		inode->i_op = &ufs_file_inode_operations;
-		inode->i_fop = &ufs_file_operations;
-		inode->i_mapping->a_ops = &ufs_aops;
-	} else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = &ufs_dir_inode_operations;
-		inode->i_fop = &ufs_dir_operations;
-	} else if (S_ISLNK(inode->i_mode)) {
-		if (!inode->i_blocks)
-			inode->i_op = &ufs_fast_symlink_inode_operations;
-		else {
-			inode->i_op = &page_symlink_inode_operations;
-			inode->i_mapping->a_ops = &ufs_aops;
-		}
-	} else   /* TODO  : here ...*/
-		init_special_inode(inode, inode->i_mode,
-			ufs_get_inode_dev(sb, ufsi));
+	ufs_set_inode_ops(inode);
 
 	brelse(bh);
 
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return;
 }
 
@@ -724,7 +757,7 @@
 	unsigned i;
 	unsigned flags;
 
-	UFSD(("ENTER, ino %lu\n", inode->i_ino))
+	UFSD("ENTER, ino %lu\n", inode->i_ino);
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -785,7 +818,7 @@
 		sync_dirty_buffer(bh);
 	brelse (bh);
 	
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return 0;
 }
 
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 8d5f98a..abd5f23 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -1,6 +1,9 @@
 /*
  * linux/fs/ufs/namei.c
  *
+ * Migration to usage of "page cache" on May 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
+ *
  * Copyright (C) 1998
  * Daniel Pirkl <daniel.pirkl@email.cz>
  * Charles University, Faculty of Mathematics and Physics
@@ -28,21 +31,9 @@
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
 #include "swab.h"	/* will go away - see comment in mknod() */
 #include "util.h"
 
-/*
-#undef UFS_NAMEI_DEBUG
-*/
-#define UFS_NAMEI_DEBUG
-
-#ifdef UFS_NAMEI_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
 static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
 {
 	int err = ufs_add_link(dentry, inode);
@@ -88,8 +79,13 @@
 static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
 		struct nameidata *nd)
 {
-	struct inode * inode = ufs_new_inode(dir, mode);
-	int err = PTR_ERR(inode);
+	struct inode *inode;
+	int err;
+
+	UFSD("BEGIN\n");
+	inode = ufs_new_inode(dir, mode);
+	err = PTR_ERR(inode);
+
 	if (!IS_ERR(inode)) {
 		inode->i_op = &ufs_file_inode_operations;
 		inode->i_fop = &ufs_file_operations;
@@ -99,6 +95,7 @@
 		err = ufs_add_nondir(dentry, inode);
 		unlock_kernel();
 	}
+	UFSD("END: err=%d\n", err);
 	return err;
 }
 
@@ -205,6 +202,7 @@
 
 	inode->i_op = &ufs_dir_inode_operations;
 	inode->i_fop = &ufs_dir_operations;
+	inode->i_mapping->a_ops = &ufs_aops;
 
 	inode_inc_link_count(inode);
 
@@ -231,19 +229,18 @@
 	goto out;
 }
 
-static int ufs_unlink(struct inode * dir, struct dentry *dentry)
+static int ufs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct inode * inode = dentry->d_inode;
-	struct buffer_head * bh;
-	struct ufs_dir_entry * de;
+	struct ufs_dir_entry *de;
+	struct page *page;
 	int err = -ENOENT;
 
-	lock_kernel();
-	de = ufs_find_entry (dentry, &bh);
+	de = ufs_find_entry(dir, dentry, &page);
 	if (!de)
 		goto out;
 
-	err = ufs_delete_entry (dir, de, bh);
+	err = ufs_delete_entry(dir, de, page);
 	if (err)
 		goto out;
 
@@ -251,7 +248,6 @@
 	inode_dec_link_count(inode);
 	err = 0;
 out:
-	unlock_kernel();
 	return err;
 }
 
@@ -273,42 +269,42 @@
 	return err;
 }
 
-static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
-	struct inode * new_dir,	struct dentry * new_dentry )
+static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		      struct inode *new_dir, struct dentry *new_dentry)
 {
 	struct inode *old_inode = old_dentry->d_inode;
 	struct inode *new_inode = new_dentry->d_inode;
-	struct buffer_head *dir_bh = NULL;
-	struct ufs_dir_entry *dir_de = NULL;
-	struct buffer_head *old_bh;
+	struct page *dir_page = NULL;
+	struct ufs_dir_entry * dir_de = NULL;
+	struct page *old_page;
 	struct ufs_dir_entry *old_de;
 	int err = -ENOENT;
 
-	lock_kernel();
-	old_de = ufs_find_entry (old_dentry, &old_bh);
+	old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
 	if (!old_de)
 		goto out;
 
 	if (S_ISDIR(old_inode->i_mode)) {
 		err = -EIO;
-		dir_de = ufs_dotdot(old_inode, &dir_bh);
+		dir_de = ufs_dotdot(old_inode, &dir_page);
 		if (!dir_de)
 			goto out_old;
 	}
 
 	if (new_inode) {
-		struct buffer_head *new_bh;
+		struct page *new_page;
 		struct ufs_dir_entry *new_de;
 
 		err = -ENOTEMPTY;
-		if (dir_de && !ufs_empty_dir (new_inode))
+		if (dir_de && !ufs_empty_dir(new_inode))
 			goto out_dir;
+
 		err = -ENOENT;
-		new_de = ufs_find_entry (new_dentry, &new_bh);
+		new_de = ufs_find_entry(new_dir, new_dentry, &new_page);
 		if (!new_de)
 			goto out_dir;
 		inode_inc_link_count(old_inode);
-		ufs_set_link(new_dir, new_de, new_bh, old_inode);
+		ufs_set_link(new_dir, new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		if (dir_de)
 			new_inode->i_nlink--;
@@ -329,24 +325,32 @@
 			inode_inc_link_count(new_dir);
 	}
 
-	ufs_delete_entry (old_dir, old_de, old_bh);
+	/*
+	 * Like most other Unix systems, set the ctime for inodes on a
+ 	 * rename.
+	 * inode_dec_link_count() will mark the inode dirty.
+	 */
+	old_inode->i_ctime = CURRENT_TIME_SEC;
 
+	ufs_delete_entry(old_dir, old_de, old_page);
 	inode_dec_link_count(old_inode);
 
 	if (dir_de) {
-		ufs_set_link(old_inode, dir_de, dir_bh, new_dir);
+		ufs_set_link(old_inode, dir_de, dir_page, new_dir);
 		inode_dec_link_count(old_dir);
 	}
-	unlock_kernel();
 	return 0;
 
+
 out_dir:
-	if (dir_de)
-		brelse(dir_bh);
+	if (dir_de) {
+		kunmap(dir_page);
+		page_cache_release(dir_page);
+	}
 out_old:
-	brelse (old_bh);
+	kunmap(old_page);
+	page_cache_release(old_page);
 out:
-	unlock_kernel();
 	return err;
 }
 
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index fe5ab2a..74ef5e9 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -90,95 +90,84 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_SUPER_DEBUG
-#undef UFS_SUPER_DEBUG_MORE
-
-
-#undef UFS_SUPER_DEBUG_MORE
-#ifdef UFS_SUPER_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-#ifdef UFS_SUPER_DEBUG_MORE
+#ifdef CONFIG_UFS_DEBUG
 /*
  * Print contents of ufs_super_block, useful for debugging
  */
-void ufs_print_super_stuff(struct super_block *sb,
-	struct ufs_super_block_first * usb1,
-	struct ufs_super_block_second * usb2, 
-	struct ufs_super_block_third * usb3)
+static void ufs_print_super_stuff(struct super_block *sb, unsigned flags,
+				  struct ufs_super_block_first *usb1,
+				  struct ufs_super_block_second *usb2,
+				  struct ufs_super_block_third *usb3)
 {
 	printk("ufs_print_super_stuff\n");
-	printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
-	printk("  magic:         0x%x\n", fs32_to_cpu(sb, usb3->fs_magic));
-	printk("  sblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_sblkno));
-	printk("  cblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_cblkno));
-	printk("  iblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_iblkno));
-	printk("  dblkno:        %u\n", fs32_to_cpu(sb, usb1->fs_dblkno));
-	printk("  cgoffset:      %u\n", fs32_to_cpu(sb, usb1->fs_cgoffset));
-	printk("  ~cgmask:       0x%x\n", ~fs32_to_cpu(sb, usb1->fs_cgmask));
-	printk("  size:          %u\n", fs32_to_cpu(sb, usb1->fs_size));
-	printk("  dsize:         %u\n", fs32_to_cpu(sb, usb1->fs_dsize));
-	printk("  ncg:           %u\n", fs32_to_cpu(sb, usb1->fs_ncg));
-	printk("  bsize:         %u\n", fs32_to_cpu(sb, usb1->fs_bsize));
-	printk("  fsize:         %u\n", fs32_to_cpu(sb, usb1->fs_fsize));
-	printk("  frag:          %u\n", fs32_to_cpu(sb, usb1->fs_frag));
-	printk("  fragshift:     %u\n", fs32_to_cpu(sb, usb1->fs_fragshift));
-	printk("  ~fmask:        %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask));
-	printk("  fshift:        %u\n", fs32_to_cpu(sb, usb1->fs_fshift));
-	printk("  sbsize:        %u\n", fs32_to_cpu(sb, usb1->fs_sbsize));
-	printk("  spc:           %u\n", fs32_to_cpu(sb, usb1->fs_spc));
-	printk("  cpg:           %u\n", fs32_to_cpu(sb, usb1->fs_cpg));
-	printk("  ipg:           %u\n", fs32_to_cpu(sb, usb1->fs_ipg));
-	printk("  fpg:           %u\n", fs32_to_cpu(sb, usb1->fs_fpg));
-	printk("  csaddr:        %u\n", fs32_to_cpu(sb, usb1->fs_csaddr));
-	printk("  cssize:        %u\n", fs32_to_cpu(sb, usb1->fs_cssize));
-	printk("  cgsize:        %u\n", fs32_to_cpu(sb, usb1->fs_cgsize));
-	printk("  fstodb:        %u\n", fs32_to_cpu(sb, usb1->fs_fsbtodb));
-	printk("  contigsumsize: %d\n", fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize));
-	printk("  postblformat:  %u\n", fs32_to_cpu(sb, usb3->fs_postblformat));
-	printk("  nrpos:         %u\n", fs32_to_cpu(sb, usb3->fs_nrpos));
-	printk("  ndir           %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir));
-	printk("  nifree         %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree));
-	printk("  nbfree         %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree));
-	printk("  nffree         %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree));
-	printk("\n");
-}
-
-/*
- * Print contents of ufs2 ufs_super_block, useful for debugging
- */
-void ufs2_print_super_stuff(
-     struct super_block *sb,
-      struct ufs_super_block *usb)
-{
-	printk("ufs_print_super_stuff\n");
-	printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
-	printk("  magic:         0x%x\n", fs32_to_cpu(sb, usb->fs_magic));
-	printk("  fs_size:   %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size));
-	printk("  fs_dsize:  %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize));
-	printk("  bsize:         %u\n", fs32_to_cpu(usb, usb->fs_bsize));
-	printk("  fsize:         %u\n", fs32_to_cpu(usb, usb->fs_fsize));
-	printk("  fs_volname:  %s\n", usb->fs_u11.fs_u2.fs_volname);
-	printk("  fs_fsmnt:  %s\n", usb->fs_u11.fs_u2.fs_fsmnt);
-	printk("  fs_sblockloc: %u\n",fs64_to_cpu(sb,
-			usb->fs_u11.fs_u2.fs_sblockloc));
-	printk("  cs_ndir(No of dirs):  %u\n",fs64_to_cpu(sb,
-			usb->fs_u11.fs_u2.fs_cstotal.cs_ndir));
-	printk("  cs_nbfree(No of free blocks):  %u\n",fs64_to_cpu(sb,
-			usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree));
+	printk("  magic:     0x%x\n", fs32_to_cpu(sb, usb3->fs_magic));
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		printk("  fs_size:   %llu\n", (unsigned long long)
+		       fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size));
+		printk("  fs_dsize:  %llu\n", (unsigned long long)
+		       fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize));
+		printk("  bsize:         %u\n",
+		       fs32_to_cpu(sb, usb1->fs_bsize));
+		printk("  fsize:         %u\n",
+		       fs32_to_cpu(sb, usb1->fs_fsize));
+		printk("  fs_volname:  %s\n", usb2->fs_un.fs_u2.fs_volname);
+		printk("  fs_sblockloc: %llu\n", (unsigned long long)
+		       fs64_to_cpu(sb, usb2->fs_un.fs_u2.fs_sblockloc));
+		printk("  cs_ndir(No of dirs):  %llu\n", (unsigned long long)
+		       fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir));
+		printk("  cs_nbfree(No of free blocks):  %llu\n",
+		       (unsigned long long)
+		       fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree));
+	} else {
+		printk(" sblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_sblkno));
+		printk(" cblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_cblkno));
+		printk(" iblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_iblkno));
+		printk(" dblkno:      %u\n", fs32_to_cpu(sb, usb1->fs_dblkno));
+		printk(" cgoffset:    %u\n",
+		       fs32_to_cpu(sb, usb1->fs_cgoffset));
+		printk(" ~cgmask:     0x%x\n",
+		       ~fs32_to_cpu(sb, usb1->fs_cgmask));
+		printk(" size:        %u\n", fs32_to_cpu(sb, usb1->fs_size));
+		printk(" dsize:       %u\n", fs32_to_cpu(sb, usb1->fs_dsize));
+		printk(" ncg:         %u\n", fs32_to_cpu(sb, usb1->fs_ncg));
+		printk(" bsize:       %u\n", fs32_to_cpu(sb, usb1->fs_bsize));
+		printk(" fsize:       %u\n", fs32_to_cpu(sb, usb1->fs_fsize));
+		printk(" frag:        %u\n", fs32_to_cpu(sb, usb1->fs_frag));
+		printk(" fragshift:   %u\n",
+		       fs32_to_cpu(sb, usb1->fs_fragshift));
+		printk(" ~fmask:      %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask));
+		printk(" fshift:      %u\n", fs32_to_cpu(sb, usb1->fs_fshift));
+		printk(" sbsize:      %u\n", fs32_to_cpu(sb, usb1->fs_sbsize));
+		printk(" spc:         %u\n", fs32_to_cpu(sb, usb1->fs_spc));
+		printk(" cpg:         %u\n", fs32_to_cpu(sb, usb1->fs_cpg));
+		printk(" ipg:         %u\n", fs32_to_cpu(sb, usb1->fs_ipg));
+		printk(" fpg:         %u\n", fs32_to_cpu(sb, usb1->fs_fpg));
+		printk(" csaddr:      %u\n", fs32_to_cpu(sb, usb1->fs_csaddr));
+		printk(" cssize:      %u\n", fs32_to_cpu(sb, usb1->fs_cssize));
+		printk(" cgsize:      %u\n", fs32_to_cpu(sb, usb1->fs_cgsize));
+		printk(" fstodb:      %u\n",
+		       fs32_to_cpu(sb, usb1->fs_fsbtodb));
+		printk(" nrpos:       %u\n", fs32_to_cpu(sb, usb3->fs_nrpos));
+		printk(" ndir         %u\n",
+		       fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir));
+		printk(" nifree       %u\n",
+		       fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree));
+		printk(" nbfree       %u\n",
+		       fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree));
+		printk(" nffree       %u\n",
+		       fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree));
+	}
 	printk("\n");
 }
 
 /*
  * Print contents of ufs_cylinder_group, useful for debugging
  */
-void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group *cg)
+static void ufs_print_cylinder_stuff(struct super_block *sb,
+				     struct ufs_cylinder_group *cg)
 {
 	printk("\nufs_print_cylinder_stuff\n");
-	printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group));
+	printk("size of ucg: %zu\n", sizeof(struct ufs_cylinder_group));
 	printk("  magic:        %x\n", fs32_to_cpu(sb, cg->cg_magic));
 	printk("  time:         %u\n", fs32_to_cpu(sb, cg->cg_time));
 	printk("  cgx:          %u\n", fs32_to_cpu(sb, cg->cg_cgx));
@@ -202,12 +191,18 @@
 	printk("  iuseoff:      %u\n", fs32_to_cpu(sb, cg->cg_iusedoff));
 	printk("  freeoff:      %u\n", fs32_to_cpu(sb, cg->cg_freeoff));
 	printk("  nextfreeoff:  %u\n", fs32_to_cpu(sb, cg->cg_nextfreeoff));
-	printk("  clustersumoff %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff));
-	printk("  clusteroff    %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff));
-	printk("  nclusterblks  %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks));
+	printk("  clustersumoff %u\n",
+	       fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff));
+	printk("  clusteroff    %u\n",
+	       fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff));
+	printk("  nclusterblks  %u\n",
+	       fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks));
 	printk("\n");
 }
-#endif /* UFS_SUPER_DEBUG_MORE */
+#else
+#  define ufs_print_super_stuff(sb, flags, usb1, usb2, usb3) /**/
+#  define ufs_print_cylinder_stuff(sb, cg) /**/
+#endif /* CONFIG_UFS_DEBUG */
 
 static struct super_operations ufs_super_ops;
 
@@ -225,7 +220,7 @@
 	
 	if (!(sb->s_flags & MS_RDONLY)) {
 		usb1->fs_clean = UFS_FSBAD;
-		ubh_mark_buffer_dirty(USPI_UBH);
+		ubh_mark_buffer_dirty(USPI_UBH(uspi));
 		sb->s_dirt = 1;
 		sb->s_flags |= MS_RDONLY;
 	}
@@ -257,7 +252,7 @@
 	
 	if (!(sb->s_flags & MS_RDONLY)) {
 		usb1->fs_clean = UFS_FSBAD;
-		ubh_mark_buffer_dirty(USPI_UBH);
+		ubh_mark_buffer_dirty(USPI_UBH(uspi));
 		sb->s_dirt = 1;
 	}
 	va_start (args, fmt);
@@ -309,7 +304,7 @@
 {
 	char * p;
 	
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 	
 	if (!options)
 		return 1;
@@ -386,27 +381,57 @@
 }
 
 /*
+ * Diffrent types of UFS hold fs_cstotal in different
+ * places, and use diffrent data structure for it.
+ * To make things simplier we just copy fs_cstotal to ufs_sb_private_info
+ */
+static void ufs_setup_cstotal(struct super_block *sb)
+{
+	struct ufs_sb_info *sbi = UFS_SB(sb);
+	struct ufs_sb_private_info *uspi = sbi->s_uspi;
+	struct ufs_super_block_first *usb1;
+	struct ufs_super_block_second *usb2;
+	struct ufs_super_block_third *usb3;
+	unsigned mtype = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE;
+
+	UFSD("ENTER, mtype=%u\n", mtype);
+	usb1 = ubh_get_usb_first(uspi);
+	usb2 = ubh_get_usb_second(uspi);
+	usb3 = ubh_get_usb_third(uspi);
+
+	if ((mtype == UFS_MOUNT_UFSTYPE_44BSD &&
+	     (usb1->fs_flags & UFS_FLAGS_UPDATED)) ||
+	    mtype == UFS_MOUNT_UFSTYPE_UFS2) {
+		/*we have statistic in different place, then usual*/
+		uspi->cs_total.cs_ndir = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir);
+		uspi->cs_total.cs_nbfree = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree);
+		uspi->cs_total.cs_nifree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree);
+		uspi->cs_total.cs_nffree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree);
+	} else {
+		uspi->cs_total.cs_ndir = fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir);
+		uspi->cs_total.cs_nbfree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree);
+		uspi->cs_total.cs_nifree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
+		uspi->cs_total.cs_nffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
+	}
+	UFSD("EXIT\n");
+}
+
+/*
  * Read on-disk structures associated with cylinder groups
  */
-static int ufs_read_cylinder_structures (struct super_block *sb)
+static int ufs_read_cylinder_structures(struct super_block *sb)
 {
-	struct ufs_sb_info * sbi = UFS_SB(sb);
-	struct ufs_sb_private_info * uspi;
-	struct ufs_super_block *usb;
+	struct ufs_sb_info *sbi = UFS_SB(sb);
+	struct ufs_sb_private_info *uspi = sbi->s_uspi;
+	unsigned flags = sbi->s_flags;
 	struct ufs_buffer_head * ubh;
 	unsigned char * base, * space;
 	unsigned size, blks, i;
-	unsigned flags = 0;
-	
-	UFSD(("ENTER\n"))
-	
-	uspi = sbi->s_uspi;
+	struct ufs_super_block_third *usb3;
 
-	usb  = (struct ufs_super_block *)
-		((struct ufs_buffer_head *)uspi)->bh[0]->b_data;
+	UFSD("ENTER\n");
 
-        flags = UFS_SB(sb)->s_flags;
-	
+	usb3 = ubh_get_usb_third(uspi);
 	/*
 	 * Read cs structures from (usually) first data block
 	 * on the device. 
@@ -424,7 +449,7 @@
 
 		if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 
 			ubh = ubh_bread(sb,
-				fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
+				fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr) + i, size);
 		else 
 			ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
 		
@@ -451,14 +476,13 @@
 		sbi->s_cgno[i] = UFS_CGNO_EMPTY;
 	}
 	for (i = 0; i < uspi->s_ncg; i++) {
-		UFSD(("read cg %u\n", i))
+		UFSD("read cg %u\n", i);
 		if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i))))
 			goto failed;
 		if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data))
 			goto failed;
-#ifdef UFS_SUPER_DEBUG_MORE
+
 		ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data);
-#endif
 	}
 	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
 		if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
@@ -466,7 +490,7 @@
 		sbi->s_cgno[i] = UFS_CGNO_EMPTY;
 	}
 	sbi->s_cg_loaded = 0;
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return 1;
 
 failed:
@@ -479,26 +503,69 @@
 		for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
 			kfree (sbi->s_ucpi[i]);
 	}
-	UFSD(("EXIT (FAILED)\n"))
+	UFSD("EXIT (FAILED)\n");
 	return 0;
 }
 
 /*
- * Put on-disk structures associated with cylinder groups and 
- * write them back to disk
+ * Sync our internal copy of fs_cstotal with disk
  */
-static void ufs_put_cylinder_structures (struct super_block *sb)
+static void ufs_put_cstotal(struct super_block *sb)
 {
-	struct ufs_sb_info * sbi = UFS_SB(sb);
-	struct ufs_sb_private_info * uspi;
+	unsigned mtype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE;
+	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
+	struct ufs_super_block_first *usb1;
+	struct ufs_super_block_second *usb2;
+	struct ufs_super_block_third *usb3;
+
+	UFSD("ENTER\n");
+	usb1 = ubh_get_usb_first(uspi);
+	usb2 = ubh_get_usb_second(uspi);
+	usb3 = ubh_get_usb_third(uspi);
+
+	if ((mtype == UFS_MOUNT_UFSTYPE_44BSD &&
+	     (usb1->fs_flags & UFS_FLAGS_UPDATED)) ||
+	    mtype == UFS_MOUNT_UFSTYPE_UFS2) {
+		/*we have statistic in different place, then usual*/
+		usb2->fs_un.fs_u2.cs_ndir =
+			cpu_to_fs64(sb, uspi->cs_total.cs_ndir);
+		usb2->fs_un.fs_u2.cs_nbfree =
+			cpu_to_fs64(sb, uspi->cs_total.cs_nbfree);
+		usb3->fs_un1.fs_u2.cs_nifree =
+			cpu_to_fs64(sb, uspi->cs_total.cs_nifree);
+		usb3->fs_un1.fs_u2.cs_nffree =
+			cpu_to_fs64(sb, uspi->cs_total.cs_nffree);
+	} else {
+		usb1->fs_cstotal.cs_ndir =
+			cpu_to_fs32(sb, uspi->cs_total.cs_ndir);
+		usb1->fs_cstotal.cs_nbfree =
+			cpu_to_fs32(sb, uspi->cs_total.cs_nbfree);
+		usb1->fs_cstotal.cs_nifree =
+			cpu_to_fs32(sb, uspi->cs_total.cs_nifree);
+		usb1->fs_cstotal.cs_nffree =
+			cpu_to_fs32(sb, uspi->cs_total.cs_nffree);
+	}
+	ubh_mark_buffer_dirty(USPI_UBH(uspi));
+	UFSD("EXIT\n");
+}
+
+/**
+ * ufs_put_super_internal() - put on-disk intrenal structures
+ * @sb: pointer to super_block structure
+ * Put on-disk structures associated with cylinder groups
+ * and write them back to disk, also update cs_total on disk
+ */
+static void ufs_put_super_internal(struct super_block *sb)
+{
+	struct ufs_sb_info *sbi = UFS_SB(sb);
+	struct ufs_sb_private_info *uspi = sbi->s_uspi;
 	struct ufs_buffer_head * ubh;
 	unsigned char * base, * space;
 	unsigned blks, size, i;
-	
-	UFSD(("ENTER\n"))
-	
-	uspi = sbi->s_uspi;
 
+	
+	UFSD("ENTER\n");
+	ufs_put_cstotal(sb);
 	size = uspi->s_cssize;
 	blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
 	base = space = (char*) sbi->s_csp;
@@ -523,7 +590,7 @@
 		brelse (sbi->s_ucg[i]);
 	kfree (sbi->s_ucg);
 	kfree (base);
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 }
 
 static int ufs_fill_super(struct super_block *sb, void *data, int silent)
@@ -533,7 +600,6 @@
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_second * usb2;
 	struct ufs_super_block_third * usb3;
-	struct ufs_super_block *usb;
 	struct ufs_buffer_head * ubh;	
 	struct inode *inode;
 	unsigned block_size, super_block_size;
@@ -544,7 +610,7 @@
 	ubh = NULL;
 	flags = 0;
 	
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 		
 	sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
 	if (!sbi)
@@ -552,7 +618,7 @@
 	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct ufs_sb_info));
 
-	UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY)))
+	UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
 	
 #ifndef CONFIG_UFS_FS_WRITE
 	if (!(sb->s_flags & MS_RDONLY)) {
@@ -593,7 +659,7 @@
 	   the rules */
 	switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
 	case UFS_MOUNT_UFSTYPE_44BSD:
-		UFSD(("ufstype=44bsd\n"))
+		UFSD("ufstype=44bsd\n");
 		uspi->s_fsize = block_size = 512;
 		uspi->s_fmask = ~(512 - 1);
 		uspi->s_fshift = 9;
@@ -602,7 +668,7 @@
 		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
 		break;
 	case UFS_MOUNT_UFSTYPE_UFS2:
-		UFSD(("ufstype=ufs2\n"));
+		UFSD("ufstype=ufs2\n");
 		super_block_offset=SBLOCK_UFS2;
 		uspi->s_fsize = block_size = 512;
 		uspi->s_fmask = ~(512 - 1);
@@ -617,7 +683,7 @@
 		break;
 		
 	case UFS_MOUNT_UFSTYPE_SUN:
-		UFSD(("ufstype=sun\n"))
+		UFSD("ufstype=sun\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
 		uspi->s_fshift = 10;
@@ -628,7 +694,7 @@
 		break;
 
 	case UFS_MOUNT_UFSTYPE_SUNx86:
-		UFSD(("ufstype=sunx86\n"))
+		UFSD("ufstype=sunx86\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
 		uspi->s_fshift = 10;
@@ -639,7 +705,7 @@
 		break;
 
 	case UFS_MOUNT_UFSTYPE_OLD:
-		UFSD(("ufstype=old\n"))
+		UFSD("ufstype=old\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
 		uspi->s_fshift = 10;
@@ -654,7 +720,7 @@
 		break;
 	
 	case UFS_MOUNT_UFSTYPE_NEXTSTEP:
-		UFSD(("ufstype=nextstep\n"))
+		UFSD("ufstype=nextstep\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
 		uspi->s_fshift = 10;
@@ -669,7 +735,7 @@
 		break;
 	
 	case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
-		UFSD(("ufstype=nextstep-cd\n"))
+		UFSD("ufstype=nextstep-cd\n");
 		uspi->s_fsize = block_size = 2048;
 		uspi->s_fmask = ~(2048 - 1);
 		uspi->s_fshift = 11;
@@ -684,7 +750,7 @@
 		break;
 	
 	case UFS_MOUNT_UFSTYPE_OPENSTEP:
-		UFSD(("ufstype=openstep\n"))
+		UFSD("ufstype=openstep\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
 		uspi->s_fshift = 10;
@@ -699,7 +765,7 @@
 		break;
 	
 	case UFS_MOUNT_UFSTYPE_HP:
-		UFSD(("ufstype=hp\n"))
+		UFSD("ufstype=hp\n");
 		uspi->s_fsize = block_size = 1024;
 		uspi->s_fmask = ~(1024 - 1);
 		uspi->s_fshift = 10;
@@ -737,8 +803,6 @@
 	usb1 = ubh_get_usb_first(uspi);
 	usb2 = ubh_get_usb_second(uspi);
 	usb3 = ubh_get_usb_third(uspi);
-	usb  = (struct ufs_super_block *)
-		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
 	/*
 	 * Check ufs magic number
@@ -820,16 +884,12 @@
 		ubh = NULL;
 		block_size = uspi->s_fsize;
 		super_block_size = uspi->s_sbsize;
-		UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size))
+		UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size);
 		goto again;
 	}
 
-#ifdef UFS_SUPER_DEBUG_MORE
-        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
-		ufs2_print_super_stuff(sb,usb);
-        else
-		ufs_print_super_stuff(sb, usb1, usb2, usb3);
-#endif
+
+	ufs_print_super_stuff(sb, flags, usb1, usb2, usb3);
 
 	/*
 	 * Check, if file system was correctly unmounted.
@@ -842,13 +902,13 @@
 	  (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) {
 		switch(usb1->fs_clean) {
 		case UFS_FSCLEAN:
-			UFSD(("fs is clean\n"))
+			UFSD("fs is clean\n");
 			break;
 		case UFS_FSSTABLE:
-			UFSD(("fs is stable\n"))
+			UFSD("fs is stable\n");
 			break;
 		case UFS_FSOSF1:
-			UFSD(("fs is DEC OSF/1\n"))
+			UFSD("fs is DEC OSF/1\n");
 			break;
 		case UFS_FSACTIVE:
 			printk("ufs_read_super: fs is active\n");
@@ -863,8 +923,7 @@
 			sb->s_flags |= MS_RDONLY;
 			break;
 		}
-	}
-	else {
+	} else {
 		printk("ufs_read_super: fs needs fsck\n");
 		sb->s_flags |= MS_RDONLY;
 	}
@@ -884,10 +943,9 @@
 	uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask);
 
 	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
-		uspi->s_u2_size  = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size);
-		uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
-	}
-	else {
+		uspi->s_u2_size  = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size);
+		uspi->s_u2_dsize = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize);
+	} else {
 		uspi->s_size  =  fs32_to_cpu(sb, usb1->fs_size);
 		uspi->s_dsize =  fs32_to_cpu(sb, usb1->fs_dsize);
 	}
@@ -901,8 +959,8 @@
 	uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
 	uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift);
 	uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
-	UFSD(("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
-		uspi->s_fshift));
+	UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift,
+		uspi->s_fshift);
 	uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift);
 	uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb);
 	/* s_sbsize already set */
@@ -922,8 +980,8 @@
 	uspi->s_spc = fs32_to_cpu(sb, usb1->fs_spc);
 	uspi->s_ipg = fs32_to_cpu(sb, usb1->fs_ipg);
 	uspi->s_fpg = fs32_to_cpu(sb, usb1->fs_fpg);
-	uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_cpc);
-	uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize);
+	uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_un.fs_u1.fs_cpc);
+	uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize);
 	uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3);
 	uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3);
 	uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat);
@@ -935,12 +993,11 @@
 	 * Compute another frequently used values
 	 */
 	uspi->s_fpbmask = uspi->s_fpb - 1;
-	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
 		uspi->s_apbshift = uspi->s_bshift - 3;
-	}
-	else {
+	else
 		uspi->s_apbshift = uspi->s_bshift - 2;
-	}
+
 	uspi->s_2apbshift = uspi->s_apbshift * 2;
 	uspi->s_3apbshift = uspi->s_apbshift * 3;
 	uspi->s_apb = 1 << uspi->s_apbshift;
@@ -956,7 +1013,7 @@
 	if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) ==
 	    UFS_MOUNT_UFSTYPE_44BSD)
 		uspi->s_maxsymlinklen =
-		    fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen);
+		    fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen);
 	
 	sbi->s_flags = flags;
 
@@ -967,7 +1024,7 @@
 	if (!sb->s_root)
 		goto dalloc_failed;
 
-
+	ufs_setup_cstotal(sb);
 	/*
 	 * Read cylinder group structures
 	 */
@@ -975,7 +1032,7 @@
 		if (!ufs_read_cylinder_structures(sb))
 			goto failed;
 
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return 0;
 
 dalloc_failed:
@@ -986,15 +1043,16 @@
 	kfree (uspi);
 	kfree(sbi);
 	sb->s_fs_info = NULL;
-	UFSD(("EXIT (FAILED)\n"))
+	UFSD("EXIT (FAILED)\n");
 	return -EINVAL;
 
 failed_nomem:
-	UFSD(("EXIT (NOMEM)\n"))
+	UFSD("EXIT (NOMEM)\n");
 	return -ENOMEM;
 }
 
-static void ufs_write_super (struct super_block *sb) {
+static void ufs_write_super(struct super_block *sb)
+{
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_third * usb3;
@@ -1002,7 +1060,7 @@
 
 	lock_kernel();
 
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 	flags = UFS_SB(sb)->s_flags;
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first(uspi);
@@ -1014,26 +1072,27 @@
 		  || (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
 			ufs_set_fs_state(sb, usb1, usb3,
 					UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
-		ubh_mark_buffer_dirty (USPI_UBH);
+		ufs_put_cstotal(sb);
 	}
 	sb->s_dirt = 0;
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	unlock_kernel();
 }
 
-static void ufs_put_super (struct super_block *sb)
+static void ufs_put_super(struct super_block *sb)
 {
 	struct ufs_sb_info * sbi = UFS_SB(sb);
 		
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 
 	if (!(sb->s_flags & MS_RDONLY))
-		ufs_put_cylinder_structures (sb);
+		ufs_put_super_internal(sb);
 	
 	ubh_brelse_uspi (sbi->s_uspi);
 	kfree (sbi->s_uspi);
 	kfree (sbi);
 	sb->s_fs_info = NULL;
+	UFSD("EXIT\n");
 	return;
 }
 
@@ -1062,8 +1121,7 @@
 		return -EINVAL;
 	if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) {
 		new_mount_opt |= ufstype;
-	}
-	else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
+	} else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
 		printk("ufstype can't be changed during remount\n");
 		return -EINVAL;
 	}
@@ -1077,20 +1135,19 @@
 	 * fs was mouted as rw, remounting ro
 	 */
 	if (*mount_flags & MS_RDONLY) {
-		ufs_put_cylinder_structures(sb);
+		ufs_put_super_internal(sb);
 		usb1->fs_time = cpu_to_fs32(sb, get_seconds());
 		if ((flags & UFS_ST_MASK) == UFS_ST_SUN
 		  || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) 
 			ufs_set_fs_state(sb, usb1, usb3,
 				UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
-		ubh_mark_buffer_dirty (USPI_UBH);
+		ubh_mark_buffer_dirty (USPI_UBH(uspi));
 		sb->s_dirt = 0;
 		sb->s_flags |= MS_RDONLY;
-	}
+	} else {
 	/*
 	 * fs was mounted as ro, remounting rw
 	 */
-	else {
 #ifndef CONFIG_UFS_FS_WRITE
 		printk("ufs was compiled with read-only support, "
 		"can't be mounted as read-write\n");
@@ -1102,7 +1159,7 @@
 			printk("this ufstype is read-only supported\n");
 			return -EINVAL;
 		}
-		if (!ufs_read_cylinder_structures (sb)) {
+		if (!ufs_read_cylinder_structures(sb)) {
 			printk("failed during remounting\n");
 			return -EPERM;
 		}
@@ -1113,37 +1170,31 @@
 	return 0;
 }
 
-static int ufs_statfs (struct dentry *dentry, struct kstatfs *buf)
+static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	struct super_block *sb = dentry->d_sb;
-	struct ufs_sb_private_info * uspi;
-	struct ufs_super_block_first * usb1;
-	struct ufs_super_block * usb;
-	unsigned  flags = 0;
+	struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi;
+	unsigned  flags = UFS_SB(sb)->s_flags;
+	struct ufs_super_block_first *usb1;
+	struct ufs_super_block_second *usb2;
+	struct ufs_super_block_third *usb3;
 
 	lock_kernel();
 
-	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first (uspi);
-	usb  = (struct ufs_super_block *)
-		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
+	usb1 = ubh_get_usb_first(uspi);
+	usb2 = ubh_get_usb_second(uspi);
+	usb3 = ubh_get_usb_third(uspi);
 	
-	flags = UFS_SB(sb)->s_flags;
 	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
 		buf->f_type = UFS2_MAGIC;
-		buf->f_blocks = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
-		buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) +
-			fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree);
-		buf->f_ffree = fs64_to_cpu(sb,
-        		usb->fs_u11.fs_u2.fs_cstotal.cs_nifree);
-	}
-	else {
+		buf->f_blocks = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize);
+	} else {
 		buf->f_type = UFS_MAGIC;
 		buf->f_blocks = uspi->s_dsize;
-		buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
-			fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
-		buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
 	}
+	buf->f_bfree = ufs_blkstofrags(uspi->cs_total.cs_nbfree) +
+		uspi->cs_total.cs_nffree;
+	buf->f_ffree = uspi->cs_total.cs_nifree;
 	buf->f_bsize = sb->s_blocksize;
 	buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree))
 		? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 02e8629..3c3b301 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -49,14 +49,6 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_TRUNCATE_DEBUG
-
-#ifdef UFS_TRUNCATE_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
- 
 /*
  * Secure deletion currently doesn't work. It interacts very badly
  * with buffers shared with memory mappings, and for that reason
@@ -82,7 +74,7 @@
 	unsigned i, tmp;
 	int retry;
 	
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -105,7 +97,7 @@
 		block2 = ufs_fragstoblks (frag3);
 	}
 
-	UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4))
+	UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4);
 
 	if (frag1 >= frag2)
 		goto next1;		
@@ -120,9 +112,8 @@
 	frag1 = ufs_fragnum (frag1);
 	frag2 = ufs_fragnum (frag2);
 
-	inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
-	mark_inode_dirty(inode);
 	ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
+	mark_inode_dirty(inode);
 	frag_to_free = tmp + frag1;
 
 next1:
@@ -136,8 +127,7 @@
 			continue;
 
 		*p = 0;
-		inode->i_blocks -= uspi->s_nspb;
-		mark_inode_dirty(inode);
+
 		if (free_count == 0) {
 			frag_to_free = tmp;
 			free_count = uspi->s_fpb;
@@ -148,6 +138,7 @@
 			frag_to_free = tmp;
 			free_count = uspi->s_fpb;
 		}
+		mark_inode_dirty(inode);
 	}
 	
 	if (free_count > 0)
@@ -166,12 +157,12 @@
 	frag4 = ufs_fragnum (frag4);
 
 	*p = 0;
-	inode->i_blocks -= frag4 << uspi->s_nspfshift;
-	mark_inode_dirty(inode);
+
 	ufs_free_fragments (inode, tmp, frag4);
+	mark_inode_dirty(inode);
  next3:
 
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return retry;
 }
 
@@ -186,7 +177,7 @@
 	unsigned frag_to_free, free_count;
 	int retry;
 
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 		
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -227,7 +218,7 @@
 			frag_to_free = tmp;
 			free_count = uspi->s_fpb;
 		}
-		inode->i_blocks -= uspi->s_nspb;
+
 		mark_inode_dirty(inode);
 	}
 
@@ -238,26 +229,21 @@
 		if (*ubh_get_addr32(ind_ubh,i))
 			break;
 	if (i >= uspi->s_apb) {
-		if (ubh_max_bcount(ind_ubh) != 1) {
-			retry = 1;
-		}
-		else {
-			tmp = fs32_to_cpu(sb, *p);
-			*p = 0;
-			inode->i_blocks -= uspi->s_nspb;
-			mark_inode_dirty(inode);
-			ufs_free_blocks (inode, tmp, uspi->s_fpb);
-			ubh_bforget(ind_ubh);
-			ind_ubh = NULL;
-		}
+		tmp = fs32_to_cpu(sb, *p);
+		*p = 0;
+
+		ufs_free_blocks (inode, tmp, uspi->s_fpb);
+		mark_inode_dirty(inode);
+		ubh_bforget(ind_ubh);
+		ind_ubh = NULL;
 	}
 	if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
-		ubh_ll_rw_block (SWRITE, 1, &ind_ubh);
+		ubh_ll_rw_block(SWRITE, ind_ubh);
 		ubh_wait_on_buffer (ind_ubh);
 	}
 	ubh_brelse (ind_ubh);
 	
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	
 	return retry;
 }
@@ -271,7 +257,7 @@
 	__fs32 * dind;
 	int retry = 0;
 	
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -306,25 +292,21 @@
 		if (*ubh_get_addr32 (dind_bh, i))
 			break;
 	if (i >= uspi->s_apb) {
-		if (ubh_max_bcount(dind_bh) != 1)
-			retry = 1;
-		else {
-			tmp = fs32_to_cpu(sb, *p);
-			*p = 0;
-			inode->i_blocks -= uspi->s_nspb;
-			mark_inode_dirty(inode);
-			ufs_free_blocks (inode, tmp, uspi->s_fpb);
-			ubh_bforget(dind_bh);
-			dind_bh = NULL;
-		}
+		tmp = fs32_to_cpu(sb, *p);
+		*p = 0;
+
+		ufs_free_blocks(inode, tmp, uspi->s_fpb);
+		mark_inode_dirty(inode);
+		ubh_bforget(dind_bh);
+		dind_bh = NULL;
 	}
 	if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
-		ubh_ll_rw_block (SWRITE, 1, &dind_bh);
+		ubh_ll_rw_block(SWRITE, dind_bh);
 		ubh_wait_on_buffer (dind_bh);
 	}
 	ubh_brelse (dind_bh);
 	
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	
 	return retry;
 }
@@ -339,7 +321,7 @@
 	__fs32 * tind, * p;
 	int retry;
 	
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
@@ -370,25 +352,21 @@
 		if (*ubh_get_addr32 (tind_bh, i))
 			break;
 	if (i >= uspi->s_apb) {
-		if (ubh_max_bcount(tind_bh) != 1)
-			retry = 1;
-		else {
-			tmp = fs32_to_cpu(sb, *p);
-			*p = 0;
-			inode->i_blocks -= uspi->s_nspb;
-			mark_inode_dirty(inode);
-			ufs_free_blocks (inode, tmp, uspi->s_fpb);
-			ubh_bforget(tind_bh);
-			tind_bh = NULL;
-		}
+		tmp = fs32_to_cpu(sb, *p);
+		*p = 0;
+
+		ufs_free_blocks(inode, tmp, uspi->s_fpb);
+		mark_inode_dirty(inode);
+		ubh_bforget(tind_bh);
+		tind_bh = NULL;
 	}
 	if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
-		ubh_ll_rw_block (SWRITE, 1, &tind_bh);
+		ubh_ll_rw_block(SWRITE, tind_bh);
 		ubh_wait_on_buffer (tind_bh);
 	}
 	ubh_brelse (tind_bh);
 	
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 	return retry;
 }
 		
@@ -399,7 +377,7 @@
 	struct ufs_sb_private_info * uspi;
 	int retry;
 	
-	UFSD(("ENTER\n"))
+	UFSD("ENTER\n");
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
 
@@ -430,5 +408,5 @@
 	ufsi->i_lastfrag = DIRECT_FRAGMENT;
 	unlock_kernel();
 	mark_inode_dirty(inode);
-	UFSD(("EXIT\n"))
+	UFSD("EXIT\n");
 }
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 59acc8f..a2f13f4 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -14,15 +14,6 @@
 #include "swab.h"
 #include "util.h"
 
-#undef UFS_UTILS_DEBUG
-
-#ifdef UFS_UTILS_DEBUG
-#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
-#else
-#define UFSD(x)
-#endif
-
-
 struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
 	struct super_block *sb, u64 fragment, u64 size)
 {
@@ -63,17 +54,17 @@
 	count = size >> uspi->s_fshift;
 	if (count <= 0 || count > UFS_MAXFRAG)
 		return NULL;
-	USPI_UBH->fragment = fragment;
-	USPI_UBH->count = count;
+	USPI_UBH(uspi)->fragment = fragment;
+	USPI_UBH(uspi)->count = count;
 	for (i = 0; i < count; i++)
-		if (!(USPI_UBH->bh[i] = sb_bread(sb, fragment + i)))
+		if (!(USPI_UBH(uspi)->bh[i] = sb_bread(sb, fragment + i)))
 			goto failed;
 	for (; i < UFS_MAXFRAG; i++)
-		USPI_UBH->bh[i] = NULL;
-	return USPI_UBH;
+		USPI_UBH(uspi)->bh[i] = NULL;
+	return USPI_UBH(uspi);
 failed:
 	for (j = 0; j < i; j++)
-		brelse (USPI_UBH->bh[j]);
+		brelse (USPI_UBH(uspi)->bh[j]);
 	return NULL;
 }
 
@@ -90,11 +81,11 @@
 void ubh_brelse_uspi (struct ufs_sb_private_info * uspi)
 {
 	unsigned i;
-	if (!USPI_UBH)
+	if (!USPI_UBH(uspi))
 		return;
-	for ( i = 0; i < USPI_UBH->count; i++ ) {
-		brelse (USPI_UBH->bh[i]);
-		USPI_UBH->bh[i] = NULL;
+	for ( i = 0; i < USPI_UBH(uspi)->count; i++ ) {
+		brelse (USPI_UBH(uspi)->bh[i]);
+		USPI_UBH(uspi)->bh[i] = NULL;
 	}
 }
 
@@ -121,13 +112,12 @@
 	}
 }
 
-void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[])
+void ubh_ll_rw_block(int rw, struct ufs_buffer_head *ubh)
 {
-	unsigned i;
 	if (!ubh)
 		return;
-	for ( i = 0; i < nr; i++ )
-		ll_rw_block (rw, ubh[i]->count, ubh[i]->bh);
+
+	ll_rw_block(rw, ubh->count, ubh->bh);
 }
 
 void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
@@ -139,18 +129,6 @@
 		wait_on_buffer (ubh->bh[i]);
 }
 
-unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
-{
-	unsigned i;
-	unsigned max = 0;
-	if (!ubh)
-		return 0;
-	for ( i = 0; i < ubh->count; i++ ) 
-		if ( atomic_read(&ubh->bh[i]->b_count) > max )
-			max = atomic_read(&ubh->bh[i]->b_count);
-	return max;
-}
-
 void ubh_bforget (struct ufs_buffer_head * ubh)
 {
 	unsigned i;
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 48d6d9b..406981f 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -17,10 +17,16 @@
 #define in_range(b,first,len)	((b)>=(first)&&(b)<(first)+(len))
 
 /*
- * macros used for retyping
+ * functions used for retyping
  */
-#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
-#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+static inline struct ufs_buffer_head *UCPI_UBH(struct ufs_cg_private_info *cpi)
+{
+	return &cpi->c_ubh;
+}
+static inline struct ufs_buffer_head *USPI_UBH(struct ufs_sb_private_info *spi)
+{
+	return &spi->s_ubh;
+}
 
 
 
@@ -33,12 +39,12 @@
 {
 	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
-		return fs32_to_cpu(sb, usb3->fs_u2.fs_sun.fs_state);
+		return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state);
 	case UFS_ST_SUNx86:
 		return fs32_to_cpu(sb, usb1->fs_u1.fs_sunx86.fs_state);
 	case UFS_ST_44BSD:
 	default:
-		return fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_state);
+		return fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_state);
 	}
 }
 
@@ -48,13 +54,13 @@
 {
 	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
-		usb3->fs_u2.fs_sun.fs_state = cpu_to_fs32(sb, value);
+		usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value);
 		break;
 	case UFS_ST_SUNx86:
 		usb1->fs_u1.fs_sunx86.fs_state = cpu_to_fs32(sb, value);
 		break;
 	case UFS_ST_44BSD:
-		usb3->fs_u2.fs_44.fs_state = cpu_to_fs32(sb, value);
+		usb3->fs_un2.fs_44.fs_state = cpu_to_fs32(sb, value);
 		break;
 	}
 }
@@ -64,7 +70,7 @@
 		  struct ufs_super_block_third *usb3)
 {
 	if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
-		return fs32_to_cpu(sb, usb3->fs_u2.fs_sunx86.fs_npsect);
+		return fs32_to_cpu(sb, usb3->fs_un2.fs_sunx86.fs_npsect);
 	else
 		return fs32_to_cpu(sb, usb1->fs_u1.fs_sun.fs_npsect);
 }
@@ -76,16 +82,16 @@
 
 	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
-		((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qbmask[0];
-		((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qbmask[1];
+		((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qbmask[0];
+		((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qbmask[1];
 		break;
 	case UFS_ST_SUNx86:
-		((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qbmask[0];
-		((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qbmask[1];
+		((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qbmask[0];
+		((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qbmask[1];
 		break;
 	case UFS_ST_44BSD:
-		((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qbmask[0];
-		((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qbmask[1];
+		((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qbmask[0];
+		((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qbmask[1];
 		break;
 	}
 
@@ -99,16 +105,16 @@
 
 	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
 	case UFS_ST_SUN:
-		((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qfmask[0];
-		((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qfmask[1];
+		((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qfmask[0];
+		((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qfmask[1];
 		break;
 	case UFS_ST_SUNx86:
-		((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qfmask[0];
-		((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qfmask[1];
+		((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qfmask[0];
+		((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qfmask[1];
 		break;
 	case UFS_ST_44BSD:
-		((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qfmask[0];
-		((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qfmask[1];
+		((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qfmask[0];
+		((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qfmask[1];
 		break;
 	}
 
@@ -236,9 +242,8 @@
 extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
 extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
 extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
-extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
+extern void ubh_ll_rw_block(int, struct ufs_buffer_head *);
 extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
-extern unsigned ubh_max_bcount (struct ufs_buffer_head *);
 extern void ubh_bforget (struct ufs_buffer_head *);
 extern int  ubh_buffer_dirty (struct ufs_buffer_head *);
 #define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)
@@ -297,40 +302,26 @@
 #define ubh_blkmap(ubh,begin,bit) \
 	((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb)))
 
-
-/*
- * Macros for access to superblock array structures
- */
-#define ubh_postbl(ubh,cylno,i) \
-	((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
-	? (*(__s16*)(ubh_get_addr(ubh, \
-	(unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \
-	+ (((cylno) * 16 + (i)) << 1) ) )) \
-	: (*(__s16*)(ubh_get_addr(ubh, \
-	uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) ))))
-
-#define ubh_rotbl(ubh,i) \
-	((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
-	? (*(__u8*)(ubh_get_addr(ubh, \
-	(unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \
-	: (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i)))))
-
 /*
  * Determine the number of available frags given a
  * percentage to hold in reserve.
  */
-#define ufs_freespace(usb, percentreserved) \
-	(ufs_blkstofrags(fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nbfree)) + \
-	fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100))
+static inline u64
+ufs_freespace(struct ufs_sb_private_info *uspi, int percentreserved)
+{
+	return ufs_blkstofrags(uspi->cs_total.cs_nbfree) +
+		uspi->cs_total.cs_nffree -
+		(uspi->s_dsize * (percentreserved) / 100);
+}
 
 /*
  * Macros to access cylinder group array structures
  */
 #define ubh_cg_blktot(ucpi,cylno) \
-	(*((__fs32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2))))
+	(*((__fs32*)ubh_get_addr(UCPI_UBH(ucpi), (ucpi)->c_btotoff + ((cylno) << 2))))
 
 #define ubh_cg_blks(ucpi,cylno,rpos) \
-	(*((__fs16*)ubh_get_addr(UCPI_UBH, \
+	(*((__fs16*)ubh_get_addr(UCPI_UBH(ucpi), \
 	(ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 ))))
 
 /*
@@ -508,29 +499,3 @@
 	if (fragsize > 0 && fragsize < uspi->s_fpb)
 		fs32_add(sb, &fraglist[fragsize], cnt);
 }
-
-#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
-static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, 
-	unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
-{
-	unsigned rest, offset;
-	unsigned char * cp;
-	
-
-	offset = begin & ~uspi->s_fmask;
-	begin >>= uspi->s_fshift;
-	for (;;) {
-		if ((offset + size) < uspi->s_fsize)
-			rest = size;
-		else
-			rest = uspi->s_fsize - offset;
-		size -= rest;
-		cp = ubh->bh[begin]->b_data + offset;
-		while ((table[*cp++] & mask) == 0 && --rest);
-		if (rest || !size)
-			break;
-		begin++;
-		offset = 0;
-	}
-	return (size + rest);
-}
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 7066237..3d4f6df 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -299,7 +299,8 @@
 
 STATIC int
 xfs_file_close(
-	struct file	*filp)
+	struct file	*filp,
+	fl_owner_t	id)
 {
 	return -bhv_vop_close(vn_from_inode(filp->f_dentry->d_inode), 0,
 				file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL);
diff --git a/include/asm-alpha/floppy.h b/include/asm-alpha/floppy.h
index e177d41..21816d3 100644
--- a/include/asm-alpha/floppy.h
+++ b/include/asm-alpha/floppy.h
@@ -25,9 +25,8 @@
 #define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
 #define fd_cacheflush(addr,size) /* nothing */
-#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
-					    SA_INTERRUPT|SA_SAMPLE_RANDOM, \
-				            "floppy", NULL)
+#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt,\
+					    SA_INTERRUPT, "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
 #ifdef CONFIG_PCI
diff --git a/include/asm-arm/floppy.h b/include/asm-arm/floppy.h
index 6ea657c..aa0c8d2 100644
--- a/include/asm-arm/floppy.h
+++ b/include/asm-arm/floppy.h
@@ -25,7 +25,7 @@
 
 #define fd_inb(port)		inb((port))
 #define fd_request_irq()	request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
-					SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
+					    SA_INTERRUPT,"floppy",NULL)
 #define fd_free_irq()		free_irq(IRQ_FLOPPYDISK,NULL)
 #define fd_disable_irq()	disable_irq(IRQ_FLOPPYDISK)
 #define fd_enable_irq()		enable_irq(IRQ_FLOPPYDISK)
diff --git a/include/asm-arm/hardware/locomo.h b/include/asm-arm/hardware/locomo.h
index 5f10048..22dfb17 100644
--- a/include/asm-arm/hardware/locomo.h
+++ b/include/asm-arm/hardware/locomo.h
@@ -111,6 +111,8 @@
 #define LOCOMO_ALS		0x00	/* Adjust light cycle */
 #define LOCOMO_ALD		0x04	/* Adjust light duty */
 
+#define LOCOMO_ALC_EN		0x8000
+
 /* Backlight controller: TFT signal */
 #define LOCOMO_BACKLIGHT	0x38
 #define LOCOMO_TC		0x00		/* TFT control signal */
@@ -203,4 +205,7 @@
 /* M62332 control function */
 void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel);
 
+/* Frontlight control */
+void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf);
+
 #endif
diff --git a/include/asm-arm26/floppy.h b/include/asm-arm26/floppy.h
index 9e090ad..a18af06 100644
--- a/include/asm-arm26/floppy.h
+++ b/include/asm-arm26/floppy.h
@@ -22,7 +22,7 @@
 
 #define fd_inb(port)		inb((port))
 #define fd_request_irq()	request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
-					SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
+					SA_INTERRUPT,"floppy",NULL)
 #define fd_free_irq()		free_irq(IRQ_FLOPPYDISK,NULL)
 #define fd_disable_irq()	disable_irq(IRQ_FLOPPYDISK)
 #define fd_enable_irq()		enable_irq(IRQ_FLOPPYDISK)
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 0cd9711..845cb67 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -38,4 +38,17 @@
 #endif
 #endif
 
+#define WARN_ON_ONCE(condition)				\
+({							\
+	static int __warn_once = 1;			\
+	int __ret = 0;					\
+							\
+	if (unlikely((condition) && __warn_once)) {	\
+		__warn_once = 0;			\
+		WARN_ON(1);				\
+		__ret = 1;				\
+	}						\
+	__ret;						\
+})
+
 #endif
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index c0caf43..c745211 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -14,6 +14,7 @@
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
 #define __get_cpu_var(var) per_cpu(var, smp_processor_id())
+#define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id())
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)			\
@@ -30,6 +31,7 @@
 
 #define per_cpu(var, cpu)			(*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)			per_cpu__##var
+#define __raw_get_cpu_var(var)			per_cpu__##var
 
 #endif	/* SMP */
 
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index d79e9ee..c61bd1a 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -5,6 +5,8 @@
 
 #include <asm/types.h>
 
+#include <linux/types.h>
+
 struct alt_instr {
 	u8 *instr; 		/* original instruction */
 	u8 *replacement;
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index 1d8362c..2c1e371 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -111,24 +111,12 @@
 extern void smp_local_timer_interrupt (struct pt_regs * regs);
 extern void setup_boot_APIC_clock (void);
 extern void setup_secondary_APIC_clock (void);
-extern void setup_apic_nmi_watchdog (void);
-extern int reserve_lapic_nmi(void);
-extern void release_lapic_nmi(void);
-extern void disable_timer_nmi_watchdog(void);
-extern void enable_timer_nmi_watchdog(void);
-extern void nmi_watchdog_tick (struct pt_regs * regs);
 extern int APIC_init_uniprocessor (void);
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
 
 extern void enable_NMI_through_LVT0 (void * dummy);
 
-extern unsigned int nmi_watchdog;
-#define NMI_NONE	0
-#define NMI_IO_APIC	1
-#define NMI_LOCAL_APIC	2
-#define NMI_INVALID	3
-
 extern int disable_timer_pin_1;
 
 void smp_send_timer_broadcast_ipi(struct pt_regs *regs);
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index 3ecedba..d314ebb 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -72,6 +72,7 @@
 #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
 #define X86_FEATURE_UP		(3*32+ 9) /* smp kernel running on up */
 #define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */
+#define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
diff --git a/include/asm-i386/delay.h b/include/asm-i386/delay.h
index 456db85..b1c7650 100644
--- a/include/asm-i386/delay.h
+++ b/include/asm-i386/delay.h
@@ -23,4 +23,6 @@
 	((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
 	__ndelay(n))
 
+void use_tsc_delay(void);
+
 #endif /* defined(_I386_DELAY_H) */
diff --git a/include/asm-i386/dwarf2.h b/include/asm-i386/dwarf2.h
new file mode 100644
index 0000000..2280f62
--- /dev/null
+++ b/include/asm-i386/dwarf2.h
@@ -0,0 +1,54 @@
+#ifndef _DWARF2_H
+#define _DWARF2_H
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+#warning "asm/dwarf2.h should be only included in pure assembly files"
+#endif
+
+/*
+   Macros for dwarf2 CFI unwind table entries.
+   See "as.info" for details on these pseudo ops. Unfortunately
+   they are only supported in very new binutils, so define them
+   away for older version.
+ */
+
+#ifdef CONFIG_UNWIND_INFO
+
+#define CFI_STARTPROC .cfi_startproc
+#define CFI_ENDPROC .cfi_endproc
+#define CFI_DEF_CFA .cfi_def_cfa
+#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
+#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
+#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
+#define CFI_OFFSET .cfi_offset
+#define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_REGISTER .cfi_register
+#define CFI_RESTORE .cfi_restore
+#define CFI_REMEMBER_STATE .cfi_remember_state
+#define CFI_RESTORE_STATE .cfi_restore_state
+
+#else
+
+/* Due to the structure of pre-exisiting code, don't use assembler line
+   comment character # to ignore the arguments. Instead, use a dummy macro. */
+.macro ignore a=0, b=0, c=0, d=0
+.endm
+
+#define CFI_STARTPROC	ignore
+#define CFI_ENDPROC	ignore
+#define CFI_DEF_CFA	ignore
+#define CFI_DEF_CFA_REGISTER	ignore
+#define CFI_DEF_CFA_OFFSET	ignore
+#define CFI_ADJUST_CFA_OFFSET	ignore
+#define CFI_OFFSET	ignore
+#define CFI_REL_OFFSET	ignore
+#define CFI_REGISTER	ignore
+#define CFI_RESTORE	ignore
+#define CFI_REMEMBER_STATE ignore
+#define CFI_RESTORE_STATE ignore
+
+#endif
+
+#endif
diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h
index 0340304..9cb2793 100644
--- a/include/asm-i386/floppy.h
+++ b/include/asm-i386/floppy.h
@@ -147,9 +147,8 @@
 		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
 						   "floppy", NULL);
 	else
-		return request_irq(FLOPPY_IRQ, floppy_interrupt,
-						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
-						   "floppy", NULL);	
+		return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+				   "floppy", NULL);
 
 }
 
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index 95d3fd0..a4c0a5a 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -19,6 +19,8 @@
 
 struct hw_interrupt_type;
 
+#define NMI_VECTOR		0x02
+
 /*
  * Various low-level irq details needed by irq.c, process.c,
  * time.c, io_apic.c and smp.c
diff --git a/include/asm-i386/intel_arch_perfmon.h b/include/asm-i386/intel_arch_perfmon.h
new file mode 100644
index 0000000..134ea9c
--- /dev/null
+++ b/include/asm-i386/intel_arch_perfmon.h
@@ -0,0 +1,19 @@
+#ifndef X86_INTEL_ARCH_PERFMON_H
+#define X86_INTEL_ARCH_PERFMON_H 1
+
+#define MSR_ARCH_PERFMON_PERFCTR0		0xc1
+#define MSR_ARCH_PERFMON_PERFCTR1		0xc2
+
+#define MSR_ARCH_PERFMON_EVENTSEL0		0x186
+#define MSR_ARCH_PERFMON_EVENTSEL1		0x187
+
+#define ARCH_PERFMON_EVENTSEL0_ENABLE      (1 << 22)
+#define ARCH_PERFMON_EVENTSEL_INT          (1 << 20)
+#define ARCH_PERFMON_EVENTSEL_OS           (1 << 17)
+#define ARCH_PERFMON_EVENTSEL_USR          (1 << 16)
+
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL	(0x3c)
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK	(0x00 << 8)
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
+
+#endif	/* X86_INTEL_ARCH_PERFMON_H */
diff --git a/include/asm-i386/k8.h b/include/asm-i386/k8.h
new file mode 100644
index 0000000..dfd88a6
--- /dev/null
+++ b/include/asm-i386/k8.h
@@ -0,0 +1 @@
+#include <asm-x86_64/k8.h>
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
index 96d0828..d18cdb9 100644
--- a/include/asm-i386/kdebug.h
+++ b/include/asm-i386/kdebug.h
@@ -19,6 +19,8 @@
 
 extern int register_die_notifier(struct notifier_block *);
 extern int unregister_die_notifier(struct notifier_block *);
+extern int register_page_fault_notifier(struct notifier_block *);
+extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head i386die_chain;
 
 
diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h
index 57d157c..0730a20 100644
--- a/include/asm-i386/kprobes.h
+++ b/include/asm-i386/kprobes.h
@@ -44,6 +44,7 @@
 
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)pentry
 #define ARCH_SUPPORTS_KRETPROBES
+#define  ARCH_INACTIVE_KPROBE_COUNT 0
 
 void arch_remove_kprobe(struct kprobe *p);
 void kretprobe_trampoline(void);
diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h
index e67fa08..3b4998c 100644
--- a/include/asm-i386/local.h
+++ b/include/asm-i386/local.h
@@ -55,12 +55,26 @@
  * much more efficient than these naive implementations.  Note they take
  * a variable, not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(v)	 	\
+	({ local_t res__;		\
+	   preempt_disable(); 		\
+	   res__ = (v);			\
+	   preempt_enable();		\
+	   res__; })
+#define cpu_local_wrap(v)		\
+	({ preempt_disable();		\
+	   v;				\
+	   preempt_enable(); })		\
+
+#define cpu_local_read(v)    cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
+#define cpu_local_set(v, i)  cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
+#define cpu_local_inc(v)     cpu_local_wrap(local_inc(&__get_cpu_var(v)))
+#define cpu_local_dec(v)     cpu_local_wrap(local_dec(&__get_cpu_var(v)))
+#define cpu_local_add(i, v)  cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
+#define cpu_local_sub(i, v)  cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
 
 #define __cpu_local_inc(v)	cpu_local_inc(v)
 #define __cpu_local_dec(v)	cpu_local_dec(v)
diff --git a/include/asm-i386/mach-default/mach_ipi.h b/include/asm-i386/mach-default/mach_ipi.h
index a1d0072..0dba244 100644
--- a/include/asm-i386/mach-default/mach_ipi.h
+++ b/include/asm-i386/mach-default/mach_ipi.h
@@ -1,6 +1,9 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
+/* Avoid include hell */
+#define NMI_VECTOR 0x02
+
 void send_IPI_mask_bitmask(cpumask_t mask, int vector);
 void __send_IPI_shortcut(unsigned int shortcut, int vector);
 
@@ -13,7 +16,7 @@
 
 static inline void __local_send_IPI_allbutself(int vector)
 {
-	if (no_broadcast) {
+	if (no_broadcast || vector == NMI_VECTOR) {
 		cpumask_t mask = cpu_online_map;
 
 		cpu_clear(smp_processor_id(), mask);
@@ -24,7 +27,7 @@
 
 static inline void __local_send_IPI_all(int vector)
 {
-	if (no_broadcast)
+	if (no_broadcast || vector == NMI_VECTOR)
 		send_IPI_mask(cpu_online_map, vector);
 	else
 		__send_IPI_shortcut(APIC_DEST_ALLINC, vector);
diff --git a/include/asm-i386/mach-default/mach_timer.h b/include/asm-i386/mach-default/mach_timer.h
index 4b9703b..807992f 100644
--- a/include/asm-i386/mach-default/mach_timer.h
+++ b/include/asm-i386/mach-default/mach_timer.h
@@ -15,7 +15,9 @@
 #ifndef _MACH_TIMER_H
 #define _MACH_TIMER_H
 
-#define CALIBRATE_LATCH	(5 * LATCH)
+#define CALIBRATE_TIME_MSEC 30 /* 30 msecs */
+#define CALIBRATE_LATCH	\
+	((CLOCK_TICK_RATE * CALIBRATE_TIME_MSEC + 1000/2)/1000)
 
 static inline void mach_prepare_counter(void)
 {
diff --git a/include/asm-i386/mach-default/setup_arch_pre.h b/include/asm-i386/mach-default/setup_arch.h
similarity index 100%
rename from include/asm-i386/mach-default/setup_arch_pre.h
rename to include/asm-i386/mach-default/setup_arch.h
diff --git a/include/asm-i386/mach-default/setup_arch_post.h b/include/asm-i386/mach-default/setup_arch_post.h
deleted file mode 100644
index 2fc4888..0000000
--- a/include/asm-i386/mach-default/setup_arch_post.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * machine_specific_memory_setup - Hook for machine specific memory setup.
- *
- * Description:
- *	This is included late in kernel/setup.c so that it can make
- *	use of all of the static functions.
- **/
-
-static char * __init machine_specific_memory_setup(void)
-{
-	char *who;
-
-
-	who = "BIOS-e820";
-
-	/*
-	 * Try to copy the BIOS-supplied E820-map.
-	 *
-	 * Otherwise fake a memory map; one section from 0k->640k,
-	 * the next section from 1mb->appropriate_mem_k
-	 */
-	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
-		unsigned long mem_size;
-
-		/* compare results from other methods and take the greater */
-		if (ALT_MEM_K < EXT_MEM_K) {
-			mem_size = EXT_MEM_K;
-			who = "BIOS-88";
-		} else {
-			mem_size = ALT_MEM_K;
-			who = "BIOS-e801";
-		}
-
-		e820.nr_map = 0;
-		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-  	}
-	return who;
-}
diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h
index 1cce2b9..9426839 100644
--- a/include/asm-i386/mach-summit/mach_mpparse.h
+++ b/include/asm-i386/mach-summit/mach_mpparse.h
@@ -2,6 +2,7 @@
 #define __ASM_MACH_MPPARSE_H
 
 #include <mach_apic.h>
+#include <asm/tsc.h>
 
 extern int use_cyclone;
 
@@ -29,6 +30,7 @@
 			(!strncmp(productid, "VIGIL SMP", 9) 
 			 || !strncmp(productid, "EXA", 3)
 			 || !strncmp(productid, "RUTHLESS SMP", 12))){
+		mark_tsc_unstable();
 		use_cyclone = 1; /*enable cyclone-timer*/
 		setup_summit();
 		return 1;
@@ -42,6 +44,7 @@
 	if (!strncmp(oem_id, "IBM", 3) &&
 	    (!strncmp(oem_table_id, "SERVIGIL", 8)
 	     || !strncmp(oem_table_id, "EXA", 3))){
+		mark_tsc_unstable();
 		use_cyclone = 1; /*enable cyclone-timer*/
 		setup_summit();
 		return 1;
diff --git a/include/asm-i386/mach-visws/setup_arch_pre.h b/include/asm-i386/mach-visws/setup_arch.h
similarity index 100%
rename from include/asm-i386/mach-visws/setup_arch_pre.h
rename to include/asm-i386/mach-visws/setup_arch.h
diff --git a/include/asm-i386/mach-visws/setup_arch_post.h b/include/asm-i386/mach-visws/setup_arch_post.h
deleted file mode 100644
index cdbd895..0000000
--- a/include/asm-i386/mach-visws/setup_arch_post.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Hook for machine specific memory setup.
- *
- * This is included late in kernel/setup.c so that it can make use of all of
- * the static functions. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-
-long long mem_size __initdata = 0;
-
-static char * __init machine_specific_memory_setup(void)
-{
-	long long gfx_mem_size = 8 * MB;
-
-	mem_size = ALT_MEM_K;
-
-	if (!mem_size) {
-		printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
-		mem_size = 128 * MB;
-	}
-
-	/*
-	 * this hardcodes the graphics memory to 8 MB
-	 * it really should be sized dynamically (or at least
-	 * set as a boot param)
-	 */
-	if (!sgivwfb_mem_size) {
-		printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
-		sgivwfb_mem_size = 8 * MB;
-	}
-
-	/*
-	 * Trim to nearest MB
-	 */
-	sgivwfb_mem_size &= ~((1 << 20) - 1);
-	sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
-	add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-	add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
-	add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
-	return "PROM";
-
-	/* Remove gcc warnings */
-	(void) sanitize_e820_map(NULL, NULL);
-	(void) copy_e820_map(NULL, 0);
-}
diff --git a/include/asm-i386/mach-voyager/setup_arch_pre.h b/include/asm-i386/mach-voyager/setup_arch.h
similarity index 97%
rename from include/asm-i386/mach-voyager/setup_arch_pre.h
rename to include/asm-i386/mach-voyager/setup_arch.h
index 48f7e6f..84d01ad 100644
--- a/include/asm-i386/mach-voyager/setup_arch_pre.h
+++ b/include/asm-i386/mach-voyager/setup_arch.h
@@ -3,7 +3,7 @@
 
 /* Hook to call BIOS initialisation function */
 
-/* for voyager, pass the voyager BIOS/SUS info area to the detection 
+/* for voyager, pass the voyager BIOS/SUS info area to the detection
  * routines */
 
 #define ARCH_SETUP	voyager_detect(VOYAGER_BIOS_INFO);
diff --git a/include/asm-i386/mach-voyager/setup_arch_post.h b/include/asm-i386/mach-voyager/setup_arch_post.h
deleted file mode 100644
index f6f6c2c..0000000
--- a/include/asm-i386/mach-voyager/setup_arch_post.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Hook for machine specific memory setup.
- *
- * This is included late in kernel/setup.c so that it can make use of all of
- * the static functions. */
-
-static char * __init machine_specific_memory_setup(void)
-{
-	char *who;
-
-	who = "NOT VOYAGER";
-
-	if(voyager_level == 5) {
-		__u32 addr, length;
-		int i;
-
-		who = "Voyager-SUS";
-
-		e820.nr_map = 0;
-		for(i=0; voyager_memory_detect(i, &addr, &length); i++) {
-			add_memory_region(addr, length, E820_RAM);
-		}
-		return who;
-	} else if(voyager_level == 4) {
-		__u32 tom;
-		__u16 catbase = inb(VOYAGER_SSPB_RELOCATION_PORT)<<8;
-		/* select the DINO config space */
-		outb(VOYAGER_DINO, VOYAGER_CAT_CONFIG_PORT);
-		/* Read DINO top of memory register */
-		tom = ((inb(catbase + 0x4) & 0xf0) << 16)
-			+ ((inb(catbase + 0x5) & 0x7f) << 24);
-
-		if(inb(catbase) != VOYAGER_DINO) {
-			printk(KERN_ERR "Voyager: Failed to get DINO for L4, setting tom to EXT_MEM_K\n");
-			tom = (EXT_MEM_K)<<10;
-		}
-		who = "Voyager-TOM";
-		add_memory_region(0, 0x9f000, E820_RAM);
-		/* map from 1M to top of memory */
-		add_memory_region(1*1024*1024, tom - 1*1024*1024, E820_RAM);
-		/* FIXME: Should check the ASICs to see if I need to
-		 * take out the 8M window.  Just do it at the moment
-		 * */
-		add_memory_region(8*1024*1024, 8*1024*1024, E820_RESERVED);
-		return who;
-	}
-
-	who = "BIOS-e820";
-
-	/*
-	 * Try to copy the BIOS-supplied E820-map.
-	 *
-	 * Otherwise fake a memory map; one section from 0k->640k,
-	 * the next section from 1mb->appropriate_mem_k
-	 */
-	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
-		unsigned long mem_size;
-
-		/* compare results from other methods and take the greater */
-		if (ALT_MEM_K < EXT_MEM_K) {
-			mem_size = EXT_MEM_K;
-			who = "BIOS-88";
-		} else {
-			mem_size = ALT_MEM_K;
-			who = "BIOS-e801";
-		}
-
-		e820.nr_map = 0;
-		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-  	}
-	return who;
-}
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index 21f1663..67d9947 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -5,24 +5,38 @@
 #define ASM_NMI_H
 
 #include <linux/pm.h>
- 
+
 struct pt_regs;
- 
+
 typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
- 
-/** 
+
+/**
  * set_nmi_callback
  *
  * Set a handler for an NMI. Only one handler may be
  * set. Return 1 if the NMI was handled.
  */
 void set_nmi_callback(nmi_callback_t callback);
- 
-/** 
+
+/**
  * unset_nmi_callback
  *
  * Remove the handler previously set.
  */
 void unset_nmi_callback(void);
- 
+
+extern void setup_apic_nmi_watchdog (void);
+extern int reserve_lapic_nmi(void);
+extern void release_lapic_nmi(void);
+extern void disable_timer_nmi_watchdog(void);
+extern void enable_timer_nmi_watchdog(void);
+extern void nmi_watchdog_tick (struct pt_regs * regs);
+
+extern unsigned int nmi_watchdog;
+#define NMI_DEFAULT     -1
+#define NMI_NONE	0
+#define NMI_IO_APIC	1
+#define NMI_LOCAL_APIC	2
+#define NMI_INVALID	3
+
 #endif /* ASM_NMI_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 0c83cf1..55ea992 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -112,6 +112,7 @@
 extern void identify_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
+extern unsigned short num_cache_leaves;
 
 #ifdef CONFIG_X86_HT
 extern void detect_ht(struct cpuinfo_x86 *c);
@@ -554,7 +555,7 @@
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
-void show_trace(struct task_struct *task, unsigned long *stack);
+void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack);
 
 unsigned long get_wchan(struct task_struct *p);
 
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
index ee94145..f737e42 100644
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -59,6 +59,21 @@
 #define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF))
 #define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
 
+/*
+ * Do NOT EVER look at the BIOS memory size location.
+ * It does not work on many machines.
+ */
+#define LOWMEMSIZE()	(0x9f000)
+
+struct e820entry;
+
+char * __init machine_specific_memory_setup(void);
+
+int __init copy_e820_map(struct e820entry * biosmap, int nr_map);
+int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map);
+void __init add_memory_region(unsigned long long start,
+			      unsigned long long size, int type);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _i386_SETUP_H */
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 0249f91..cab0180 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -427,7 +427,7 @@
  * does not enforce ordering, since there is no data dependency between
  * the read of "a" and the read of "b".  Therefore, on some CPUs, such
  * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
- * in cases like thiswhere there are no data dependencies.
+ * in cases like this where there are no data dependencies.
  **/
 
 #define read_barrier_depends()	do { } while(0)
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 8420ed1..fdbc7f4 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -140,8 +140,7 @@
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal() */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
-#define TIF_MEMDIE		17
+#define TIF_MEMDIE		16
 
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
@@ -153,7 +152,6 @@
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
@@ -170,6 +168,9 @@
  * have to worry about atomic accesses.
  */
 #define TS_USEDFPU		0x0001	/* FPU was used by this task this quantum (SMP) */
+#define TS_POLLING		0x0002	/* True if in idle loop and not sleeping */
+
+#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index aed1643..d0ebd05 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -3,68 +3,11 @@
 #include <linux/init.h>
 #include <linux/pm.h>
 
-/**
- * struct timer_ops - used to define a timer source
- *
- * @name: name of the timer.
- * @init: Probes and initializes the timer. Takes clock= override 
- *        string as an argument. Returns 0 on success, anything else
- *        on failure.
- * @mark_offset: called by the timer interrupt.
- * @get_offset:  called by gettimeofday(). Returns the number of microseconds
- *               since the last timer interupt.
- * @monotonic_clock: returns the number of nanoseconds since the init of the
- *                   timer.
- * @delay: delays this many clock cycles.
- */
-struct timer_opts {
-	char* name;
-	void (*mark_offset)(void);
-	unsigned long (*get_offset)(void);
-	unsigned long long (*monotonic_clock)(void);
-	void (*delay)(unsigned long);
-	unsigned long (*read_timer)(void);
-	int (*suspend)(pm_message_t state);
-	int (*resume)(void);
-};
-
-struct init_timer_opts {
-	int (*init)(char *override);
-	struct timer_opts *opts;
-};
-
 #define TICK_SIZE (tick_nsec / 1000)
-
-extern struct timer_opts* __init select_timer(void);
-extern void clock_fallback(void);
 void setup_pit_timer(void);
-
 /* Modifiers for buggy PIT handling */
-
 extern int pit_latch_buggy;
-
-extern struct timer_opts *cur_timer;
 extern int timer_ack;
-
-/* list of externed timers */
-extern struct timer_opts timer_none;
-extern struct timer_opts timer_pit;
-extern struct init_timer_opts timer_pit_init;
-extern struct init_timer_opts timer_tsc_init;
-#ifdef CONFIG_X86_CYCLONE_TIMER
-extern struct init_timer_opts timer_cyclone_init;
-#endif
-
-extern unsigned long calibrate_tsc(void);
-extern unsigned long read_timer_tsc(void);
-extern void init_cpu_khz(void);
 extern int recalibrate_cpu_khz(void);
-#ifdef CONFIG_HPET_TIMER
-extern struct init_timer_opts timer_hpet_init;
-extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
-#endif
 
-#ifdef CONFIG_X86_PM_TIMER
-extern struct init_timer_opts timer_pmtmr_init;
-#endif
 #endif
diff --git a/include/asm-i386/timex.h b/include/asm-i386/timex.h
index d434984..3666044 100644
--- a/include/asm-i386/timex.h
+++ b/include/asm-i386/timex.h
@@ -7,6 +7,7 @@
 #define _ASMi386_TIMEX_H
 
 #include <asm/processor.h>
+#include <asm/tsc.h>
 
 #ifdef CONFIG_X86_ELAN
 #  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
@@ -15,39 +16,6 @@
 #endif
 
 
-/*
- * Standard way to access the cycle counter on i586+ CPUs.
- * Currently only used on SMP.
- *
- * If you really have a SMP machine with i486 chips or older,
- * compile for that, and this will just always return zero.
- * That's ok, it just means that the nicer scheduling heuristics
- * won't work for you.
- *
- * We only use the low 32 bits, and we'd simply better make sure
- * that we reschedule before that wraps. Scheduling at least every
- * four billion cycles just basically sounds like a good idea,
- * regardless of how fast the machine is. 
- */
-typedef unsigned long long cycles_t;
-
-static inline cycles_t get_cycles (void)
-{
-	unsigned long long ret=0;
-
-#ifndef CONFIG_X86_TSC
-	if (!cpu_has_tsc)
-		return 0;
-#endif
-
-#if defined(CONFIG_X86_GENERIC) || defined(CONFIG_X86_TSC)
-	rdtscll(ret);
-#endif
-	return ret;
-}
-
-extern unsigned int cpu_khz;
-
 extern int read_current_timer(unsigned long *timer_value);
 #define ARCH_HAS_READ_CURRENT_TIMER	1
 
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
new file mode 100644
index 0000000..97b828c
--- /dev/null
+++ b/include/asm-i386/tsc.h
@@ -0,0 +1,49 @@
+/*
+ * linux/include/asm-i386/tsc.h
+ *
+ * i386 TSC related functions
+ */
+#ifndef _ASM_i386_TSC_H
+#define _ASM_i386_TSC_H
+
+#include <linux/config.h>
+#include <asm/processor.h>
+
+/*
+ * Standard way to access the cycle counter on i586+ CPUs.
+ * Currently only used on SMP.
+ *
+ * If you really have a SMP machine with i486 chips or older,
+ * compile for that, and this will just always return zero.
+ * That's ok, it just means that the nicer scheduling heuristics
+ * won't work for you.
+ *
+ * We only use the low 32 bits, and we'd simply better make sure
+ * that we reschedule before that wraps. Scheduling at least every
+ * four billion cycles just basically sounds like a good idea,
+ * regardless of how fast the machine is.
+ */
+typedef unsigned long long cycles_t;
+
+extern unsigned int cpu_khz;
+extern unsigned int tsc_khz;
+
+static inline cycles_t get_cycles(void)
+{
+	unsigned long long ret = 0;
+
+#ifndef CONFIG_X86_TSC
+	if (!cpu_has_tsc)
+		return 0;
+#endif
+
+#if defined(CONFIG_X86_GENERIC) || defined(CONFIG_X86_TSC)
+	rdtscll(ret);
+#endif
+	return ret;
+}
+
+extern void tsc_init(void);
+extern void mark_tsc_unstable(void);
+
+#endif
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 8462f8e..54d905e 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -390,8 +390,12 @@
 				const void *from, unsigned long n);
 unsigned long __must_check __copy_from_user_ll(void *to,
 				const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nozero(void *to,
+				const void __user *from, unsigned long n);
 unsigned long __must_check __copy_from_user_ll_nocache(void *to,
 				const void __user *from, unsigned long n);
+unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to,
+				const void __user *from, unsigned long n);
 
 /*
  * Here we special-case 1, 2 and 4-byte copy_*_user invocations.  On a fault
@@ -458,10 +462,41 @@
  *
  * If some data could not be copied, this function will pad the copied
  * data to the requested size using zero bytes.
+ *
+ * An alternate version - __copy_from_user_inatomic() - may be called from
+ * atomic context and will fail rather than sleep.  In this case the
+ * uncopied bytes will *NOT* be padded with zeros.  See fs/filemap.h
+ * for explanation of why this is needed.
  */
 static __always_inline unsigned long
 __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
+	/* Avoid zeroing the tail if the copy fails..
+	 * If 'n' is constant and 1, 2, or 4, we do still zero on a failure,
+	 * but as the zeroing behaviour is only significant when n is not
+	 * constant, that shouldn't be a problem.
+	 */
+	if (__builtin_constant_p(n)) {
+		unsigned long ret;
+
+		switch (n) {
+		case 1:
+			__get_user_size(*(u8 *)to, from, 1, ret, 1);
+			return ret;
+		case 2:
+			__get_user_size(*(u16 *)to, from, 2, ret, 2);
+			return ret;
+		case 4:
+			__get_user_size(*(u32 *)to, from, 4, ret, 4);
+			return ret;
+		}
+	}
+	return __copy_from_user_ll_nozero(to, from, n);
+}
+static __always_inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+	might_sleep();
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
 
@@ -482,9 +517,10 @@
 
 #define ARCH_HAS_NOCACHE_UACCESS
 
-static __always_inline unsigned long __copy_from_user_inatomic_nocache(void *to,
+static __always_inline unsigned long __copy_from_user_nocache(void *to,
 				const void __user *from, unsigned long n)
 {
+	might_sleep();
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
 
@@ -504,17 +540,9 @@
 }
 
 static __always_inline unsigned long
-__copy_from_user(void *to, const void __user *from, unsigned long n)
+__copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
-       return __copy_from_user_inatomic(to, from, n);
-}
-
-static __always_inline unsigned long
-__copy_from_user_nocache(void *to, const void __user *from, unsigned long n)
-{
-       might_sleep();
-       return __copy_from_user_inatomic_nocache(to, from, n);
+       return __copy_from_user_ll_nocache_nozero(to, from, n);
 }
 
 unsigned long __must_check copy_to_user(void __user *to,
diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h
new file mode 100644
index 0000000..d480f2e
--- /dev/null
+++ b/include/asm-i386/unwind.h
@@ -0,0 +1,98 @@
+#ifndef _ASM_I386_UNWIND_H
+#define _ASM_I386_UNWIND_H
+
+/*
+ * Copyright (C) 2002-2006 Novell, Inc.
+ *	Jan Beulich <jbeulich@novell.com>
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+#ifdef CONFIG_STACK_UNWIND
+
+#include <linux/sched.h>
+#include <asm/fixmap.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+struct unwind_frame_info
+{
+	struct pt_regs regs;
+	struct task_struct *task;
+};
+
+#define UNW_PC(frame)        (frame)->regs.eip
+#define UNW_SP(frame)        (frame)->regs.esp
+#ifdef CONFIG_FRAME_POINTER
+#define UNW_FP(frame)        (frame)->regs.ebp
+#define FRAME_RETADDR_OFFSET 4
+#define FRAME_LINK_OFFSET    0
+#define STACK_BOTTOM(tsk)    STACK_LIMIT((tsk)->thread.esp0)
+#define STACK_TOP(tsk)       ((tsk)->thread.esp0)
+#endif
+#define STACK_LIMIT(ptr)     (((ptr) - 1) & ~(THREAD_SIZE - 1))
+
+#define UNW_REGISTER_INFO \
+	PTREGS_INFO(eax), \
+	PTREGS_INFO(ecx), \
+	PTREGS_INFO(edx), \
+	PTREGS_INFO(ebx), \
+	PTREGS_INFO(esp), \
+	PTREGS_INFO(ebp), \
+	PTREGS_INFO(esi), \
+	PTREGS_INFO(edi), \
+	PTREGS_INFO(eip)
+
+static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
+                                            /*const*/ struct pt_regs *regs)
+{
+	if (user_mode_vm(regs))
+		info->regs = *regs;
+	else {
+		memcpy(&info->regs, regs, offsetof(struct pt_regs, esp));
+		info->regs.esp = (unsigned long)&regs->esp;
+		info->regs.xss = __KERNEL_DS;
+	}
+}
+
+static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
+{
+	memset(&info->regs, 0, sizeof(info->regs));
+	info->regs.eip = info->task->thread.eip;
+	info->regs.xcs = __KERNEL_CS;
+	__get_user(info->regs.ebp, (long *)info->task->thread.esp);
+	info->regs.esp = info->task->thread.esp;
+	info->regs.xss = __KERNEL_DS;
+	info->regs.xds = __USER_DS;
+	info->regs.xes = __USER_DS;
+}
+
+extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *,
+                                               asmlinkage int (*callback)(struct unwind_frame_info *,
+                                                                          void *arg),
+                                               void *arg);
+
+static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
+{
+#if 0 /* This can only work when selector register and EFLAGS saves/restores
+         are properly annotated (and tracked in UNW_REGISTER_INFO). */
+	return user_mode_vm(&info->regs);
+#else
+	return info->regs.eip < PAGE_OFFSET
+	       || (info->regs.eip >= __fix_to_virt(FIX_VSYSCALL)
+	            && info->regs.eip < __fix_to_virt(FIX_VSYSCALL) + PAGE_SIZE)
+	       || info->regs.esp < PAGE_OFFSET;
+#endif
+}
+
+#else
+
+#define UNW_PC(frame) ((void)(frame), 0)
+
+static inline int arch_unw_user_mode(const void *info)
+{
+	return 0;
+}
+
+#endif
+
+#endif /* _ASM_I386_UNWIND_H */
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h
index c195a9a..aed7142 100644
--- a/include/asm-ia64/kdebug.h
+++ b/include/asm-ia64/kdebug.h
@@ -40,6 +40,8 @@
 
 extern int register_die_notifier(struct notifier_block *);
 extern int unregister_die_notifier(struct notifier_block *);
+extern int register_page_fault_notifier(struct notifier_block *);
+extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head ia64die_chain;
 
 enum die_val {
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index 8c0fc22..2418a78 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -82,6 +82,7 @@
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)pentry
 
 #define ARCH_SUPPORTS_KRETPROBES
+#define  ARCH_INACTIVE_KPROBE_COUNT 1
 
 #define SLOT0_OPCODE_SHIFT	(37)
 #define SLOT1_p1_OPCODE_SHIFT	(37 - (64-46))
diff --git a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
index ae357d5..24d898b 100644
--- a/include/asm-ia64/percpu.h
+++ b/include/asm-ia64/percpu.h
@@ -42,6 +42,7 @@
 
 #define per_cpu(var, cpu)  (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
 
 extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size);
 extern void setup_per_cpu_areas (void);
@@ -51,6 +52,7 @@
 
 #define per_cpu(var, cpu)			(*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)			per_cpu__##var
+#define __raw_get_cpu_var(var)			per_cpu__##var
 #define per_cpu_init()				(__phys_per_cpu_start)
 
 #endif	/* SMP */
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index e5392c4..8bc9869 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -27,6 +27,7 @@
 	__u32 flags;			/* thread_info flags (see TIF_*) */
 	__u32 cpu;			/* current CPU */
 	__u32 last_cpu;			/* Last CPU thread ran on */
+	__u32 status;			/* Thread synchronous flags */
 	mm_segment_t addr_limit;	/* user-level address space limit */
 	int preempt_count;		/* 0=premptable, <0=BUG; will also serve as bh-counter */
 	struct restart_block restart_block;
@@ -103,4 +104,8 @@
 /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */
 #define TIF_WORK_MASK		(TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
 
+#define TS_POLLING		1 	/* true if in idle loop and not sleeping */
+
+#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+
 #endif /* _ASM_IA64_THREAD_INFO_H */
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 33567e8..66c4742f 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -318,7 +318,7 @@
  * does not enforce ordering, since there is no data dependency between
  * the read of "a" and the read of "b".  Therefore, on some CPUs, such
  * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
- * in cases like thiswhere there are no data dependencies.
+ * in cases like this where there are no data dependencies.
  **/
 
 #define read_barrier_depends()	do { } while (0)
diff --git a/include/asm-m68k/amigaints.h b/include/asm-m68k/amigaints.h
index aa968d0..7c87134 100644
--- a/include/asm-m68k/amigaints.h
+++ b/include/asm-m68k/amigaints.h
@@ -13,6 +13,8 @@
 #ifndef _ASMm68k_AMIGAINTS_H_
 #define _ASMm68k_AMIGAINTS_H_
 
+#include <asm/irq.h>
+
 /*
 ** Amiga Interrupt sources.
 **
@@ -23,72 +25,52 @@
 #define CIA_IRQS            (5)
 #define AMI_IRQS            (32) /* AUTO_IRQS+AMI_STD_IRQS+2*CIA_IRQS */
 
-/* vertical blanking interrupt */
-#define IRQ_AMIGA_VERTB     0
-
-/* copper interrupt */
-#define IRQ_AMIGA_COPPER    1
-
-/* Audio interrupts */
-#define IRQ_AMIGA_AUD0	    2
-#define IRQ_AMIGA_AUD1	    3
-#define IRQ_AMIGA_AUD2	    4
-#define IRQ_AMIGA_AUD3	    5
-
-/* Blitter done interrupt */
-#define IRQ_AMIGA_BLIT	    6
+/* builtin serial port interrupts */
+#define IRQ_AMIGA_TBE		(IRQ_USER+0)
+#define IRQ_AMIGA_RBF		(IRQ_USER+11)
 
 /* floppy disk interrupts */
-#define IRQ_AMIGA_DSKSYN    7
-#define IRQ_AMIGA_DSKBLK    8
-
-/* builtin serial port interrupts */
-#define IRQ_AMIGA_RBF	    9
-#define IRQ_AMIGA_TBE	    10
+#define IRQ_AMIGA_DSKBLK	(IRQ_USER+1)
+#define IRQ_AMIGA_DSKSYN	(IRQ_USER+12)
 
 /* software interrupts */
-#define IRQ_AMIGA_SOFT      11
+#define IRQ_AMIGA_SOFT		(IRQ_USER+2)
 
 /* interrupts from external hardware */
-#define IRQ_AMIGA_PORTS	    12
-#define IRQ_AMIGA_EXTER	    13
+#define IRQ_AMIGA_PORTS		IRQ_AUTO_2
+#define IRQ_AMIGA_EXTER		IRQ_AUTO_6
+
+/* copper interrupt */
+#define IRQ_AMIGA_COPPER	(IRQ_USER+4)
+
+/* vertical blanking interrupt */
+#define IRQ_AMIGA_VERTB		(IRQ_USER+5)
+
+/* Blitter done interrupt */
+#define IRQ_AMIGA_BLIT		(IRQ_USER+6)
+
+/* Audio interrupts */
+#define IRQ_AMIGA_AUD0		(IRQ_USER+7)
+#define IRQ_AMIGA_AUD1		(IRQ_USER+8)
+#define IRQ_AMIGA_AUD2		(IRQ_USER+9)
+#define IRQ_AMIGA_AUD3		(IRQ_USER+10)
 
 /* CIA interrupt sources */
-#define IRQ_AMIGA_CIAA      14
-#define IRQ_AMIGA_CIAA_TA   14
-#define IRQ_AMIGA_CIAA_TB   15
-#define IRQ_AMIGA_CIAA_ALRM 16
-#define IRQ_AMIGA_CIAA_SP   17
-#define IRQ_AMIGA_CIAA_FLG  18
-#define IRQ_AMIGA_CIAB      19
-#define IRQ_AMIGA_CIAB_TA   19
-#define IRQ_AMIGA_CIAB_TB   20
-#define IRQ_AMIGA_CIAB_ALRM 21
-#define IRQ_AMIGA_CIAB_SP   22
-#define IRQ_AMIGA_CIAB_FLG  23
+#define IRQ_AMIGA_CIAA		(IRQ_USER+14)
+#define IRQ_AMIGA_CIAA_TA	(IRQ_USER+14)
+#define IRQ_AMIGA_CIAA_TB	(IRQ_USER+15)
+#define IRQ_AMIGA_CIAA_ALRM	(IRQ_USER+16)
+#define IRQ_AMIGA_CIAA_SP	(IRQ_USER+17)
+#define IRQ_AMIGA_CIAA_FLG	(IRQ_USER+18)
+#define IRQ_AMIGA_CIAB		(IRQ_USER+19)
+#define IRQ_AMIGA_CIAB_TA	(IRQ_USER+19)
+#define IRQ_AMIGA_CIAB_TB	(IRQ_USER+20)
+#define IRQ_AMIGA_CIAB_ALRM	(IRQ_USER+21)
+#define IRQ_AMIGA_CIAB_SP	(IRQ_USER+22)
+#define IRQ_AMIGA_CIAB_FLG	(IRQ_USER+23)
 
-/* auto-vector interrupts */
-#define IRQ_AMIGA_AUTO      24
-#define IRQ_AMIGA_AUTO_0    24 /* This is just a dummy */
-#define IRQ_AMIGA_AUTO_1    25
-#define IRQ_AMIGA_AUTO_2    26
-#define IRQ_AMIGA_AUTO_3    27
-#define IRQ_AMIGA_AUTO_4    28
-#define IRQ_AMIGA_AUTO_5    29
-#define IRQ_AMIGA_AUTO_6    30
-#define IRQ_AMIGA_AUTO_7    31
-
-#define IRQ_FLOPPY	    IRQ_AMIGA_DSKBLK
 
 /* INTREQR masks */
-#define IRQ1_MASK   0x0007	/* INTREQR mask for IRQ 1 */
-#define IRQ2_MASK   0x0008	/* INTREQR mask for IRQ 2 */
-#define IRQ3_MASK   0x0070	/* INTREQR mask for IRQ 3 */
-#define IRQ4_MASK   0x0780	/* INTREQR mask for IRQ 4 */
-#define IRQ5_MASK   0x1800	/* INTREQR mask for IRQ 5 */
-#define IRQ6_MASK   0x2000	/* INTREQR mask for IRQ 6 */
-#define IRQ7_MASK   0x4000	/* INTREQR mask for IRQ 7 */
-
 #define IF_SETCLR   0x8000      /* set/clr bit */
 #define IF_INTEN    0x4000	/* master interrupt bit in INT* registers */
 #define IF_EXTER    0x2000	/* external level 6 and CIA B interrupt */
@@ -106,9 +88,6 @@
 #define IF_DSKBLK   0x0002	/* diskblock DMA finished */
 #define IF_TBE	    0x0001	/* serial transmit buffer empty interrupt */
 
-extern void amiga_do_irq(int irq, struct pt_regs *fp);
-extern void amiga_do_irq_list(int irq, struct pt_regs *fp);
-
 /* CIA interrupt control register bits */
 
 #define CIA_ICR_TA	0x01
@@ -125,6 +104,7 @@
 
 extern struct ciabase ciaa_base, ciab_base;
 
+extern void cia_init_IRQ(struct ciabase *base);
 extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask);
 extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask);
 
diff --git a/include/asm-m68k/apollohw.h b/include/asm-m68k/apollohw.h
index 4304e1c..a1373b9 100644
--- a/include/asm-m68k/apollohw.h
+++ b/include/asm-m68k/apollohw.h
@@ -3,6 +3,8 @@
 #ifndef _ASMm68k_APOLLOHW_H_
 #define _ASMm68k_APOLLOHW_H_
 
+#include <linux/types.h>
+
 /*
    apollo models
 */
@@ -101,4 +103,6 @@
 
 #define isaIO2mem(x) (((((x) & 0x3f8)  << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
 
+#define IRQ_APOLLO	IRQ_USER
+
 #endif
diff --git a/include/asm-m68k/atari_stdma.h b/include/asm-m68k/atari_stdma.h
index 64f9288..b4eadf8 100644
--- a/include/asm-m68k/atari_stdma.h
+++ b/include/asm-m68k/atari_stdma.h
@@ -3,7 +3,7 @@
 #define _atari_stdma_h
 
 
-#include <asm/irq.h>
+#include <linux/interrupt.h>
 
 
 /***************************** Prototypes *****************************/
diff --git a/include/asm-m68k/atariints.h b/include/asm-m68k/atariints.h
index 42952c8..0ed454f 100644
--- a/include/asm-m68k/atariints.h
+++ b/include/asm-m68k/atariints.h
@@ -45,17 +45,6 @@
 #define IRQ_TYPE_FAST     1
 #define IRQ_TYPE_PRIO     2
 
-#define	IRQ_SPURIOUS      (0)
-
-/* auto-vector interrupts */
-#define IRQ_AUTO_1        (1)
-#define IRQ_AUTO_2        (2)
-#define IRQ_AUTO_3        (3)
-#define IRQ_AUTO_4        (4)
-#define IRQ_AUTO_5        (5)
-#define IRQ_AUTO_6        (6)
-#define IRQ_AUTO_7        (7)
-
 /* ST-MFP interrupts */
 #define IRQ_MFP_BUSY      (8)
 #define IRQ_MFP_DCD       (9)
diff --git a/include/asm-m68k/bvme6000hw.h b/include/asm-m68k/bvme6000hw.h
index 28a859b..f40d2f8 100644
--- a/include/asm-m68k/bvme6000hw.h
+++ b/include/asm-m68k/bvme6000hw.h
@@ -109,23 +109,23 @@
 
 #define BVME_IRQ_TYPE_PRIO	0
 
-#define BVME_IRQ_PRN		0x54
-#define BVME_IRQ_I596		0x1a
-#define BVME_IRQ_SCSI		0x1b
-#define BVME_IRQ_TIMER		0x59
-#define BVME_IRQ_RTC		0x1e
-#define BVME_IRQ_ABORT		0x1f
+#define BVME_IRQ_PRN		(IRQ_USER+20)
+#define BVME_IRQ_TIMER		(IRQ_USER+25)
+#define BVME_IRQ_I596		IRQ_AUTO_2
+#define BVME_IRQ_SCSI		IRQ_AUTO_3
+#define BVME_IRQ_RTC		IRQ_AUTO_6
+#define BVME_IRQ_ABORT		IRQ_AUTO_7
 
 /* SCC interrupts */
-#define BVME_IRQ_SCC_BASE		0x40
-#define BVME_IRQ_SCCB_TX		0x40
-#define BVME_IRQ_SCCB_STAT		0x42
-#define BVME_IRQ_SCCB_RX		0x44
-#define BVME_IRQ_SCCB_SPCOND		0x46
-#define BVME_IRQ_SCCA_TX		0x48
-#define BVME_IRQ_SCCA_STAT		0x4a
-#define BVME_IRQ_SCCA_RX		0x4c
-#define BVME_IRQ_SCCA_SPCOND		0x4e
+#define BVME_IRQ_SCC_BASE		IRQ_USER
+#define BVME_IRQ_SCCB_TX		IRQ_USER
+#define BVME_IRQ_SCCB_STAT		(IRQ_USER+2)
+#define BVME_IRQ_SCCB_RX		(IRQ_USER+4)
+#define BVME_IRQ_SCCB_SPCOND		(IRQ_USER+6)
+#define BVME_IRQ_SCCA_TX		(IRQ_USER+8)
+#define BVME_IRQ_SCCA_STAT		(IRQ_USER+10)
+#define BVME_IRQ_SCCA_RX		(IRQ_USER+12)
+#define BVME_IRQ_SCCA_SPCOND		(IRQ_USER+14)
 
 /* Address control registers */
 
diff --git a/include/asm-m68k/cacheflush.h b/include/asm-m68k/cacheflush.h
index 8aba971..24d3ff4 100644
--- a/include/asm-m68k/cacheflush.h
+++ b/include/asm-m68k/cacheflush.h
@@ -3,26 +3,30 @@
 
 #include <linux/mm.h>
 
+/* cache code */
+#define FLUSH_I_AND_D	(0x00000808)
+#define FLUSH_I		(0x00000008)
+
 /*
  * Cache handling functions
  */
 
-#define flush_icache()						\
-({								\
-	if (CPU_IS_040_OR_060)					\
-		__asm__ __volatile__("nop\n\t"			\
-				     ".chip 68040\n\t"		\
-				     "cinva %%ic\n\t"		\
-				     ".chip 68k" : );		\
-	else {							\
-		unsigned long _tmp;				\
-		__asm__ __volatile__("movec %%cacr,%0\n\t"	\
-				     "orw %1,%0\n\t"		\
-				     "movec %0,%%cacr"		\
-				     : "=&d" (_tmp)		\
-				     : "id" (FLUSH_I));	\
-	}							\
-})
+static inline void flush_icache(void)
+{
+	if (CPU_IS_040_OR_060)
+		asm volatile (	"nop\n"
+			"	.chip	68040\n"
+			"	cpusha	%bc\n"
+			"	.chip	68k");
+	else {
+		unsigned long tmp;
+		asm volatile (	"movec	%%cacr,%0\n"
+			"	or.w	%1,%0\n"
+			"	movec	%0,%%cacr"
+			: "=&d" (tmp)
+			: "id" (FLUSH_I));
+	}
+}
 
 /*
  * invalidate the cache for the specified memory range.
@@ -43,10 +47,6 @@
  */
 extern void cache_push_v(unsigned long vaddr, int len);
 
-/* cache code */
-#define FLUSH_I_AND_D	(0x00000808)
-#define FLUSH_I		(0x00000008)
-
 /* This is needed whenever the virtual mapping of the current
    process changes.  */
 #define __flush_cache_all()					\
diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h
index dffd59c..cebbb03 100644
--- a/include/asm-m68k/dma-mapping.h
+++ b/include/asm-m68k/dma-mapping.h
@@ -1,11 +1,91 @@
 #ifndef _M68K_DMA_MAPPING_H
 #define _M68K_DMA_MAPPING_H
 
+#include <asm/cache.h>
 
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif
+struct scatterlist;
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+	return 1;
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+	return 0;
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+	return 1 << L1_CACHE_SHIFT;
+}
+
+static inline int dma_is_consistent(dma_addr_t dma_addr)
+{
+	return 0;
+}
+
+extern void *dma_alloc_coherent(struct device *, size_t,
+				dma_addr_t *, int);
+extern void dma_free_coherent(struct device *, size_t,
+			      void *, dma_addr_t);
+
+static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
+					  dma_addr_t *handle, int flag)
+{
+	return dma_alloc_coherent(dev, size, handle, flag);
+}
+static inline void dma_free_noncoherent(struct device *dev, size_t size,
+					void *addr, dma_addr_t handle)
+{
+	dma_free_coherent(dev, size, addr, handle);
+}
+static inline void dma_cache_sync(void *vaddr, size_t size,
+				  enum dma_data_direction dir)
+{
+	/* we use coherent allocation, so not much to do here. */
+}
+
+extern dma_addr_t dma_map_single(struct device *, void *, size_t,
+				 enum dma_data_direction);
+static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
+				    size_t size, enum dma_data_direction dir)
+{
+}
+
+extern dma_addr_t dma_map_page(struct device *, struct page *,
+			       unsigned long, size_t size,
+			       enum dma_data_direction);
+static inline void dma_unmap_page(struct device *dev, dma_addr_t address,
+				  size_t size, enum dma_data_direction dir)
+{
+}
+
+extern int dma_map_sg(struct device *, struct scatterlist *, int,
+		      enum dma_data_direction);
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+				int nhwentries, enum dma_data_direction dir)
+{
+}
+
+extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
+				       enum dma_data_direction);
+extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
+				   enum dma_data_direction);
+
+static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+					   size_t size, enum dma_data_direction dir)
+{
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+				       int nents, enum dma_data_direction dir)
+{
+}
+
+static inline int dma_mapping_error(dma_addr_t handle)
+{
+	return 0;
+}
 
 #endif  /* _M68K_DMA_MAPPING_H */
diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
index 9727ca9..f4ae7d8 100644
--- a/include/asm-m68k/irq.h
+++ b/include/asm-m68k/irq.h
@@ -1,13 +1,9 @@
 #ifndef _M68K_IRQ_H_
 #define _M68K_IRQ_H_
 
-#include <linux/interrupt.h>
-
-/*
- * # of m68k interrupts
- */
-
-#define SYS_IRQS 8
+#include <linux/linkage.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock_types.h>
 
 /*
  * This should be the same as the max(NUM_X_SOURCES) for all the
@@ -15,10 +11,20 @@
  * Currently the Atari has 72 and the Amiga 24, but if both are
  * supported in the kernel it is better to make room for 72.
  */
-#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
-#define NR_IRQS (72+SYS_IRQS)
+#if defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
+#define NR_IRQS 200
+#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#define NR_IRQS 72
+#elif defined(CONFIG_Q40)
+#define NR_IRQS	43
+#elif defined(CONFIG_AMIGA)
+#define NR_IRQS	32
+#elif defined(CONFIG_APOLLO)
+#define NR_IRQS	24
+#elif defined(CONFIG_HP300)
+#define NR_IRQS	8
 #else
-#define NR_IRQS (24+SYS_IRQS)
+#error unknown nr of irqs
 #endif
 
 /*
@@ -40,53 +46,25 @@
  * that routine requires service.
  */
 
-#define IRQ1		(1)	/* level 1 interrupt */
-#define IRQ2		(2)	/* level 2 interrupt */
-#define IRQ3		(3)	/* level 3 interrupt */
-#define IRQ4		(4)	/* level 4 interrupt */
-#define IRQ5		(5)	/* level 5 interrupt */
-#define IRQ6		(6)	/* level 6 interrupt */
-#define IRQ7		(7)	/* level 7 interrupt (non-maskable) */
+#define IRQ_SPURIOUS	0
 
-/*
- * "Generic" interrupt sources
- */
+#define IRQ_AUTO_1	1	/* level 1 interrupt */
+#define IRQ_AUTO_2	2	/* level 2 interrupt */
+#define IRQ_AUTO_3	3	/* level 3 interrupt */
+#define IRQ_AUTO_4	4	/* level 4 interrupt */
+#define IRQ_AUTO_5	5	/* level 5 interrupt */
+#define IRQ_AUTO_6	6	/* level 6 interrupt */
+#define IRQ_AUTO_7	7	/* level 7 interrupt (non-maskable) */
 
-#define IRQ_SCHED_TIMER	(8)    /* interrupt source for scheduling timer */
+#define IRQ_USER	8
 
-static __inline__ int irq_canonicalize(int irq)
-{
-	return irq;
-}
-
-/*
- * Machine specific interrupt sources.
- *
- * Adding an interrupt service routine for a source with this bit
- * set indicates a special machine specific interrupt source.
- * The machine specific files define these sources.
- *
- * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
- * introduce unnecessary overhead.
- *
- * All interrupt handling is actually machine specific so it is better
- * to use function pointers, as used by the Sparc port, and select the
- * interrupt handling functions when initializing the kernel. This way
- * we save some unnecessary overhead at run-time.
- *                                                      01/11/97 - Jes
- */
-
-extern void (*enable_irq)(unsigned int);
-extern void (*disable_irq)(unsigned int);
+extern unsigned int irq_canonicalize(unsigned int irq);
+extern void enable_irq(unsigned int);
+extern void disable_irq(unsigned int);
 #define disable_irq_nosync	disable_irq
 
 struct pt_regs;
 
-extern int cpu_request_irq(unsigned int,
-			   irqreturn_t (*)(int, void *, struct pt_regs *),
-			   unsigned long, const char *, void *);
-extern void cpu_free_irq(unsigned int, void *);
-
 /*
  * various flags for request_irq() - the Amiga now uses the standard
  * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
@@ -105,29 +83,45 @@
  * interrupt source (if it supports chaining).
  */
 typedef struct irq_node {
-	irqreturn_t	(*handler)(int, void *, struct pt_regs *);
-	unsigned long	flags;
+	int		(*handler)(int, void *, struct pt_regs *);
 	void		*dev_id;
-	const char	*devname;
 	struct irq_node *next;
+	unsigned long	flags;
+	const char	*devname;
 } irq_node_t;
 
 /*
  * This structure has only 4 elements for speed reasons
  */
 typedef struct irq_handler {
-	irqreturn_t	(*handler)(int, void *, struct pt_regs *);
+	int		(*handler)(int, void *, struct pt_regs *);
 	unsigned long	flags;
 	void		*dev_id;
 	const char	*devname;
 } irq_handler_t;
 
-/* count of spurious interrupts */
-extern volatile unsigned int num_spurious;
+struct irq_controller {
+	const char *name;
+	spinlock_t lock;
+	int (*startup)(unsigned int irq);
+	void (*shutdown)(unsigned int irq);
+	void (*enable)(unsigned int irq);
+	void (*disable)(unsigned int irq);
+};
+
+extern int m68k_irq_startup(unsigned int);
+extern void m68k_irq_shutdown(unsigned int);
 
 /*
  * This function returns a new irq_node_t
  */
 extern irq_node_t *new_irq_node(void);
 
+extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
+				      void (*handler)(unsigned int, struct pt_regs *));
+extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
+
+asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *);
+
 #endif /* _M68K_IRQ_H_ */
diff --git a/include/asm-m68k/mac_oss.h b/include/asm-m68k/mac_oss.h
index 7644a63..7221f72 100644
--- a/include/asm-m68k/mac_oss.h
+++ b/include/asm-m68k/mac_oss.h
@@ -69,12 +69,12 @@
 
 #define OSS_IRQLEV_DISABLED	0
 #define OSS_IRQLEV_IOPISM	1	/* ADB? */
-#define OSS_IRQLEV_SCSI		2
-#define OSS_IRQLEV_NUBUS	3	/* keep this on its own level */
-#define OSS_IRQLEV_IOPSCC	4	/* matches VIA alternate mapping */
-#define OSS_IRQLEV_SOUND	5	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_SCSI		IRQ_AUTO_2
+#define OSS_IRQLEV_NUBUS	IRQ_AUTO_3	/* keep this on its own level */
+#define OSS_IRQLEV_IOPSCC	IRQ_AUTO_4	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_SOUND	IRQ_AUTO_5	/* matches VIA alternate mapping */
 #define OSS_IRQLEV_60HZ		6	/* matches VIA alternate mapping */
-#define OSS_IRQLEV_VIA1		6	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_VIA1		IRQ_AUTO_6	/* matches VIA alternate mapping */
 #define OSS_IRQLEV_PARITY	7	/* matches VIA alternate mapping */
 
 #ifndef __ASSEMBLY__
diff --git a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h
index 7d3fee3..df898f2 100644
--- a/include/asm-m68k/machdep.h
+++ b/include/asm-m68k/machdep.h
@@ -13,14 +13,8 @@
 extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *));
 /* machine dependent irq functions */
 extern void (*mach_init_IRQ) (void);
-extern irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
-extern int (*mach_request_irq) (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                                unsigned long flags, const char *devname, void *dev_id);
-extern void (*mach_free_irq) (unsigned int irq, void *dev_id);
 extern void (*mach_get_model) (char *model);
 extern int (*mach_get_hardware_list) (char *buffer);
-extern int (*mach_get_irq_list) (struct seq_file *p, void *v);
-extern irqreturn_t (*mach_process_int) (int irq, struct pt_regs *fp);
 /* machine dependent timer functions */
 extern unsigned long (*mach_gettimeoffset)(void);
 extern int (*mach_hwclk)(int, struct rtc_time*);
diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h
index 6fc3d19..27d11da 100644
--- a/include/asm-m68k/macintosh.h
+++ b/include/asm-m68k/macintosh.h
@@ -11,17 +11,7 @@
 extern void mac_reset(void);
 extern void mac_poweroff(void);
 extern void mac_init_IRQ(void);
-extern int mac_request_irq (unsigned int, irqreturn_t (*)(int, void *,
-				struct pt_regs *),
-				unsigned long, const char *, void *);
-extern void mac_free_irq(unsigned int, void *);
-extern void mac_enable_irq(unsigned int);
-extern void mac_disable_irq(unsigned int);
 extern int mac_irq_pending(unsigned int);
-extern int show_mac_interrupts(struct seq_file *, void *);
-#if 0
-extern void mac_default_handler(int irq);
-#endif
 extern void mac_identify(void);
 extern void mac_report_hardware(void);
 extern void mac_debugging_penguin(int);
diff --git a/include/asm-m68k/macints.h b/include/asm-m68k/macints.h
index fd8c3a9..679c48a 100644
--- a/include/asm-m68k/macints.h
+++ b/include/asm-m68k/macints.h
@@ -59,17 +59,6 @@
 #define IRQ_SRC(irq)	(irq >> 3)
 #define	IRQ_IDX(irq)	(irq & 7)
 
-#define	IRQ_SPURIOUS      (0)
-
-/* auto-vector interrupts */
-#define IRQ_AUTO_1        (1)
-#define IRQ_AUTO_2        (2)
-#define IRQ_AUTO_3        (3)
-#define IRQ_AUTO_4        (4)
-#define IRQ_AUTO_5        (5)
-#define IRQ_AUTO_6        (6)
-#define IRQ_AUTO_7        (7)
-
 /* VIA1 interrupts */
 #define IRQ_VIA1_0	  (8)		/* one second int. */
 #define IRQ_VIA1_1        (9)		/* VBlank int. */
@@ -163,7 +152,4 @@
 #define INT_CLK   24576	    /* CLK while int_clk =2.456MHz and divide = 100 */
 #define INT_TICKS 246	    /* to make sched_time = 99.902... HZ */
 
-extern irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
-extern void mac_do_irq_list(int irq, struct pt_regs *);
-
 #endif /* asm/macints.h */
diff --git a/include/asm-m68k/mvme147hw.h b/include/asm-m68k/mvme147hw.h
index f245139..b810431 100644
--- a/include/asm-m68k/mvme147hw.h
+++ b/include/asm-m68k/mvme147hw.h
@@ -1,6 +1,8 @@
 #ifndef _MVME147HW_H_
 #define _MVME147HW_H_
 
+#include <asm/irq.h>
+
 typedef struct {
 	unsigned char
 		ctrl,
@@ -72,39 +74,39 @@
 #define PCC_LEVEL_SCSI_PORT	0x04
 #define PCC_LEVEL_SCSI_DMA	0x04
 
-#define PCC_IRQ_AC_FAIL		0x40
-#define PCC_IRQ_BERR		0x41
-#define PCC_IRQ_ABORT		0x42
-/* #define PCC_IRQ_SERIAL	0x43 */
-#define PCC_IRQ_PRINTER		0x47
-#define PCC_IRQ_TIMER1		0x48
-#define PCC_IRQ_TIMER2		0x49
-#define PCC_IRQ_SOFTWARE1	0x4a
-#define PCC_IRQ_SOFTWARE2	0x4b
+#define PCC_IRQ_AC_FAIL		(IRQ_USER+0)
+#define PCC_IRQ_BERR		(IRQ_USER+1)
+#define PCC_IRQ_ABORT		(IRQ_USER+2)
+/* #define PCC_IRQ_SERIAL	(IRQ_USER+3) */
+#define PCC_IRQ_PRINTER		(IRQ_USER+7)
+#define PCC_IRQ_TIMER1		(IRQ_USER+8)
+#define PCC_IRQ_TIMER2		(IRQ_USER+9)
+#define PCC_IRQ_SOFTWARE1	(IRQ_USER+10)
+#define PCC_IRQ_SOFTWARE2	(IRQ_USER+11)
 
 
 #define M147_SCC_A_ADDR		0xfffe3002
 #define M147_SCC_B_ADDR		0xfffe3000
 #define M147_SCC_PCLK		5000000
 
-#define MVME147_IRQ_SCSI_PORT	0x45
-#define MVME147_IRQ_SCSI_DMA	0x46
+#define MVME147_IRQ_SCSI_PORT	(IRQ_USER+0x45)
+#define MVME147_IRQ_SCSI_DMA	(IRQ_USER+0x46)
 
 /* SCC interrupts, for MVME147 */
 
 #define MVME147_IRQ_TYPE_PRIO	0
-#define MVME147_IRQ_SCC_BASE		0x60
-#define MVME147_IRQ_SCCB_TX		0x60
-#define MVME147_IRQ_SCCB_STAT		0x62
-#define MVME147_IRQ_SCCB_RX		0x64
-#define MVME147_IRQ_SCCB_SPCOND		0x66
-#define MVME147_IRQ_SCCA_TX		0x68
-#define MVME147_IRQ_SCCA_STAT		0x6a
-#define MVME147_IRQ_SCCA_RX		0x6c
-#define MVME147_IRQ_SCCA_SPCOND		0x6e
+#define MVME147_IRQ_SCC_BASE		(IRQ_USER+32)
+#define MVME147_IRQ_SCCB_TX		(IRQ_USER+32)
+#define MVME147_IRQ_SCCB_STAT		(IRQ_USER+34)
+#define MVME147_IRQ_SCCB_RX		(IRQ_USER+36)
+#define MVME147_IRQ_SCCB_SPCOND		(IRQ_USER+38)
+#define MVME147_IRQ_SCCA_TX		(IRQ_USER+40)
+#define MVME147_IRQ_SCCA_STAT		(IRQ_USER+42)
+#define MVME147_IRQ_SCCA_RX		(IRQ_USER+44)
+#define MVME147_IRQ_SCCA_SPCOND		(IRQ_USER+46)
 
 #define MVME147_LANCE_BASE	0xfffe1800
-#define MVME147_LANCE_IRQ	0x44
+#define MVME147_LANCE_IRQ	(IRQ_USER+4)
 
 #define ETHERNET_ADDRESS 0xfffe0778
 
diff --git a/include/asm-m68k/mvme16xhw.h b/include/asm-m68k/mvme16xhw.h
index 5d07231..6117f56 100644
--- a/include/asm-m68k/mvme16xhw.h
+++ b/include/asm-m68k/mvme16xhw.h
@@ -66,28 +66,28 @@
 
 #define MVME162_IRQ_TYPE_PRIO	0
 
-#define MVME167_IRQ_PRN		0x54
-#define MVME16x_IRQ_I596	0x57
-#define MVME16x_IRQ_SCSI	0x55
-#define MVME16x_IRQ_FLY		0x7f
-#define MVME167_IRQ_SER_ERR	0x5c
-#define MVME167_IRQ_SER_MODEM	0x5d
-#define MVME167_IRQ_SER_TX	0x5e
-#define MVME167_IRQ_SER_RX	0x5f
-#define MVME16x_IRQ_TIMER	0x59
-#define MVME167_IRQ_ABORT	0x6e
-#define MVME162_IRQ_ABORT	0x5e
+#define MVME167_IRQ_PRN		(IRQ_USER+20)
+#define MVME16x_IRQ_I596	(IRQ_USER+23)
+#define MVME16x_IRQ_SCSI	(IRQ_USER+21)
+#define MVME16x_IRQ_FLY		(IRQ_USER+63)
+#define MVME167_IRQ_SER_ERR	(IRQ_USER+28)
+#define MVME167_IRQ_SER_MODEM	(IRQ_USER+29)
+#define MVME167_IRQ_SER_TX	(IRQ_USER+30)
+#define MVME167_IRQ_SER_RX	(IRQ_USER+31)
+#define MVME16x_IRQ_TIMER	(IRQ_USER+25)
+#define MVME167_IRQ_ABORT	(IRQ_USER+46)
+#define MVME162_IRQ_ABORT	(IRQ_USER+30)
 
 /* SCC interrupts, for MVME162 */
-#define MVME162_IRQ_SCC_BASE		0x40
-#define MVME162_IRQ_SCCB_TX		0x40
-#define MVME162_IRQ_SCCB_STAT		0x42
-#define MVME162_IRQ_SCCB_RX		0x44
-#define MVME162_IRQ_SCCB_SPCOND		0x46
-#define MVME162_IRQ_SCCA_TX		0x48
-#define MVME162_IRQ_SCCA_STAT		0x4a
-#define MVME162_IRQ_SCCA_RX		0x4c
-#define MVME162_IRQ_SCCA_SPCOND		0x4e
+#define MVME162_IRQ_SCC_BASE		(IRQ_USER+0)
+#define MVME162_IRQ_SCCB_TX		(IRQ_USER+0)
+#define MVME162_IRQ_SCCB_STAT		(IRQ_USER+2)
+#define MVME162_IRQ_SCCB_RX		(IRQ_USER+4)
+#define MVME162_IRQ_SCCB_SPCOND		(IRQ_USER+6)
+#define MVME162_IRQ_SCCA_TX		(IRQ_USER+8)
+#define MVME162_IRQ_SCCA_STAT		(IRQ_USER+10)
+#define MVME162_IRQ_SCCA_RX		(IRQ_USER+12)
+#define MVME162_IRQ_SCCA_SPCOND		(IRQ_USER+14)
 
 /* MVME162 version register */
 
diff --git a/include/asm-m68k/scatterlist.h b/include/asm-m68k/scatterlist.h
index d7c9b5c..8e61226 100644
--- a/include/asm-m68k/scatterlist.h
+++ b/include/asm-m68k/scatterlist.h
@@ -2,18 +2,17 @@
 #define _M68K_SCATTERLIST_H
 
 struct scatterlist {
-	/* These two are only valid if ADDRESS member of this
-	 * struct is NULL.
-	 */
 	struct page *page;
 	unsigned int offset;
-
 	unsigned int length;
 
-	__u32 dvma_address; /* A place to hang host-specific addresses at. */
+	__u32 dma_address;	/* A place to hang host-specific addresses at. */
 };
 
 /* This is bogus and should go away. */
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->length)
+
 #endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h
index b7b7ea2..85037a3 100644
--- a/include/asm-m68k/signal.h
+++ b/include/asm-m68k/signal.h
@@ -156,13 +156,17 @@
 
 static inline void sigaddset(sigset_t *set, int _sig)
 {
-	__asm__("bfset %0{%1,#1}" : "=m" (*set) : "id" ((_sig - 1) ^ 31)
+	asm ("bfset %0{%1,#1}"
+		: "+od" (*set)
+		: "id" ((_sig - 1) ^ 31)
 		: "cc");
 }
 
 static inline void sigdelset(sigset_t *set, int _sig)
 {
-	__asm__("bfclr %0{%1,#1}" : "=m"(*set) : "id"((_sig - 1) ^ 31)
+	asm ("bfclr %0{%1,#1}"
+		: "+od" (*set)
+		: "id" ((_sig - 1) ^ 31)
 		: "cc");
 }
 
@@ -175,8 +179,10 @@
 static inline int __gen_sigismember(sigset_t *set, int _sig)
 {
 	int ret;
-	__asm__("bfextu %1{%2,#1},%0"
-		: "=d"(ret) : "m"(*set), "id"((_sig-1) ^ 31));
+	asm ("bfextu %1{%2,#1},%0"
+		: "=d" (ret)
+		: "od" (*set), "id" ((_sig-1) ^ 31)
+		: "cc");
 	return ret;
 }
 
@@ -187,7 +193,10 @@
 
 static inline int sigfindinword(unsigned long word)
 {
-	__asm__("bfffo %1{#0,#0},%0" : "=d"(word) : "d"(word & -word) : "cc");
+	asm ("bfffo %1{#0,#0},%0"
+		: "=d" (word)
+		: "d" (word & -word)
+		: "cc");
 	return word ^ 31;
 }
 
diff --git a/include/asm-m68k/sun3ints.h b/include/asm-m68k/sun3ints.h
index bd038fc..de91fa0 100644
--- a/include/asm-m68k/sun3ints.h
+++ b/include/asm-m68k/sun3ints.h
@@ -12,37 +12,25 @@
 #define SUN3INTS_H
 
 #include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <linux/seq_file.h>
-#include <asm/segment.h>
 #include <asm/intersil.h>
 #include <asm/oplib.h>
+#include <asm/traps.h>
 
 #define SUN3_INT_VECS 192
 
 void sun3_enable_irq(unsigned int irq);
 void sun3_disable_irq(unsigned int irq);
-int sun3_request_irq(unsigned int irq,
-                     irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                     unsigned long flags, const char *devname, void *dev_id
-		    );
 extern void sun3_init_IRQ (void);
-extern irqreturn_t (*sun3_default_handler[]) (int, void *, struct pt_regs *);
-extern void sun3_free_irq (unsigned int irq, void *dev_id);
 extern void sun3_enable_interrupts (void);
 extern void sun3_disable_interrupts (void);
-extern int show_sun3_interrupts(struct seq_file *, void *);
-extern irqreturn_t sun3_process_int(int, struct pt_regs *);
 extern volatile unsigned char* sun3_intreg;
 
 /* master list of VME vectors -- don't fuck with this */
-#define SUN3_VEC_FLOPPY 0x40
-#define SUN3_VEC_VMESCSI0 0x40
-#define SUN3_VEC_VMESCSI1 0x41
-#define SUN3_VEC_CG 0xA8
+#define SUN3_VEC_FLOPPY		(IRQ_USER+0)
+#define SUN3_VEC_VMESCSI0	(IRQ_USER+0)
+#define SUN3_VEC_VMESCSI1	(IRQ_USER+1)
+#define SUN3_VEC_CG		(IRQ_USER+104)
 
 
 #endif /* SUN3INTS_H */
diff --git a/include/asm-m68k/traps.h b/include/asm-m68k/traps.h
index 4750561..8caef25 100644
--- a/include/asm-m68k/traps.h
+++ b/include/asm-m68k/traps.h
@@ -13,8 +13,15 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+
 typedef void (*e_vector)(void);
 
+asmlinkage void auto_inthandler(void);
+asmlinkage void user_inthandler(void);
+asmlinkage void bad_inthandler(void);
+
 extern e_vector vectors[];
 
 #endif
diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
index b761ef2..88b1f47 100644
--- a/include/asm-m68k/uaccess.h
+++ b/include/asm-m68k/uaccess.h
@@ -181,144 +181,164 @@
 unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n);
 unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n);
 
+#define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
+	asm volatile ("\n"						\
+		"1:	moves."#s1"	(%2)+,%3\n"			\
+		"	move."#s1"	%3,(%1)+\n"			\
+		"2:	moves."#s2"	(%2)+,%3\n"			\
+		"	move."#s2"	%3,(%1)+\n"			\
+		"	.ifnc	\""#s3"\",\"\"\n"			\
+		"3:	moves."#s3"	(%2)+,%3\n"			\
+		"	move."#s3"	%3,(%1)+\n"			\
+		"	.endif\n"					\
+		"4:\n"							\
+		"	.section __ex_table,\"a\"\n"			\
+		"	.align	4\n"					\
+		"	.long	1b,10f\n"				\
+		"	.long	2b,20f\n"				\
+		"	.ifnc	\""#s3"\",\"\"\n"			\
+		"	.long	3b,30f\n"				\
+		"	.endif\n"					\
+		"	.previous\n"					\
+		"\n"							\
+		"	.section .fixup,\"ax\"\n"			\
+		"	.even\n"					\
+		"10:	clr."#s1"	(%1)+\n"			\
+		"20:	clr."#s2"	(%1)+\n"			\
+		"	.ifnc	\""#s3"\",\"\"\n"			\
+		"30:	clr."#s3"	(%1)+\n"			\
+		"	.endif\n"					\
+		"	moveq.l	#"#n",%0\n"				\
+		"	jra	4b\n"					\
+		"	.previous\n"					\
+		: "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp)	\
+		: : "memory")
+
 static __always_inline unsigned long
 __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	unsigned long res = 0, tmp;
 
-	/* limit the inlined version to 3 moves */
-	if (n == 11 || n > 12)
-		return __generic_copy_from_user(to, from, n);
-
 	switch (n) {
 	case 1:
 		__get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1);
-		return res;
+		break;
 	case 2:
 		__get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2);
-		return res;
+		break;
+	case 3:
+		__constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
+		break;
 	case 4:
 		__get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4);
-		return res;
+		break;
+	case 5:
+		__constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
+		break;
+	case 6:
+		__constant_copy_from_user_asm(res, to, from, tmp, 6, l, w,);
+		break;
+	case 7:
+		__constant_copy_from_user_asm(res, to, from, tmp, 7, l, w, b);
+		break;
+	case 8:
+		__constant_copy_from_user_asm(res, to, from, tmp, 8, l, l,);
+		break;
+	case 9:
+		__constant_copy_from_user_asm(res, to, from, tmp, 9, l, l, b);
+		break;
+	case 10:
+		__constant_copy_from_user_asm(res, to, from, tmp, 10, l, l, w);
+		break;
+	case 12:
+		__constant_copy_from_user_asm(res, to, from, tmp, 12, l, l, l);
+		break;
+	default:
+		/* we limit the inlined version to 3 moves */
+		return __generic_copy_from_user(to, from, n);
 	}
 
-	asm volatile ("\n"
-		"	.ifndef	.Lfrom_user\n"
-		"	.set	.Lfrom_user,1\n"
-		"	.macro	copy_from_user to,from,tmp\n"
-		"	.if	.Lcnt >= 4\n"
-		"1:	moves.l	(\\from)+,\\tmp\n"
-		"	move.l	\\tmp,(\\to)+\n"
-		"	.set	.Lcnt,.Lcnt-4\n"
-		"	.elseif	.Lcnt & 2\n"
-		"1:	moves.w	(\\from)+,\\tmp\n"
-		"	move.w	\\tmp,(\\to)+\n"
-		"	.set	.Lcnt,.Lcnt-2\n"
-		"	.elseif	.Lcnt & 1\n"
-		"1:	moves.b	(\\from)+,\\tmp\n"
-		"	move.b	\\tmp,(\\to)+\n"
-		"	.set	.Lcnt,.Lcnt-1\n"
-		"	.else\n"
-		"	.exitm\n"
-		"	.endif\n"
-		"\n"
-		"	.section __ex_table,\"a\"\n"
-		"	.align	4\n"
-		"	.long	1b,3f\n"
-		"	.previous\n"
-		"	.endm\n"
-		"	.endif\n"
-		"\n"
-		"	.set	.Lcnt,%c4\n"
-		"	copy_from_user %1,%2,%3\n"
-		"	copy_from_user %1,%2,%3\n"
-		"	copy_from_user %1,%2,%3\n"
-		"2:\n"
-		"	.section .fixup,\"ax\"\n"
-		"	.even\n"
-		"3:	moveq.l	%4,%0\n"
-		"	move.l	%5,%1\n"
-		"	.rept	%c4 / 4\n"
-		"	clr.l	(%1)+\n"
-		"	.endr\n"
-		"	.if	%c4 & 2\n"
-		"	clr.w	(%1)+\n"
-		"	.endif\n"
-		"	.if	%c4 & 1\n"
-		"	clr.b	(%1)+\n"
-		"	.endif\n"
-		"	jra	2b\n"
-		"	.previous\n"
-		: "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp)
-		: "i" (n), "g" (to)
-		: "memory");
-
 	return res;
 }
 
+#define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3)	\
+	asm volatile ("\n"						\
+		"	move."#s1"	(%2)+,%3\n"			\
+		"11:	moves."#s1"	%3,(%1)+\n"			\
+		"12:	move."#s2"	(%2)+,%3\n"			\
+		"21:	moves."#s2"	%3,(%1)+\n"			\
+		"22:\n"							\
+		"	.ifnc	\""#s3"\",\"\"\n"			\
+		"	move."#s3"	(%2)+,%3\n"			\
+		"31:	moves."#s3"	%3,(%1)+\n"			\
+		"32:\n"							\
+		"	.endif\n"					\
+		"4:\n"							\
+		"\n"							\
+		"	.section __ex_table,\"a\"\n"			\
+		"	.align	4\n"					\
+		"	.long	11b,5f\n"				\
+		"	.long	12b,5f\n"				\
+		"	.long	21b,5f\n"				\
+		"	.long	22b,5f\n"				\
+		"	.ifnc	\""#s3"\",\"\"\n"			\
+		"	.long	31b,5f\n"				\
+		"	.long	32b,5f\n"				\
+		"	.endif\n"					\
+		"	.previous\n"					\
+		"\n"							\
+		"	.section .fixup,\"ax\"\n"			\
+		"	.even\n"					\
+		"5:	moveq.l	#"#n",%0\n"				\
+		"	jra	4b\n"					\
+		"	.previous\n"					\
+		: "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp)	\
+		: : "memory")
+
 static __always_inline unsigned long
 __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	unsigned long res = 0, tmp;
 
-	/* limit the inlined version to 3 moves */
-	if (n == 11 || n > 12)
-		return __generic_copy_to_user(to, from, n);
-
 	switch (n) {
 	case 1:
 		__put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1);
-		return res;
+		break;
 	case 2:
 		__put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2);
-		return res;
+		break;
+	case 3:
+		__constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
+		break;
 	case 4:
 		__put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4);
-		return res;
+		break;
+	case 5:
+		__constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
+		break;
+	case 6:
+		__constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
+		break;
+	case 7:
+		__constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
+		break;
+	case 8:
+		__constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
+		break;
+	case 9:
+		__constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
+		break;
+	case 10:
+		__constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
+		break;
+	case 12:
+		__constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
+		break;
+	default:
+		/* limit the inlined version to 3 moves */
+		return __generic_copy_to_user(to, from, n);
 	}
 
-	asm volatile ("\n"
-		"	.ifndef	.Lto_user\n"
-		"	.set	.Lto_user,1\n"
-		"	.macro	copy_to_user to,from,tmp\n"
-		"	.if	.Lcnt >= 4\n"
-		"	move.l	(\\from)+,\\tmp\n"
-		"11:	moves.l	\\tmp,(\\to)+\n"
-		"12:	.set	.Lcnt,.Lcnt-4\n"
-		"	.elseif	.Lcnt & 2\n"
-		"	move.w	(\\from)+,\\tmp\n"
-		"11:	moves.w	\\tmp,(\\to)+\n"
-		"12:	.set	.Lcnt,.Lcnt-2\n"
-		"	.elseif	.Lcnt & 1\n"
-		"	move.b	(\\from)+,\\tmp\n"
-		"11:	moves.b	\\tmp,(\\to)+\n"
-		"12:	.set	.Lcnt,.Lcnt-1\n"
-		"	.else\n"
-		"	.exitm\n"
-		"	.endif\n"
-		"\n"
-		"	.section __ex_table,\"a\"\n"
-		"	.align	4\n"
-		"	.long	11b,3f\n"
-		"	.long	12b,3f\n"
-		"	.previous\n"
-		"	.endm\n"
-		"	.endif\n"
-		"\n"
-		"	.set	.Lcnt,%c4\n"
-		"	copy_to_user %1,%2,%3\n"
-		"	copy_to_user %1,%2,%3\n"
-		"	copy_to_user %1,%2,%3\n"
-		"2:\n"
-		"	.section .fixup,\"ax\"\n"
-		"	.even\n"
-		"3:	moveq.l	%4,%0\n"
-		"	jra	2b\n"
-		"	.previous\n"
-		: "+r" (res), "+a" (to), "+a" (from), "=&d" (tmp)
-		: "i" (n)
-		: "memory");
-
 	return res;
 }
 
diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h
index 49925e9..c3aadf3 100644
--- a/include/asm-m68knommu/cacheflush.h
+++ b/include/asm-m68knommu/cacheflush.h
@@ -57,13 +57,13 @@
 		"nop\n\t"
 		: : : "d0" );
 #endif /* CONFIG_M527x || CONFIG_M528x */
-#ifdef CONFIG_M5272
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272)
 	__asm__ __volatile__ (
-        	"movel	#0x01000000, %%d0\n\t"
+        	"movel	#0x81000100, %%d0\n\t"
         	"movec	%%d0, %%CACR\n\t"
 		"nop\n\t"
 		: : : "d0" );
-#endif /* CONFIG_M5272 */
+#endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */
 #ifdef CONFIG_M5249
 	__asm__ __volatile__ (
         	"movel	#0xa1000200, %%d0\n\t"
@@ -71,6 +71,13 @@
 		"nop\n\t"
 		: : : "d0" );
 #endif /* CONFIG_M5249 */
+#ifdef CONFIG_M532x
+	__asm__ __volatile__ (
+        	"movel	#0x81000200, %%d0\n\t"
+        	"movec	%%d0, %%CACR\n\t"
+		"nop\n\t"
+		: : : "d0" );
+#endif /* CONFIG_M532x */
 }
 
 #endif /* _M68KNOMMU_CACHEFLUSH_H */
diff --git a/include/asm-m68knommu/coldfire.h b/include/asm-m68knommu/coldfire.h
index 2fabca9..83a9fa4 100644
--- a/include/asm-m68knommu/coldfire.h
+++ b/include/asm-m68knommu/coldfire.h
@@ -3,7 +3,7 @@
 /*
  *	coldfire.h -- Motorola ColdFire CPU sepecific defines
  *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *	(C) Copyright 1999-2006, Greg Ungerer (gerg@snapgear.com)
  *	(C) Copyright 2000, Lineo (www.lineo.com)
  */
 
@@ -14,6 +14,19 @@
 
 
 /*
+ *	Define master clock frequency. This is essentially done at config
+ *	time now. No point enumerating dozens of possible clock options
+ *	here. Also the peripheral clock (bus clock) divide ratio is set
+ *	at config time too.
+ */
+#ifdef CONFIG_CLOCK_SET
+#define	MCF_CLK		CONFIG_CLOCK_FREQ
+#define	MCF_BUSCLK	(CONFIG_CLOCK_FREQ / CONFIG_CLOCK_DIV)
+#else
+#error "Don't know what your ColdFire CPU clock frequency is??"
+#endif
+
+/*
  *	Define the processor support peripherals base address.
  *	This is generally setup by the boards start up code.
  */
@@ -29,64 +42,9 @@
     defined(CONFIG_M520x)
 #undef MCF_MBAR
 #define	MCF_MBAR	MCF_IPSBAR
-#endif
-
-/*
- *	Define master clock frequency.
- */
-#if defined(CONFIG_CLOCK_11MHz)
-#define	MCF_CLK		11289600
-#elif defined(CONFIG_CLOCK_16MHz)
-#define	MCF_CLK		16000000
-#elif defined(CONFIG_CLOCK_20MHz)
-#define	MCF_CLK		20000000
-#elif defined(CONFIG_CLOCK_24MHz)
-#define	MCF_CLK		24000000
-#elif defined(CONFIG_CLOCK_25MHz)
-#define	MCF_CLK		25000000
-#elif defined(CONFIG_CLOCK_33MHz)
-#define	MCF_CLK		33000000
-#elif defined(CONFIG_CLOCK_40MHz)
-#define	MCF_CLK		40000000
-#elif defined(CONFIG_CLOCK_45MHz)
-#define	MCF_CLK		45000000
-#elif defined(CONFIG_CLOCK_48MHz)
-#define	MCF_CLK		48000000
-#elif defined(CONFIG_CLOCK_50MHz)
-#define	MCF_CLK		50000000
-#elif defined(CONFIG_CLOCK_54MHz)
-#define	MCF_CLK		54000000
-#elif defined(CONFIG_CLOCK_60MHz)
-#define	MCF_CLK		60000000
-#elif defined(CONFIG_CLOCK_62_5MHz)
-#define MCF_CLK		62500000
-#elif defined(CONFIG_CLOCK_64MHz)
-#define	MCF_CLK		64000000
-#elif defined(CONFIG_CLOCK_66MHz)
-#define	MCF_CLK		66000000
-#elif defined(CONFIG_CLOCK_70MHz)
-#define	MCF_CLK		70000000
-#elif defined(CONFIG_CLOCK_100MHz)
-#define	MCF_CLK		100000000
-#elif defined(CONFIG_CLOCK_140MHz)
-#define	MCF_CLK		140000000
-#elif defined(CONFIG_CLOCK_150MHz)
-#define	MCF_CLK		150000000
-#elif defined(CONFIG_CLOCK_166MHz)
-#define	MCF_CLK		166000000
-#else
-#error "Don't know what your ColdFire CPU clock frequency is??"
-#endif
-
-/*
- *	One some ColdFire family members the bus clock (used by internal
- *	peripherals) is not the same as the CPU clock.
- */
-#if defined(CONFIG_M523x) || defined(CONFIG_M5249) || defined(CONFIG_M527x) || \
-    defined(CONFIG_M520x)
-#define	MCF_BUSCLK	(MCF_CLK / 2)
-#else
-#define	MCF_BUSCLK	MCF_CLK
+#elif defined(CONFIG_M532x)
+#undef MCF_MBAR
+#define MCF_MBAR	0x00000000
 #endif
 
 /****************************************************************************/
diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h
index c524751..5355727 100644
--- a/include/asm-m68knommu/irq.h
+++ b/include/asm-m68knommu/irq.h
@@ -83,7 +83,7 @@
 /*
  * Some drivers want these entry points
  */
-#define enable_irq(x)	0
+#define enable_irq(x)	do { } while (0)
 #define disable_irq(x)	do { } while (0)
 #define disable_irq_nosync(x)	disable_irq(x)
 
diff --git a/include/asm-m68knommu/m5249sim.h b/include/asm-m68knommu/m5249sim.h
index 9344f52..399814f 100644
--- a/include/asm-m68knommu/m5249sim.h
+++ b/include/asm-m68knommu/m5249sim.h
@@ -157,7 +157,7 @@
 	movel	%d0,0x180(%a1)			/* set PLL register */
 	nop
 
-#ifdef CONFIG_CLOCK_140MHz
+#if CONFIG_CLOCK_FREQ == 140000000
 	/*
 	 *	Set initial clock frequency. This assumes M5249C3 board
 	 *	is fitted with 11.2896MHz crystal. It will program the
diff --git a/include/asm-m68knommu/m532xsim.h b/include/asm-m68knommu/m532xsim.h
new file mode 100644
index 0000000..1835fd2
--- /dev/null
+++ b/include/asm-m68knommu/m532xsim.h
@@ -0,0 +1,2238 @@
+/****************************************************************************/
+
+/*
+ *	m532xsim.h -- ColdFire 5329 registers
+ */
+
+/****************************************************************************/
+#ifndef	m532xsim_h
+#define	m532xsim_h
+/****************************************************************************/
+
+#define MCF_REG32(x) (*(volatile unsigned long  *)(x))
+#define MCF_REG16(x) (*(volatile unsigned short *)(x))
+#define MCF_REG08(x) (*(volatile unsigned char  *)(x))
+
+#define MCFINT_VECBASE      64
+#define MCFINT_UART0        26          /* Interrupt number for UART0 */
+#define MCFINT_UART1        27          /* Interrupt number for UART1 */
+
+#define MCF_WTM_WCR	MCF_REG16(0xFC098000)
+
+/*
+ *	Define the 532x SIM register set addresses.
+ */
+#define	MCFSIM_IPRL		0xFC048004
+#define	MCFSIM_IPRH		0xFC048000
+#define	MCFSIM_IPR		MCFSIM_IPRL
+#define	MCFSIM_IMRL		0xFC04800C
+#define	MCFSIM_IMRH		0xFC048008
+#define	MCFSIM_IMR		MCFSIM_IMRL
+#define	MCFSIM_ICR0		0xFC048040	
+#define	MCFSIM_ICR1		0xFC048041	
+#define	MCFSIM_ICR2		0xFC048042	
+#define	MCFSIM_ICR3		0xFC048043	
+#define	MCFSIM_ICR4		0xFC048044	
+#define	MCFSIM_ICR5		0xFC048045	
+#define	MCFSIM_ICR6		0xFC048046	
+#define	MCFSIM_ICR7		0xFC048047	
+#define	MCFSIM_ICR8		0xFC048048	
+#define	MCFSIM_ICR9		0xFC048049	
+#define	MCFSIM_ICR10		0xFC04804A
+#define	MCFSIM_ICR11		0xFC04804B
+
+/*
+ *	Some symbol defines for the above...
+ */
+#define	MCFSIM_SWDICR		MCFSIM_ICR0	/* Watchdog timer ICR */
+#define	MCFSIM_TIMER1ICR	MCFSIM_ICR1	/* Timer 1 ICR */
+#define	MCFSIM_TIMER2ICR	MCFSIM_ICR2	/* Timer 2 ICR */
+#define	MCFSIM_UART1ICR		MCFSIM_ICR4	/* UART 1 ICR */
+#define	MCFSIM_UART2ICR		MCFSIM_ICR5	/* UART 2 ICR */
+#define	MCFSIM_DMA0ICR		MCFSIM_ICR6	/* DMA 0 ICR */
+#define	MCFSIM_DMA1ICR		MCFSIM_ICR7	/* DMA 1 ICR */
+#define	MCFSIM_DMA2ICR		MCFSIM_ICR8	/* DMA 2 ICR */
+#define	MCFSIM_DMA3ICR		MCFSIM_ICR9	/* DMA 3 ICR */
+
+
+#define	MCFSIM_IMR_MASKALL	0xFFFFFFFF	/* All SIM intr sources */
+
+#define MCFSIM_IMR_SIMR0	0xFC04801C
+#define MCFSIM_IMR_SIMR1	0xFC04C01C
+#define MCFSIM_IMR_CIMR0	0xFC04801D
+#define MCFSIM_IMR_CIMR1	0xFC04C01D
+
+#define MCFSIM_ICR_TIMER1	(0xFC048040+32)
+#define MCFSIM_ICR_TIMER2	(0xFC048040+33)
+
+
+/*
+ *	Macro to set IMR register. It is 32 bits on the 5307.
+ */
+#define	mcf_getimr()		\
+	*((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR))
+
+#define	mcf_setimr(imr)		\
+	*((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr);
+
+#define	mcf_getipr()		\
+	*((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR))
+
+#define	mcf_getiprl()		\
+	*((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPRL))
+
+#define	mcf_getiprh()		\
+	*((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPRH))
+
+
+#define mcf_enable_irq0(irq)		\
+	*((volatile unsigned char*) (MCFSIM_IMR_CIMR0)) = (irq);
+
+#define mcf_enable_irq1(irq)		\
+	*((volatile unsigned char*) (MCFSIM_IMR_CIMR1)) = (irq);
+
+#define mcf_disable_irq0(irq)		\
+	*((volatile unsigned char*) (MCFSIM_IMR_SIMR0)) = (irq);
+
+#define mcf_disable_irq1(irq)		\
+	*((volatile unsigned char*) (MCFSIM_IMR_SIMR1)) = (irq);
+
+/*
+ *	Define the Cache register flags.
+ */
+#define	CACR_EC			(1<<31)
+#define	CACR_ESB		(1<<29)
+#define	CACR_DPI		(1<<28)
+#define	CACR_HLCK		(1<<27)
+#define	CACR_CINVA		(1<<24)
+#define	CACR_DNFB		(1<<10)
+#define	CACR_DCM_WTHRU		(0<<8)
+#define	CACR_DCM_WBACK		(1<<8)
+#define	CACR_DCM_OFF_PRE	(2<<8)
+#define	CACR_DCM_OFF_IMP	(3<<8)
+#define	CACR_DW			(1<<5)
+
+#define	ACR_BASE_POS		24
+#define	ACR_MASK_POS		16
+#define	ACR_ENABLE		(1<<15)
+#define	ACR_USER		(0<<13)
+#define	ACR_SUPER		(1<<13)
+#define	ACR_ANY			(2<<13)
+#define	ACR_CM_WTHRU		(0<<5)
+#define	ACR_CM_WBACK		(1<<5)
+#define	ACR_CM_OFF_PRE		(2<<5)
+#define	ACR_CM_OFF_IMP		(3<<5)
+#define	ACR_WPROTECT		(1<<2)
+
+/*********************************************************************
+ *
+ * Inter-IC (I2C) Module
+ *
+ *********************************************************************/
+
+/* Read/Write access macros for general use */
+#define MCF532x_I2C_I2ADR       (volatile u8 *) (0xFC058000) // Address 
+#define MCF532x_I2C_I2FDR       (volatile u8 *) (0xFC058004) // Freq Divider
+#define MCF532x_I2C_I2CR        (volatile u8 *) (0xFC058008) // Control
+#define MCF532x_I2C_I2SR        (volatile u8 *) (0xFC05800C) // Status
+#define MCF532x_I2C_I2DR        (volatile u8 *) (0xFC058010) // Data I/O
+
+/* Bit level definitions and macros */
+#define MCF532x_I2C_I2ADR_ADDR(x)                       (((x)&0x7F)<<0x01)
+
+#define MCF532x_I2C_I2FDR_IC(x)                         (((x)&0x3F))
+
+#define MCF532x_I2C_I2CR_IEN    (0x80)	// I2C enable
+#define MCF532x_I2C_I2CR_IIEN   (0x40)  // interrupt enable
+#define MCF532x_I2C_I2CR_MSTA   (0x20)  // master/slave mode
+#define MCF532x_I2C_I2CR_MTX    (0x10)  // transmit/receive mode
+#define MCF532x_I2C_I2CR_TXAK   (0x08)  // transmit acknowledge enable
+#define MCF532x_I2C_I2CR_RSTA   (0x04)  // repeat start
+
+#define MCF532x_I2C_I2SR_ICF    (0x80)  // data transfer bit
+#define MCF532x_I2C_I2SR_IAAS   (0x40)  // I2C addressed as a slave
+#define MCF532x_I2C_I2SR_IBB    (0x20)  // I2C bus busy
+#define MCF532x_I2C_I2SR_IAL    (0x10)  // aribitration lost
+#define MCF532x_I2C_I2SR_SRW    (0x04)  // slave read/write
+#define MCF532x_I2C_I2SR_IIF    (0x02)  // I2C interrupt
+#define MCF532x_I2C_I2SR_RXAK   (0x01)  // received acknowledge
+
+#define MCF532x_PAR_FECI2C	(volatile u8 *) (0xFC0A4053)
+
+
+/*
+ *	The M5329EVB board needs a help getting its devices initialized 
+ *	at kernel start time if dBUG doesn't set it up (for example 
+ *	it is not used), so we need to do it manually.
+ */
+#ifdef __ASSEMBLER__
+.macro m5329EVB_setup
+	movel	#0xFC098000, %a7
+	movel	#0x0, (%a7)
+#define CORE_SRAM	0x80000000	
+#define CORE_SRAM_SIZE	0x8000
+	movel	#CORE_SRAM, %d0
+	addl	#0x221, %d0
+	movec	%d0,%RAMBAR1
+	movel	#CORE_SRAM, %sp
+	addl	#CORE_SRAM_SIZE, %sp
+	jsr	sysinit
+.endm
+#define	PLATFORM_SETUP	m5329EVB_setup
+
+#endif /* __ASSEMBLER__ */
+
+/*********************************************************************
+ *
+ * Chip Configuration Module (CCM)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_CCM_CCR               MCF_REG16(0xFC0A0004)
+#define MCF_CCM_RCON              MCF_REG16(0xFC0A0008)
+#define MCF_CCM_CIR               MCF_REG16(0xFC0A000A)
+#define MCF_CCM_MISCCR            MCF_REG16(0xFC0A0010)
+#define MCF_CCM_CDR               MCF_REG16(0xFC0A0012)
+#define MCF_CCM_UHCSR             MCF_REG16(0xFC0A0014)
+#define MCF_CCM_UOCSR             MCF_REG16(0xFC0A0016)
+
+/* Bit definitions and macros for MCF_CCM_CCR */
+#define MCF_CCM_CCR_RESERVED      (0x0001)
+#define MCF_CCM_CCR_PLL_MODE      (0x0003)
+#define MCF_CCM_CCR_OSC_MODE      (0x0005)
+#define MCF_CCM_CCR_BOOTPS(x)     (((x)&0x0003)<<3|0x0001)
+#define MCF_CCM_CCR_LOAD          (0x0021)
+#define MCF_CCM_CCR_LIMP          (0x0041)
+#define MCF_CCM_CCR_CSC(x)        (((x)&0x0003)<<8|0x0001)
+
+/* Bit definitions and macros for MCF_CCM_RCON */
+#define MCF_CCM_RCON_RESERVED     (0x0001)
+#define MCF_CCM_RCON_PLL_MODE     (0x0003)
+#define MCF_CCM_RCON_OSC_MODE     (0x0005)
+#define MCF_CCM_RCON_BOOTPS(x)    (((x)&0x0003)<<3|0x0001)
+#define MCF_CCM_RCON_LOAD         (0x0021)
+#define MCF_CCM_RCON_LIMP         (0x0041)
+#define MCF_CCM_RCON_CSC(x)       (((x)&0x0003)<<8|0x0001)
+
+/* Bit definitions and macros for MCF_CCM_CIR */
+#define MCF_CCM_CIR_PRN(x)        (((x)&0x003F)<<0)
+#define MCF_CCM_CIR_PIN(x)        (((x)&0x03FF)<<6)
+
+/* Bit definitions and macros for MCF_CCM_MISCCR */
+#define MCF_CCM_MISCCR_USBSRC     (0x0001)
+#define MCF_CCM_MISCCR_USBDIV     (0x0002)
+#define MCF_CCM_MISCCR_SSI_SRC    (0x0010)
+#define MCF_CCM_MISCCR_TIM_DMA   (0x0020)
+#define MCF_CCM_MISCCR_SSI_PUS    (0x0040)
+#define MCF_CCM_MISCCR_SSI_PUE    (0x0080)
+#define MCF_CCM_MISCCR_LCD_CHEN   (0x0100)
+#define MCF_CCM_MISCCR_LIMP       (0x1000)
+#define MCF_CCM_MISCCR_PLL_LOCK   (0x2000)
+
+/* Bit definitions and macros for MCF_CCM_CDR */
+#define MCF_CCM_CDR_SSIDIV(x)     (((x)&0x000F)<<0)
+#define MCF_CCM_CDR_LPDIV(x)      (((x)&0x000F)<<8)
+
+/* Bit definitions and macros for MCF_CCM_UHCSR */
+#define MCF_CCM_UHCSR_XPDE        (0x0001)
+#define MCF_CCM_UHCSR_UHMIE       (0x0002)
+#define MCF_CCM_UHCSR_WKUP        (0x0004)
+#define MCF_CCM_UHCSR_PORTIND(x)  (((x)&0x0003)<<14)
+
+/* Bit definitions and macros for MCF_CCM_UOCSR */
+#define MCF_CCM_UOCSR_XPDE        (0x0001)
+#define MCF_CCM_UOCSR_UOMIE       (0x0002)
+#define MCF_CCM_UOCSR_WKUP        (0x0004)
+#define MCF_CCM_UOCSR_PWRFLT      (0x0008)
+#define MCF_CCM_UOCSR_SEND        (0x0010)
+#define MCF_CCM_UOCSR_VVLD        (0x0020)
+#define MCF_CCM_UOCSR_BVLD        (0x0040)
+#define MCF_CCM_UOCSR_AVLD        (0x0080)
+#define MCF_CCM_UOCSR_DPPU        (0x0100)
+#define MCF_CCM_UOCSR_DCR_VBUS    (0x0200)
+#define MCF_CCM_UOCSR_CRG_VBUS    (0x0400)
+#define MCF_CCM_UOCSR_DRV_VBUS    (0x0800)
+#define MCF_CCM_UOCSR_DMPD        (0x1000)
+#define MCF_CCM_UOCSR_DPPD        (0x2000)
+#define MCF_CCM_UOCSR_PORTIND(x)  (((x)&0x0003)<<14)
+
+/*********************************************************************
+ *
+ * DMA Timers (DTIM)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_DTIM0_DTMR           MCF_REG16(0xFC070000)
+#define MCF_DTIM0_DTXMR          MCF_REG08(0xFC070002)
+#define MCF_DTIM0_DTER           MCF_REG08(0xFC070003)
+#define MCF_DTIM0_DTRR           MCF_REG32(0xFC070004)
+#define MCF_DTIM0_DTCR           MCF_REG32(0xFC070008)
+#define MCF_DTIM0_DTCN           MCF_REG32(0xFC07000C)
+#define MCF_DTIM1_DTMR           MCF_REG16(0xFC074000)
+#define MCF_DTIM1_DTXMR          MCF_REG08(0xFC074002)
+#define MCF_DTIM1_DTER           MCF_REG08(0xFC074003)
+#define MCF_DTIM1_DTRR           MCF_REG32(0xFC074004)
+#define MCF_DTIM1_DTCR           MCF_REG32(0xFC074008)
+#define MCF_DTIM1_DTCN           MCF_REG32(0xFC07400C)
+#define MCF_DTIM2_DTMR           MCF_REG16(0xFC078000)
+#define MCF_DTIM2_DTXMR          MCF_REG08(0xFC078002)
+#define MCF_DTIM2_DTER           MCF_REG08(0xFC078003)
+#define MCF_DTIM2_DTRR           MCF_REG32(0xFC078004)
+#define MCF_DTIM2_DTCR           MCF_REG32(0xFC078008)
+#define MCF_DTIM2_DTCN           MCF_REG32(0xFC07800C)
+#define MCF_DTIM3_DTMR           MCF_REG16(0xFC07C000)
+#define MCF_DTIM3_DTXMR          MCF_REG08(0xFC07C002)
+#define MCF_DTIM3_DTER           MCF_REG08(0xFC07C003)
+#define MCF_DTIM3_DTRR           MCF_REG32(0xFC07C004)
+#define MCF_DTIM3_DTCR           MCF_REG32(0xFC07C008)
+#define MCF_DTIM3_DTCN           MCF_REG32(0xFC07C00C)
+#define MCF_DTIM_DTMR(x)         MCF_REG16(0xFC070000+((x)*0x4000))
+#define MCF_DTIM_DTXMR(x)        MCF_REG08(0xFC070002+((x)*0x4000))
+#define MCF_DTIM_DTER(x)         MCF_REG08(0xFC070003+((x)*0x4000))
+#define MCF_DTIM_DTRR(x)         MCF_REG32(0xFC070004+((x)*0x4000))
+#define MCF_DTIM_DTCR(x)         MCF_REG32(0xFC070008+((x)*0x4000))
+#define MCF_DTIM_DTCN(x)         MCF_REG32(0xFC07000C+((x)*0x4000))
+
+/* Bit definitions and macros for MCF_DTIM_DTMR */
+#define MCF_DTIM_DTMR_RST        (0x0001)
+#define MCF_DTIM_DTMR_CLK(x)     (((x)&0x0003)<<1)
+#define MCF_DTIM_DTMR_FRR        (0x0008)
+#define MCF_DTIM_DTMR_ORRI       (0x0010)
+#define MCF_DTIM_DTMR_OM         (0x0020)
+#define MCF_DTIM_DTMR_CE(x)      (((x)&0x0003)<<6)
+#define MCF_DTIM_DTMR_PS(x)      (((x)&0x00FF)<<8)
+#define MCF_DTIM_DTMR_CE_ANY     (0x00C0)
+#define MCF_DTIM_DTMR_CE_FALL    (0x0080)
+#define MCF_DTIM_DTMR_CE_RISE    (0x0040)
+#define MCF_DTIM_DTMR_CE_NONE    (0x0000)
+#define MCF_DTIM_DTMR_CLK_DTIN   (0x0006)
+#define MCF_DTIM_DTMR_CLK_DIV16  (0x0004)
+#define MCF_DTIM_DTMR_CLK_DIV1   (0x0002)
+#define MCF_DTIM_DTMR_CLK_STOP   (0x0000)
+
+/* Bit definitions and macros for MCF_DTIM_DTXMR */
+#define MCF_DTIM_DTXMR_MODE16    (0x01)
+#define MCF_DTIM_DTXMR_DMAEN     (0x80)
+
+/* Bit definitions and macros for MCF_DTIM_DTER */
+#define MCF_DTIM_DTER_CAP        (0x01)
+#define MCF_DTIM_DTER_REF        (0x02)
+
+/* Bit definitions and macros for MCF_DTIM_DTRR */
+#define MCF_DTIM_DTRR_REF(x)     (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_DTIM_DTCR */
+#define MCF_DTIM_DTCR_CAP(x)     (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_DTIM_DTCN */
+#define MCF_DTIM_DTCN_CNT(x)     (((x)&0xFFFFFFFF)<<0)
+
+/*********************************************************************
+ *
+ * FlexBus Chip Selects (FBCS)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_FBCS0_CSAR		MCF_REG32(0xFC008000)
+#define MCF_FBCS0_CSMR		MCF_REG32(0xFC008004)
+#define MCF_FBCS0_CSCR		MCF_REG32(0xFC008008)
+#define MCF_FBCS1_CSAR		MCF_REG32(0xFC00800C)
+#define MCF_FBCS1_CSMR		MCF_REG32(0xFC008010)
+#define MCF_FBCS1_CSCR		MCF_REG32(0xFC008014)
+#define MCF_FBCS2_CSAR		MCF_REG32(0xFC008018)
+#define MCF_FBCS2_CSMR		MCF_REG32(0xFC00801C)
+#define MCF_FBCS2_CSCR		MCF_REG32(0xFC008020)
+#define MCF_FBCS3_CSAR		MCF_REG32(0xFC008024)
+#define MCF_FBCS3_CSMR		MCF_REG32(0xFC008028)
+#define MCF_FBCS3_CSCR		MCF_REG32(0xFC00802C)
+#define MCF_FBCS4_CSAR		MCF_REG32(0xFC008030)
+#define MCF_FBCS4_CSMR		MCF_REG32(0xFC008034)
+#define MCF_FBCS4_CSCR		MCF_REG32(0xFC008038)
+#define MCF_FBCS5_CSAR		MCF_REG32(0xFC00803C)
+#define MCF_FBCS5_CSMR		MCF_REG32(0xFC008040)
+#define MCF_FBCS5_CSCR		MCF_REG32(0xFC008044)
+#define MCF_FBCS_CSAR(x)	MCF_REG32(0xFC008000+((x)*0x00C))
+#define MCF_FBCS_CSMR(x)	MCF_REG32(0xFC008004+((x)*0x00C))
+#define MCF_FBCS_CSCR(x)	MCF_REG32(0xFC008008+((x)*0x00C))
+
+/* Bit definitions and macros for MCF_FBCS_CSAR */
+#define MCF_FBCS_CSAR_BA(x)	((x)&0xFFFF0000)
+
+/* Bit definitions and macros for MCF_FBCS_CSMR */
+#define MCF_FBCS_CSMR_V		(0x00000001)
+#define MCF_FBCS_CSMR_WP	(0x00000100)
+#define MCF_FBCS_CSMR_BAM(x)	(((x)&0x0000FFFF)<<16)
+#define MCF_FBCS_CSMR_BAM_4G	(0xFFFF0000)
+#define MCF_FBCS_CSMR_BAM_2G	(0x7FFF0000)
+#define MCF_FBCS_CSMR_BAM_1G	(0x3FFF0000)
+#define MCF_FBCS_CSMR_BAM_1024M	(0x3FFF0000)
+#define MCF_FBCS_CSMR_BAM_512M	(0x1FFF0000)
+#define MCF_FBCS_CSMR_BAM_256M	(0x0FFF0000)
+#define MCF_FBCS_CSMR_BAM_128M	(0x07FF0000)
+#define MCF_FBCS_CSMR_BAM_64M	(0x03FF0000)
+#define MCF_FBCS_CSMR_BAM_32M	(0x01FF0000)
+#define MCF_FBCS_CSMR_BAM_16M	(0x00FF0000)
+#define MCF_FBCS_CSMR_BAM_8M	(0x007F0000)
+#define MCF_FBCS_CSMR_BAM_4M	(0x003F0000)
+#define MCF_FBCS_CSMR_BAM_2M	(0x001F0000)
+#define MCF_FBCS_CSMR_BAM_1M	(0x000F0000)
+#define MCF_FBCS_CSMR_BAM_1024K	(0x000F0000)
+#define MCF_FBCS_CSMR_BAM_512K	(0x00070000)
+#define MCF_FBCS_CSMR_BAM_256K	(0x00030000)
+#define MCF_FBCS_CSMR_BAM_128K	(0x00010000)
+#define MCF_FBCS_CSMR_BAM_64K	(0x00000000)
+
+/* Bit definitions and macros for MCF_FBCS_CSCR */
+#define MCF_FBCS_CSCR_BSTW	(0x00000008)
+#define MCF_FBCS_CSCR_BSTR	(0x00000010)
+#define MCF_FBCS_CSCR_BEM	(0x00000020)
+#define MCF_FBCS_CSCR_PS(x)	(((x)&0x00000003)<<6)
+#define MCF_FBCS_CSCR_AA	(0x00000100)
+#define MCF_FBCS_CSCR_SBM	(0x00000200)
+#define MCF_FBCS_CSCR_WS(x)	(((x)&0x0000003F)<<10)
+#define MCF_FBCS_CSCR_WRAH(x)	(((x)&0x00000003)<<16)
+#define MCF_FBCS_CSCR_RDAH(x)	(((x)&0x00000003)<<18)
+#define MCF_FBCS_CSCR_ASET(x)	(((x)&0x00000003)<<20)
+#define MCF_FBCS_CSCR_SWSEN	(0x00800000)
+#define MCF_FBCS_CSCR_SWS(x)	(((x)&0x0000003F)<<26)
+#define MCF_FBCS_CSCR_PS_8	(0x0040)
+#define MCF_FBCS_CSCR_PS_16	(0x0080)
+#define MCF_FBCS_CSCR_PS_32	(0x0000)
+
+/*********************************************************************
+ *
+ * General Purpose I/O (GPIO)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_GPIO_PODR_FECH		MCF_REG08(0xFC0A4000)
+#define MCF_GPIO_PODR_FECL		MCF_REG08(0xFC0A4001)
+#define MCF_GPIO_PODR_SSI		MCF_REG08(0xFC0A4002)
+#define MCF_GPIO_PODR_BUSCTL		MCF_REG08(0xFC0A4003)
+#define MCF_GPIO_PODR_BE		MCF_REG08(0xFC0A4004)
+#define MCF_GPIO_PODR_CS		MCF_REG08(0xFC0A4005)
+#define MCF_GPIO_PODR_PWM		MCF_REG08(0xFC0A4006)
+#define MCF_GPIO_PODR_FECI2C		MCF_REG08(0xFC0A4007)
+#define MCF_GPIO_PODR_UART		MCF_REG08(0xFC0A4009)
+#define MCF_GPIO_PODR_QSPI		MCF_REG08(0xFC0A400A)
+#define MCF_GPIO_PODR_TIMER		MCF_REG08(0xFC0A400B)
+#define MCF_GPIO_PODR_LCDDATAH		MCF_REG08(0xFC0A400D)
+#define MCF_GPIO_PODR_LCDDATAM		MCF_REG08(0xFC0A400E)
+#define MCF_GPIO_PODR_LCDDATAL		MCF_REG08(0xFC0A400F)
+#define MCF_GPIO_PODR_LCDCTLH		MCF_REG08(0xFC0A4010)
+#define MCF_GPIO_PODR_LCDCTLL		MCF_REG08(0xFC0A4011)
+#define MCF_GPIO_PDDR_FECH		MCF_REG08(0xFC0A4014)
+#define MCF_GPIO_PDDR_FECL		MCF_REG08(0xFC0A4015)
+#define MCF_GPIO_PDDR_SSI		MCF_REG08(0xFC0A4016)
+#define MCF_GPIO_PDDR_BUSCTL		MCF_REG08(0xFC0A4017)
+#define MCF_GPIO_PDDR_BE		MCF_REG08(0xFC0A4018)
+#define MCF_GPIO_PDDR_CS		MCF_REG08(0xFC0A4019)
+#define MCF_GPIO_PDDR_PWM		MCF_REG08(0xFC0A401A)
+#define MCF_GPIO_PDDR_FECI2C		MCF_REG08(0xFC0A401B)
+#define MCF_GPIO_PDDR_UART		MCF_REG08(0xFC0A401C)
+#define MCF_GPIO_PDDR_QSPI		MCF_REG08(0xFC0A401E)
+#define MCF_GPIO_PDDR_TIMER		MCF_REG08(0xFC0A401F)
+#define MCF_GPIO_PDDR_LCDDATAH		MCF_REG08(0xFC0A4021)
+#define MCF_GPIO_PDDR_LCDDATAM		MCF_REG08(0xFC0A4022)
+#define MCF_GPIO_PDDR_LCDDATAL		MCF_REG08(0xFC0A4023)
+#define MCF_GPIO_PDDR_LCDCTLH		MCF_REG08(0xFC0A4024)
+#define MCF_GPIO_PDDR_LCDCTLL		MCF_REG08(0xFC0A4025)
+#define MCF_GPIO_PPDSDR_FECH		MCF_REG08(0xFC0A4028)
+#define MCF_GPIO_PPDSDR_FECL		MCF_REG08(0xFC0A4029)
+#define MCF_GPIO_PPDSDR_SSI		MCF_REG08(0xFC0A402A)
+#define MCF_GPIO_PPDSDR_BUSCTL		MCF_REG08(0xFC0A402B)
+#define MCF_GPIO_PPDSDR_BE		MCF_REG08(0xFC0A402C)
+#define MCF_GPIO_PPDSDR_CS		MCF_REG08(0xFC0A402D)
+#define MCF_GPIO_PPDSDR_PWM		MCF_REG08(0xFC0A402E)
+#define MCF_GPIO_PPDSDR_FECI2C		MCF_REG08(0xFC0A402F)
+#define MCF_GPIO_PPDSDR_UART		MCF_REG08(0xFC0A4031)
+#define MCF_GPIO_PPDSDR_QSPI		MCF_REG08(0xFC0A4032)
+#define MCF_GPIO_PPDSDR_TIMER		MCF_REG08(0xFC0A4033)
+#define MCF_GPIO_PPDSDR_LCDDATAH	MCF_REG08(0xFC0A4035)
+#define MCF_GPIO_PPDSDR_LCDDATAM	MCF_REG08(0xFC0A4036)
+#define MCF_GPIO_PPDSDR_LCDDATAL	MCF_REG08(0xFC0A4037)
+#define MCF_GPIO_PPDSDR_LCDCTLH		MCF_REG08(0xFC0A4038)
+#define MCF_GPIO_PPDSDR_LCDCTLL		MCF_REG08(0xFC0A4039)
+#define MCF_GPIO_PCLRR_FECH		MCF_REG08(0xFC0A403C)
+#define MCF_GPIO_PCLRR_FECL		MCF_REG08(0xFC0A403D)
+#define MCF_GPIO_PCLRR_SSI		MCF_REG08(0xFC0A403E)
+#define MCF_GPIO_PCLRR_BUSCTL		MCF_REG08(0xFC0A403F)
+#define MCF_GPIO_PCLRR_BE		MCF_REG08(0xFC0A4040)
+#define MCF_GPIO_PCLRR_CS		MCF_REG08(0xFC0A4041)
+#define MCF_GPIO_PCLRR_PWM		MCF_REG08(0xFC0A4042)
+#define MCF_GPIO_PCLRR_FECI2C		MCF_REG08(0xFC0A4043)
+#define MCF_GPIO_PCLRR_UART		MCF_REG08(0xFC0A4045)
+#define MCF_GPIO_PCLRR_QSPI		MCF_REG08(0xFC0A4046)
+#define MCF_GPIO_PCLRR_TIMER		MCF_REG08(0xFC0A4047)
+#define MCF_GPIO_PCLRR_LCDDATAH		MCF_REG08(0xFC0A4049)
+#define MCF_GPIO_PCLRR_LCDDATAM		MCF_REG08(0xFC0A404A)
+#define MCF_GPIO_PCLRR_LCDDATAL		MCF_REG08(0xFC0A404B)
+#define MCF_GPIO_PCLRR_LCDCTLH		MCF_REG08(0xFC0A404C)
+#define MCF_GPIO_PCLRR_LCDCTLL		MCF_REG08(0xFC0A404D)
+#define MCF_GPIO_PAR_FEC		MCF_REG08(0xFC0A4050)
+#define MCF_GPIO_PAR_PWM		MCF_REG08(0xFC0A4051)
+#define MCF_GPIO_PAR_BUSCTL		MCF_REG08(0xFC0A4052)
+#define MCF_GPIO_PAR_FECI2C		MCF_REG08(0xFC0A4053)
+#define MCF_GPIO_PAR_BE			MCF_REG08(0xFC0A4054)
+#define MCF_GPIO_PAR_CS			MCF_REG08(0xFC0A4055)
+#define MCF_GPIO_PAR_SSI		MCF_REG16(0xFC0A4056)
+#define MCF_GPIO_PAR_UART		MCF_REG16(0xFC0A4058)
+#define MCF_GPIO_PAR_QSPI		MCF_REG16(0xFC0A405A)
+#define MCF_GPIO_PAR_TIMER		MCF_REG08(0xFC0A405C)
+#define MCF_GPIO_PAR_LCDDATA		MCF_REG08(0xFC0A405D)
+#define MCF_GPIO_PAR_LCDCTL		MCF_REG16(0xFC0A405E)
+#define MCF_GPIO_PAR_IRQ		MCF_REG16(0xFC0A4060)
+#define MCF_GPIO_MSCR_FLEXBUS		MCF_REG08(0xFC0A4064)
+#define MCF_GPIO_MSCR_SDRAM		MCF_REG08(0xFC0A4065)
+#define MCF_GPIO_DSCR_I2C		MCF_REG08(0xFC0A4068)
+#define MCF_GPIO_DSCR_PWM		MCF_REG08(0xFC0A4069)
+#define MCF_GPIO_DSCR_FEC		MCF_REG08(0xFC0A406A)
+#define MCF_GPIO_DSCR_UART		MCF_REG08(0xFC0A406B)
+#define MCF_GPIO_DSCR_QSPI		MCF_REG08(0xFC0A406C)
+#define MCF_GPIO_DSCR_TIMER		MCF_REG08(0xFC0A406D)
+#define MCF_GPIO_DSCR_SSI		MCF_REG08(0xFC0A406E)
+#define MCF_GPIO_DSCR_LCD		MCF_REG08(0xFC0A406F)
+#define MCF_GPIO_DSCR_DEBUG		MCF_REG08(0xFC0A4070)
+#define MCF_GPIO_DSCR_CLKRST		MCF_REG08(0xFC0A4071)
+#define MCF_GPIO_DSCR_IRQ		MCF_REG08(0xFC0A4072)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_FECH */
+#define MCF_GPIO_PODR_FECH_PODR_FECH0              (0x01)
+#define MCF_GPIO_PODR_FECH_PODR_FECH1              (0x02)
+#define MCF_GPIO_PODR_FECH_PODR_FECH2              (0x04)
+#define MCF_GPIO_PODR_FECH_PODR_FECH3              (0x08)
+#define MCF_GPIO_PODR_FECH_PODR_FECH4              (0x10)
+#define MCF_GPIO_PODR_FECH_PODR_FECH5              (0x20)
+#define MCF_GPIO_PODR_FECH_PODR_FECH6              (0x40)
+#define MCF_GPIO_PODR_FECH_PODR_FECH7              (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_FECL */
+#define MCF_GPIO_PODR_FECL_PODR_FECL0              (0x01)
+#define MCF_GPIO_PODR_FECL_PODR_FECL1              (0x02)
+#define MCF_GPIO_PODR_FECL_PODR_FECL2              (0x04)
+#define MCF_GPIO_PODR_FECL_PODR_FECL3              (0x08)
+#define MCF_GPIO_PODR_FECL_PODR_FECL4              (0x10)
+#define MCF_GPIO_PODR_FECL_PODR_FECL5              (0x20)
+#define MCF_GPIO_PODR_FECL_PODR_FECL6              (0x40)
+#define MCF_GPIO_PODR_FECL_PODR_FECL7              (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_SSI */
+#define MCF_GPIO_PODR_SSI_PODR_SSI0                (0x01)
+#define MCF_GPIO_PODR_SSI_PODR_SSI1                (0x02)
+#define MCF_GPIO_PODR_SSI_PODR_SSI2                (0x04)
+#define MCF_GPIO_PODR_SSI_PODR_SSI3                (0x08)
+#define MCF_GPIO_PODR_SSI_PODR_SSI4                (0x10)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_BUSCTL */
+#define MCF_GPIO_PODR_BUSCTL_POSDR_BUSCTL0         (0x01)
+#define MCF_GPIO_PODR_BUSCTL_PODR_BUSCTL1          (0x02)
+#define MCF_GPIO_PODR_BUSCTL_PODR_BUSCTL2          (0x04)
+#define MCF_GPIO_PODR_BUSCTL_PODR_BUSCTL3          (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_BE */
+#define MCF_GPIO_PODR_BE_PODR_BE0                  (0x01)
+#define MCF_GPIO_PODR_BE_PODR_BE1                  (0x02)
+#define MCF_GPIO_PODR_BE_PODR_BE2                  (0x04)
+#define MCF_GPIO_PODR_BE_PODR_BE3                  (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_CS */
+#define MCF_GPIO_PODR_CS_PODR_CS1                  (0x02)
+#define MCF_GPIO_PODR_CS_PODR_CS2                  (0x04)
+#define MCF_GPIO_PODR_CS_PODR_CS3                  (0x08)
+#define MCF_GPIO_PODR_CS_PODR_CS4                  (0x10)
+#define MCF_GPIO_PODR_CS_PODR_CS5                  (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_PWM */
+#define MCF_GPIO_PODR_PWM_PODR_PWM2                (0x04)
+#define MCF_GPIO_PODR_PWM_PODR_PWM3                (0x08)
+#define MCF_GPIO_PODR_PWM_PODR_PWM4                (0x10)
+#define MCF_GPIO_PODR_PWM_PODR_PWM5                (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_FECI2C */
+#define MCF_GPIO_PODR_FECI2C_PODR_FECI2C0          (0x01)
+#define MCF_GPIO_PODR_FECI2C_PODR_FECI2C1          (0x02)
+#define MCF_GPIO_PODR_FECI2C_PODR_FECI2C2          (0x04)
+#define MCF_GPIO_PODR_FECI2C_PODR_FECI2C3          (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_UART */
+#define MCF_GPIO_PODR_UART_PODR_UART0              (0x01)
+#define MCF_GPIO_PODR_UART_PODR_UART1              (0x02)
+#define MCF_GPIO_PODR_UART_PODR_UART2              (0x04)
+#define MCF_GPIO_PODR_UART_PODR_UART3              (0x08)
+#define MCF_GPIO_PODR_UART_PODR_UART4              (0x10)
+#define MCF_GPIO_PODR_UART_PODR_UART5              (0x20)
+#define MCF_GPIO_PODR_UART_PODR_UART6              (0x40)
+#define MCF_GPIO_PODR_UART_PODR_UART7              (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_QSPI */
+#define MCF_GPIO_PODR_QSPI_PODR_QSPI0              (0x01)
+#define MCF_GPIO_PODR_QSPI_PODR_QSPI1              (0x02)
+#define MCF_GPIO_PODR_QSPI_PODR_QSPI2              (0x04)
+#define MCF_GPIO_PODR_QSPI_PODR_QSPI3              (0x08)
+#define MCF_GPIO_PODR_QSPI_PODR_QSPI4              (0x10)
+#define MCF_GPIO_PODR_QSPI_PODR_QSPI5              (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_TIMER */
+#define MCF_GPIO_PODR_TIMER_PODR_TIMER0            (0x01)
+#define MCF_GPIO_PODR_TIMER_PODR_TIMER1            (0x02)
+#define MCF_GPIO_PODR_TIMER_PODR_TIMER2            (0x04)
+#define MCF_GPIO_PODR_TIMER_PODR_TIMER3            (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_LCDDATAH */
+#define MCF_GPIO_PODR_LCDDATAH_PODR_LCDDATAH0      (0x01)
+#define MCF_GPIO_PODR_LCDDATAH_PODR_LCDDATAH1      (0x02)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_LCDDATAM */
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM0      (0x01)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM1      (0x02)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM2      (0x04)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM3      (0x08)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM4      (0x10)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM5      (0x20)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM6      (0x40)
+#define MCF_GPIO_PODR_LCDDATAM_PODR_LCDDATAM7      (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_LCDDATAL */
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL0      (0x01)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL1      (0x02)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL2      (0x04)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL3      (0x08)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL4      (0x10)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL5      (0x20)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL6      (0x40)
+#define MCF_GPIO_PODR_LCDDATAL_PODR_LCDDATAL7      (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_LCDCTLH */
+#define MCF_GPIO_PODR_LCDCTLH_PODR_LCDCTLH0        (0x01)
+
+/* Bit definitions and macros for MCF_GPIO_PODR_LCDCTLL */
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL0        (0x01)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL1        (0x02)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL2        (0x04)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL3        (0x08)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL4        (0x10)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL5        (0x20)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL6        (0x40)
+#define MCF_GPIO_PODR_LCDCTLL_PODR_LCDCTLL7        (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_FECH */
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH0              (0x01)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH1              (0x02)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH2              (0x04)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH3              (0x08)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH4              (0x10)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH5              (0x20)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH6              (0x40)
+#define MCF_GPIO_PDDR_FECH_PDDR_FECH7              (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_FECL */
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL0              (0x01)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL1              (0x02)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL2              (0x04)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL3              (0x08)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL4              (0x10)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL5              (0x20)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL6              (0x40)
+#define MCF_GPIO_PDDR_FECL_PDDR_FECL7              (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_SSI */
+#define MCF_GPIO_PDDR_SSI_PDDR_SSI0                (0x01)
+#define MCF_GPIO_PDDR_SSI_PDDR_SSI1                (0x02)
+#define MCF_GPIO_PDDR_SSI_PDDR_SSI2                (0x04)
+#define MCF_GPIO_PDDR_SSI_PDDR_SSI3                (0x08)
+#define MCF_GPIO_PDDR_SSI_PDDR_SSI4                (0x10)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_BUSCTL */
+#define MCF_GPIO_PDDR_BUSCTL_POSDR_BUSCTL0         (0x01)
+#define MCF_GPIO_PDDR_BUSCTL_PDDR_BUSCTL1          (0x02)
+#define MCF_GPIO_PDDR_BUSCTL_PDDR_BUSCTL2          (0x04)
+#define MCF_GPIO_PDDR_BUSCTL_PDDR_BUSCTL3          (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_BE */
+#define MCF_GPIO_PDDR_BE_PDDR_BE0                  (0x01)
+#define MCF_GPIO_PDDR_BE_PDDR_BE1                  (0x02)
+#define MCF_GPIO_PDDR_BE_PDDR_BE2                  (0x04)
+#define MCF_GPIO_PDDR_BE_PDDR_BE3                  (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_CS */
+#define MCF_GPIO_PDDR_CS_PDDR_CS1                  (0x02)
+#define MCF_GPIO_PDDR_CS_PDDR_CS2                  (0x04)
+#define MCF_GPIO_PDDR_CS_PDDR_CS3                  (0x08)
+#define MCF_GPIO_PDDR_CS_PDDR_CS4                  (0x10)
+#define MCF_GPIO_PDDR_CS_PDDR_CS5                  (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_PWM */
+#define MCF_GPIO_PDDR_PWM_PDDR_PWM2                (0x04)
+#define MCF_GPIO_PDDR_PWM_PDDR_PWM3                (0x08)
+#define MCF_GPIO_PDDR_PWM_PDDR_PWM4                (0x10)
+#define MCF_GPIO_PDDR_PWM_PDDR_PWM5                (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_FECI2C */
+#define MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C0          (0x01)
+#define MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C1          (0x02)
+#define MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C2          (0x04)
+#define MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C3          (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_UART */
+#define MCF_GPIO_PDDR_UART_PDDR_UART0              (0x01)
+#define MCF_GPIO_PDDR_UART_PDDR_UART1              (0x02)
+#define MCF_GPIO_PDDR_UART_PDDR_UART2              (0x04)
+#define MCF_GPIO_PDDR_UART_PDDR_UART3              (0x08)
+#define MCF_GPIO_PDDR_UART_PDDR_UART4              (0x10)
+#define MCF_GPIO_PDDR_UART_PDDR_UART5              (0x20)
+#define MCF_GPIO_PDDR_UART_PDDR_UART6              (0x40)
+#define MCF_GPIO_PDDR_UART_PDDR_UART7              (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_QSPI */
+#define MCF_GPIO_PDDR_QSPI_PDDR_QSPI0              (0x01)
+#define MCF_GPIO_PDDR_QSPI_PDDR_QSPI1              (0x02)
+#define MCF_GPIO_PDDR_QSPI_PDDR_QSPI2              (0x04)
+#define MCF_GPIO_PDDR_QSPI_PDDR_QSPI3              (0x08)
+#define MCF_GPIO_PDDR_QSPI_PDDR_QSPI4              (0x10)
+#define MCF_GPIO_PDDR_QSPI_PDDR_QSPI5              (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_TIMER */
+#define MCF_GPIO_PDDR_TIMER_PDDR_TIMER0            (0x01)
+#define MCF_GPIO_PDDR_TIMER_PDDR_TIMER1            (0x02)
+#define MCF_GPIO_PDDR_TIMER_PDDR_TIMER2            (0x04)
+#define MCF_GPIO_PDDR_TIMER_PDDR_TIMER3            (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_LCDDATAH */
+#define MCF_GPIO_PDDR_LCDDATAH_PDDR_LCDDATAH0      (0x01)
+#define MCF_GPIO_PDDR_LCDDATAH_PDDR_LCDDATAH1      (0x02)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_LCDDATAM */
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM0      (0x01)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM1      (0x02)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM2      (0x04)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM3      (0x08)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM4      (0x10)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM5      (0x20)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM6      (0x40)
+#define MCF_GPIO_PDDR_LCDDATAM_PDDR_LCDDATAM7      (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_LCDDATAL */
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL0      (0x01)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL1      (0x02)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL2      (0x04)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL3      (0x08)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL4      (0x10)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL5      (0x20)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL6      (0x40)
+#define MCF_GPIO_PDDR_LCDDATAL_PDDR_LCDDATAL7      (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_LCDCTLH */
+#define MCF_GPIO_PDDR_LCDCTLH_PDDR_LCDCTLH0        (0x01)
+
+/* Bit definitions and macros for MCF_GPIO_PDDR_LCDCTLL */
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL0        (0x01)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL1        (0x02)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL2        (0x04)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL3        (0x08)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL4        (0x10)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL5        (0x20)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL6        (0x40)
+#define MCF_GPIO_PDDR_LCDCTLL_PDDR_LCDCTLL7        (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_FECH */
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH0          (0x01)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH1          (0x02)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH2          (0x04)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH3          (0x08)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH4          (0x10)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH5          (0x20)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH6          (0x40)
+#define MCF_GPIO_PPDSDR_FECH_PPDSDR_FECH7          (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_FECL */
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL0          (0x01)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL1          (0x02)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL2          (0x04)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL3          (0x08)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL4          (0x10)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL5          (0x20)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL6          (0x40)
+#define MCF_GPIO_PPDSDR_FECL_PPDSDR_FECL7          (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_SSI */
+#define MCF_GPIO_PPDSDR_SSI_PPDSDR_SSI0            (0x01)
+#define MCF_GPIO_PPDSDR_SSI_PPDSDR_SSI1            (0x02)
+#define MCF_GPIO_PPDSDR_SSI_PPDSDR_SSI2            (0x04)
+#define MCF_GPIO_PPDSDR_SSI_PPDSDR_SSI3            (0x08)
+#define MCF_GPIO_PPDSDR_SSI_PPDSDR_SSI4            (0x10)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_BUSCTL */
+#define MCF_GPIO_PPDSDR_BUSCTL_POSDR_BUSCTL0       (0x01)
+#define MCF_GPIO_PPDSDR_BUSCTL_PPDSDR_BUSCTL1      (0x02)
+#define MCF_GPIO_PPDSDR_BUSCTL_PPDSDR_BUSCTL2      (0x04)
+#define MCF_GPIO_PPDSDR_BUSCTL_PPDSDR_BUSCTL3      (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_BE */
+#define MCF_GPIO_PPDSDR_BE_PPDSDR_BE0              (0x01)
+#define MCF_GPIO_PPDSDR_BE_PPDSDR_BE1              (0x02)
+#define MCF_GPIO_PPDSDR_BE_PPDSDR_BE2              (0x04)
+#define MCF_GPIO_PPDSDR_BE_PPDSDR_BE3              (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_CS */
+#define MCF_GPIO_PPDSDR_CS_PPDSDR_CS1              (0x02)
+#define MCF_GPIO_PPDSDR_CS_PPDSDR_CS2              (0x04)
+#define MCF_GPIO_PPDSDR_CS_PPDSDR_CS3              (0x08)
+#define MCF_GPIO_PPDSDR_CS_PPDSDR_CS4              (0x10)
+#define MCF_GPIO_PPDSDR_CS_PPDSDR_CS5              (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_PWM */
+#define MCF_GPIO_PPDSDR_PWM_PPDSDR_PWM2            (0x04)
+#define MCF_GPIO_PPDSDR_PWM_PPDSDR_PWM3            (0x08)
+#define MCF_GPIO_PPDSDR_PWM_PPDSDR_PWM4            (0x10)
+#define MCF_GPIO_PPDSDR_PWM_PPDSDR_PWM5            (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_FECI2C */
+#define MCF_GPIO_PPDSDR_FECI2C_PPDSDR_FECI2C0      (0x01)
+#define MCF_GPIO_PPDSDR_FECI2C_PPDSDR_FECI2C1      (0x02)
+#define MCF_GPIO_PPDSDR_FECI2C_PPDSDR_FECI2C2      (0x04)
+#define MCF_GPIO_PPDSDR_FECI2C_PPDSDR_FECI2C3      (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_UART */
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART0          (0x01)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART1          (0x02)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART2          (0x04)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART3          (0x08)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART4          (0x10)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART5          (0x20)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART6          (0x40)
+#define MCF_GPIO_PPDSDR_UART_PPDSDR_UART7          (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_QSPI */
+#define MCF_GPIO_PPDSDR_QSPI_PPDSDR_QSPI0          (0x01)
+#define MCF_GPIO_PPDSDR_QSPI_PPDSDR_QSPI1          (0x02)
+#define MCF_GPIO_PPDSDR_QSPI_PPDSDR_QSPI2          (0x04)
+#define MCF_GPIO_PPDSDR_QSPI_PPDSDR_QSPI3          (0x08)
+#define MCF_GPIO_PPDSDR_QSPI_PPDSDR_QSPI4          (0x10)
+#define MCF_GPIO_PPDSDR_QSPI_PPDSDR_QSPI5          (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_TIMER */
+#define MCF_GPIO_PPDSDR_TIMER_PPDSDR_TIMER0        (0x01)
+#define MCF_GPIO_PPDSDR_TIMER_PPDSDR_TIMER1        (0x02)
+#define MCF_GPIO_PPDSDR_TIMER_PPDSDR_TIMER2        (0x04)
+#define MCF_GPIO_PPDSDR_TIMER_PPDSDR_TIMER3        (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_LCDDATAH */
+#define MCF_GPIO_PPDSDR_LCDDATAH_PPDSDR_LCDDATAH0  (0x01)
+#define MCF_GPIO_PPDSDR_LCDDATAH_PPDSDR_LCDDATAH1  (0x02)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_LCDDATAM */
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM0  (0x01)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM1  (0x02)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM2  (0x04)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM3  (0x08)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM4  (0x10)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM5  (0x20)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM6  (0x40)
+#define MCF_GPIO_PPDSDR_LCDDATAM_PPDSDR_LCDDATAM7  (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_LCDDATAL */
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL0  (0x01)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL1  (0x02)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL2  (0x04)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL3  (0x08)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL4  (0x10)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL5  (0x20)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL6  (0x40)
+#define MCF_GPIO_PPDSDR_LCDDATAL_PPDSDR_LCDDATAL7  (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_LCDCTLH */
+#define MCF_GPIO_PPDSDR_LCDCTLH_PPDSDR_LCDCTLH0    (0x01)
+
+/* Bit definitions and macros for MCF_GPIO_PPDSDR_LCDCTLL */
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL0    (0x01)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL1    (0x02)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL2    (0x04)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL3    (0x08)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL4    (0x10)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL5    (0x20)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL6    (0x40)
+#define MCF_GPIO_PPDSDR_LCDCTLL_PPDSDR_LCDCTLL7    (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_FECH */
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH0            (0x01)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH1            (0x02)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH2            (0x04)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH3            (0x08)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH4            (0x10)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH5            (0x20)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH6            (0x40)
+#define MCF_GPIO_PCLRR_FECH_PCLRR_FECH7            (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_FECL */
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL0            (0x01)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL1            (0x02)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL2            (0x04)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL3            (0x08)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL4            (0x10)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL5            (0x20)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL6            (0x40)
+#define MCF_GPIO_PCLRR_FECL_PCLRR_FECL7            (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_SSI */
+#define MCF_GPIO_PCLRR_SSI_PCLRR_SSI0              (0x01)
+#define MCF_GPIO_PCLRR_SSI_PCLRR_SSI1              (0x02)
+#define MCF_GPIO_PCLRR_SSI_PCLRR_SSI2              (0x04)
+#define MCF_GPIO_PCLRR_SSI_PCLRR_SSI3              (0x08)
+#define MCF_GPIO_PCLRR_SSI_PCLRR_SSI4              (0x10)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_BUSCTL */
+#define MCF_GPIO_PCLRR_BUSCTL_POSDR_BUSCTL0        (0x01)
+#define MCF_GPIO_PCLRR_BUSCTL_PCLRR_BUSCTL1        (0x02)
+#define MCF_GPIO_PCLRR_BUSCTL_PCLRR_BUSCTL2        (0x04)
+#define MCF_GPIO_PCLRR_BUSCTL_PCLRR_BUSCTL3        (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_BE */
+#define MCF_GPIO_PCLRR_BE_PCLRR_BE0                (0x01)
+#define MCF_GPIO_PCLRR_BE_PCLRR_BE1                (0x02)
+#define MCF_GPIO_PCLRR_BE_PCLRR_BE2                (0x04)
+#define MCF_GPIO_PCLRR_BE_PCLRR_BE3                (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_CS */
+#define MCF_GPIO_PCLRR_CS_PCLRR_CS1                (0x02)
+#define MCF_GPIO_PCLRR_CS_PCLRR_CS2                (0x04)
+#define MCF_GPIO_PCLRR_CS_PCLRR_CS3                (0x08)
+#define MCF_GPIO_PCLRR_CS_PCLRR_CS4                (0x10)
+#define MCF_GPIO_PCLRR_CS_PCLRR_CS5                (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_PWM */
+#define MCF_GPIO_PCLRR_PWM_PCLRR_PWM2              (0x04)
+#define MCF_GPIO_PCLRR_PWM_PCLRR_PWM3              (0x08)
+#define MCF_GPIO_PCLRR_PWM_PCLRR_PWM4              (0x10)
+#define MCF_GPIO_PCLRR_PWM_PCLRR_PWM5              (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_FECI2C */
+#define MCF_GPIO_PCLRR_FECI2C_PCLRR_FECI2C0        (0x01)
+#define MCF_GPIO_PCLRR_FECI2C_PCLRR_FECI2C1        (0x02)
+#define MCF_GPIO_PCLRR_FECI2C_PCLRR_FECI2C2        (0x04)
+#define MCF_GPIO_PCLRR_FECI2C_PCLRR_FECI2C3        (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_UART */
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART0            (0x01)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART1            (0x02)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART2            (0x04)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART3            (0x08)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART4            (0x10)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART5            (0x20)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART6            (0x40)
+#define MCF_GPIO_PCLRR_UART_PCLRR_UART7            (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_QSPI */
+#define MCF_GPIO_PCLRR_QSPI_PCLRR_QSPI0            (0x01)
+#define MCF_GPIO_PCLRR_QSPI_PCLRR_QSPI1            (0x02)
+#define MCF_GPIO_PCLRR_QSPI_PCLRR_QSPI2            (0x04)
+#define MCF_GPIO_PCLRR_QSPI_PCLRR_QSPI3            (0x08)
+#define MCF_GPIO_PCLRR_QSPI_PCLRR_QSPI4            (0x10)
+#define MCF_GPIO_PCLRR_QSPI_PCLRR_QSPI5            (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_TIMER */
+#define MCF_GPIO_PCLRR_TIMER_PCLRR_TIMER0          (0x01)
+#define MCF_GPIO_PCLRR_TIMER_PCLRR_TIMER1          (0x02)
+#define MCF_GPIO_PCLRR_TIMER_PCLRR_TIMER2          (0x04)
+#define MCF_GPIO_PCLRR_TIMER_PCLRR_TIMER3          (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_LCDDATAH */
+#define MCF_GPIO_PCLRR_LCDDATAH_PCLRR_LCDDATAH0    (0x01)
+#define MCF_GPIO_PCLRR_LCDDATAH_PCLRR_LCDDATAH1    (0x02)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_LCDDATAM */
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM0    (0x01)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM1    (0x02)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM2    (0x04)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM3    (0x08)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM4    (0x10)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM5    (0x20)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM6    (0x40)
+#define MCF_GPIO_PCLRR_LCDDATAM_PCLRR_LCDDATAM7    (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_LCDDATAL */
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL0    (0x01)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL1    (0x02)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL2    (0x04)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL3    (0x08)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL4    (0x10)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL5    (0x20)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL6    (0x40)
+#define MCF_GPIO_PCLRR_LCDDATAL_PCLRR_LCDDATAL7    (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_LCDCTLH */
+#define MCF_GPIO_PCLRR_LCDCTLH_PCLRR_LCDCTLH0      (0x01)
+
+/* Bit definitions and macros for MCF_GPIO_PCLRR_LCDCTLL */
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL0      (0x01)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL1      (0x02)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL2      (0x04)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL3      (0x08)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL4      (0x10)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL5      (0x20)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL6      (0x40)
+#define MCF_GPIO_PCLRR_LCDCTLL_PCLRR_LCDCTLL7      (0x80)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_FEC */
+#define MCF_GPIO_PAR_FEC_PAR_FEC_MII(x)            (((x)&0x03)<<0)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_7W(x)             (((x)&0x03)<<2)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_7W_GPIO           (0x00)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_7W_URTS1          (0x04)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC            (0x0C)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_MII_GPIO          (0x00)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_MII_UART          (0x01)
+#define MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC           (0x03)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_PWM */
+#define MCF_GPIO_PAR_PWM_PAR_PWM1(x)               (((x)&0x03)<<0)
+#define MCF_GPIO_PAR_PWM_PAR_PWM3(x)               (((x)&0x03)<<2)
+#define MCF_GPIO_PAR_PWM_PAR_PWM5                  (0x10)
+#define MCF_GPIO_PAR_PWM_PAR_PWM7                  (0x20)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_BUSCTL */
+#define MCF_GPIO_PAR_BUSCTL_PAR_TS(x)              (((x)&0x03)<<3)
+#define MCF_GPIO_PAR_BUSCTL_PAR_RWB                (0x20)
+#define MCF_GPIO_PAR_BUSCTL_PAR_TA                 (0x40)
+#define MCF_GPIO_PAR_BUSCTL_PAR_OE                 (0x80)
+#define MCF_GPIO_PAR_BUSCTL_PAR_OE_GPIO            (0x00)
+#define MCF_GPIO_PAR_BUSCTL_PAR_OE_OE              (0x80)
+#define MCF_GPIO_PAR_BUSCTL_PAR_TA_GPIO            (0x00)
+#define MCF_GPIO_PAR_BUSCTL_PAR_TA_TA              (0x40)
+#define MCF_GPIO_PAR_BUSCTL_PAR_RWB_GPIO           (0x00)
+#define MCF_GPIO_PAR_BUSCTL_PAR_RWB_RWB            (0x20)
+#define MCF_GPIO_PAR_BUSCTL_PAR_TS_GPIO            (0x00)
+#define MCF_GPIO_PAR_BUSCTL_PAR_TS_DACK0           (0x10)
+#define MCF_GPIO_PAR_BUSCTL_PAR_TS_TS              (0x18)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_FECI2C */
+#define MCF_GPIO_PAR_FECI2C_PAR_SDA(x)             (((x)&0x03)<<0)
+#define MCF_GPIO_PAR_FECI2C_PAR_SCL(x)             (((x)&0x03)<<2)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDIO(x)            (((x)&0x03)<<4)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDC(x)             (((x)&0x03)<<6)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDC_GPIO           (0x00)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDC_UTXD2          (0x40)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDC_SCL            (0x80)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC           (0xC0)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDIO_GPIO          (0x00)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDIO_URXD2         (0x10)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDIO_SDA           (0x20)
+#define MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO         (0x30)
+#define MCF_GPIO_PAR_FECI2C_PAR_SCL_GPIO           (0x00)
+#define MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2          (0x04)
+#define MCF_GPIO_PAR_FECI2C_PAR_SCL_SCL            (0x0C)
+#define MCF_GPIO_PAR_FECI2C_PAR_SDA_GPIO           (0x00)
+#define MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2          (0x02)
+#define MCF_GPIO_PAR_FECI2C_PAR_SDA_SDA            (0x03)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_BE */
+#define MCF_GPIO_PAR_BE_PAR_BE0                    (0x01)
+#define MCF_GPIO_PAR_BE_PAR_BE1                    (0x02)
+#define MCF_GPIO_PAR_BE_PAR_BE2                    (0x04)
+#define MCF_GPIO_PAR_BE_PAR_BE3                    (0x08)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_CS */
+#define MCF_GPIO_PAR_CS_PAR_CS1                    (0x02)
+#define MCF_GPIO_PAR_CS_PAR_CS2                    (0x04)
+#define MCF_GPIO_PAR_CS_PAR_CS3                    (0x08)
+#define MCF_GPIO_PAR_CS_PAR_CS4                    (0x10)
+#define MCF_GPIO_PAR_CS_PAR_CS5                    (0x20)
+#define MCF_GPIO_PAR_CS_PAR_CS_CS1_GPIO            (0x00)
+#define MCF_GPIO_PAR_CS_PAR_CS_CS1_SDCS1           (0x01)
+#define MCF_GPIO_PAR_CS_PAR_CS_CS1_CS1             (0x03)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_SSI */
+#define MCF_GPIO_PAR_SSI_PAR_MCLK                  (0x0080)
+#define MCF_GPIO_PAR_SSI_PAR_TXD(x)                (((x)&0x0003)<<8)
+#define MCF_GPIO_PAR_SSI_PAR_RXD(x)                (((x)&0x0003)<<10)
+#define MCF_GPIO_PAR_SSI_PAR_FS(x)                 (((x)&0x0003)<<12)
+#define MCF_GPIO_PAR_SSI_PAR_BCLK(x)               (((x)&0x0003)<<14)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_UART */
+#define MCF_GPIO_PAR_UART_PAR_UTXD0                (0x0001)
+#define MCF_GPIO_PAR_UART_PAR_URXD0                (0x0002)
+#define MCF_GPIO_PAR_UART_PAR_URTS0                (0x0004)
+#define MCF_GPIO_PAR_UART_PAR_UCTS0                (0x0008)
+#define MCF_GPIO_PAR_UART_PAR_UTXD1(x)             (((x)&0x0003)<<4)
+#define MCF_GPIO_PAR_UART_PAR_URXD1(x)             (((x)&0x0003)<<6)
+#define MCF_GPIO_PAR_UART_PAR_URTS1(x)             (((x)&0x0003)<<8)
+#define MCF_GPIO_PAR_UART_PAR_UCTS1(x)             (((x)&0x0003)<<10)
+#define MCF_GPIO_PAR_UART_PAR_UCTS1_GPIO           (0x0000)
+#define MCF_GPIO_PAR_UART_PAR_UCTS1_SSI_BCLK       (0x0800)
+#define MCF_GPIO_PAR_UART_PAR_UCTS1_ULPI_D7        (0x0400)
+#define MCF_GPIO_PAR_UART_PAR_UCTS1_UCTS1          (0x0C00)
+#define MCF_GPIO_PAR_UART_PAR_URTS1_GPIO           (0x0000)
+#define MCF_GPIO_PAR_UART_PAR_URTS1_SSI_FS         (0x0200)
+#define MCF_GPIO_PAR_UART_PAR_URTS1_ULPI_D6        (0x0100)
+#define MCF_GPIO_PAR_UART_PAR_URTS1_URTS1          (0x0300)
+#define MCF_GPIO_PAR_UART_PAR_URXD1_GPIO           (0x0000)
+#define MCF_GPIO_PAR_UART_PAR_URXD1_SSI_RXD        (0x0080)
+#define MCF_GPIO_PAR_UART_PAR_URXD1_ULPI_D5        (0x0040)
+#define MCF_GPIO_PAR_UART_PAR_URXD1_URXD1          (0x00C0)
+#define MCF_GPIO_PAR_UART_PAR_UTXD1_GPIO           (0x0000)
+#define MCF_GPIO_PAR_UART_PAR_UTXD1_SSI_TXD        (0x0020)
+#define MCF_GPIO_PAR_UART_PAR_UTXD1_ULPI_D4        (0x0010)
+#define MCF_GPIO_PAR_UART_PAR_UTXD1_UTXD1          (0x0030)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_QSPI */
+#define MCF_GPIO_PAR_QSPI_PAR_SCK(x)               (((x)&0x0003)<<4)
+#define MCF_GPIO_PAR_QSPI_PAR_DOUT(x)              (((x)&0x0003)<<6)
+#define MCF_GPIO_PAR_QSPI_PAR_DIN(x)               (((x)&0x0003)<<8)
+#define MCF_GPIO_PAR_QSPI_PAR_PCS0(x)              (((x)&0x0003)<<10)
+#define MCF_GPIO_PAR_QSPI_PAR_PCS1(x)              (((x)&0x0003)<<12)
+#define MCF_GPIO_PAR_QSPI_PAR_PCS2(x)              (((x)&0x0003)<<14)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_TIMER */
+#define MCF_GPIO_PAR_TIMER_PAR_TIN0(x)             (((x)&0x03)<<0)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN1(x)             (((x)&0x03)<<2)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN2(x)             (((x)&0x03)<<4)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN3(x)             (((x)&0x03)<<6)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN3_GPIO           (0x00)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN3_TOUT3          (0x80)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN3_URXD2          (0x40)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN3_TIN3           (0xC0)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN2_GPIO           (0x00)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN2_TOUT2          (0x20)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN2_UTXD2          (0x10)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN2_TIN2           (0x30)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN1_GPIO           (0x00)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN1_TOUT1          (0x08)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN1_DACK1          (0x04)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN1_TIN1           (0x0C)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN0_GPIO           (0x00)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN0_TOUT0          (0x02)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN0_DREQ0          (0x01)
+#define MCF_GPIO_PAR_TIMER_PAR_TIN0_TIN0           (0x03)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_LCDDATA */
+#define MCF_GPIO_PAR_LCDDATA_PAR_LD7_0(x)          (((x)&0x03)<<0)
+#define MCF_GPIO_PAR_LCDDATA_PAR_LD15_8(x)         (((x)&0x03)<<2)
+#define MCF_GPIO_PAR_LCDDATA_PAR_LD16(x)           (((x)&0x03)<<4)
+#define MCF_GPIO_PAR_LCDDATA_PAR_LD17(x)           (((x)&0x03)<<6)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_LCDCTL */
+#define MCF_GPIO_PAR_LCDCTL_PAR_CLS                (0x0001)
+#define MCF_GPIO_PAR_LCDCTL_PAR_PS                 (0x0002)
+#define MCF_GPIO_PAR_LCDCTL_PAR_REV                (0x0004)
+#define MCF_GPIO_PAR_LCDCTL_PAR_SPL_SPR            (0x0008)
+#define MCF_GPIO_PAR_LCDCTL_PAR_CONTRAST           (0x0010)
+#define MCF_GPIO_PAR_LCDCTL_PAR_LSCLK              (0x0020)
+#define MCF_GPIO_PAR_LCDCTL_PAR_LP_HSYNC           (0x0040)
+#define MCF_GPIO_PAR_LCDCTL_PAR_FLM_VSYNC          (0x0080)
+#define MCF_GPIO_PAR_LCDCTL_PAR_ACD_OE             (0x0100)
+
+/* Bit definitions and macros for MCF_GPIO_PAR_IRQ */
+#define MCF_GPIO_PAR_IRQ_PAR_IRQ1(x)               (((x)&0x0003)<<4)
+#define MCF_GPIO_PAR_IRQ_PAR_IRQ2(x)               (((x)&0x0003)<<6)
+#define MCF_GPIO_PAR_IRQ_PAR_IRQ4(x)               (((x)&0x0003)<<8)
+#define MCF_GPIO_PAR_IRQ_PAR_IRQ5(x)               (((x)&0x0003)<<10)
+#define MCF_GPIO_PAR_IRQ_PAR_IRQ6(x)               (((x)&0x0003)<<12)
+
+/* Bit definitions and macros for MCF_GPIO_MSCR_FLEXBUS */
+#define MCF_GPIO_MSCR_FLEXBUS_MSCR_ADDRCTL(x)      (((x)&0x03)<<0)
+#define MCF_GPIO_MSCR_FLEXBUS_MSCR_DLOWER(x)       (((x)&0x03)<<2)
+#define MCF_GPIO_MSCR_FLEXBUS_MSCR_DUPPER(x)       (((x)&0x03)<<4)
+
+/* Bit definitions and macros for MCF_GPIO_MSCR_SDRAM */
+#define MCF_GPIO_MSCR_SDRAM_MSCR_SDRAM(x)          (((x)&0x03)<<0)
+#define MCF_GPIO_MSCR_SDRAM_MSCR_SDCLK(x)          (((x)&0x03)<<2)
+#define MCF_GPIO_MSCR_SDRAM_MSCR_SDCLKB(x)         (((x)&0x03)<<4)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_I2C */
+#define MCF_GPIO_DSCR_I2C_I2C_DSE(x)               (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_PWM */
+#define MCF_GPIO_DSCR_PWM_PWM_DSE(x)               (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_FEC */
+#define MCF_GPIO_DSCR_FEC_FEC_DSE(x)               (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_UART */
+#define MCF_GPIO_DSCR_UART_UART0_DSE(x)            (((x)&0x03)<<0)
+#define MCF_GPIO_DSCR_UART_UART1_DSE(x)            (((x)&0x03)<<2)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_QSPI */
+#define MCF_GPIO_DSCR_QSPI_QSPI_DSE(x)             (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_TIMER */
+#define MCF_GPIO_DSCR_TIMER_TIMER_DSE(x)           (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_SSI */
+#define MCF_GPIO_DSCR_SSI_SSI_DSE(x)               (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_LCD */
+#define MCF_GPIO_DSCR_LCD_LCD_DSE(x)               (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_DEBUG */
+#define MCF_GPIO_DSCR_DEBUG_DEBUG_DSE(x)           (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_CLKRST */
+#define MCF_GPIO_DSCR_CLKRST_CLKRST_DSE(x)         (((x)&0x03)<<0)
+
+/* Bit definitions and macros for MCF_GPIO_DSCR_IRQ */
+#define MCF_GPIO_DSCR_IRQ_IRQ_DSE(x)               (((x)&0x03)<<0)
+
+/*********************************************************************
+ *
+ * Interrupt Controller (INTC)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_INTC0_IPRH             MCF_REG32(0xFC048000)
+#define MCF_INTC0_IPRL             MCF_REG32(0xFC048004)
+#define MCF_INTC0_IMRH             MCF_REG32(0xFC048008)
+#define MCF_INTC0_IMRL             MCF_REG32(0xFC04800C)
+#define MCF_INTC0_INTFRCH          MCF_REG32(0xFC048010)
+#define MCF_INTC0_INTFRCL          MCF_REG32(0xFC048014)
+#define MCF_INTC0_ICONFIG          MCF_REG16(0xFC04801A)
+#define MCF_INTC0_SIMR             MCF_REG08(0xFC04801C)
+#define MCF_INTC0_CIMR             MCF_REG08(0xFC04801D)
+#define MCF_INTC0_CLMASK           MCF_REG08(0xFC04801E)
+#define MCF_INTC0_SLMASK           MCF_REG08(0xFC04801F)
+#define MCF_INTC0_ICR0             MCF_REG08(0xFC048040)
+#define MCF_INTC0_ICR1             MCF_REG08(0xFC048041)
+#define MCF_INTC0_ICR2             MCF_REG08(0xFC048042)
+#define MCF_INTC0_ICR3             MCF_REG08(0xFC048043)
+#define MCF_INTC0_ICR4             MCF_REG08(0xFC048044)
+#define MCF_INTC0_ICR5             MCF_REG08(0xFC048045)
+#define MCF_INTC0_ICR6             MCF_REG08(0xFC048046)
+#define MCF_INTC0_ICR7             MCF_REG08(0xFC048047)
+#define MCF_INTC0_ICR8             MCF_REG08(0xFC048048)
+#define MCF_INTC0_ICR9             MCF_REG08(0xFC048049)
+#define MCF_INTC0_ICR10            MCF_REG08(0xFC04804A)
+#define MCF_INTC0_ICR11            MCF_REG08(0xFC04804B)
+#define MCF_INTC0_ICR12            MCF_REG08(0xFC04804C)
+#define MCF_INTC0_ICR13            MCF_REG08(0xFC04804D)
+#define MCF_INTC0_ICR14            MCF_REG08(0xFC04804E)
+#define MCF_INTC0_ICR15            MCF_REG08(0xFC04804F)
+#define MCF_INTC0_ICR16            MCF_REG08(0xFC048050)
+#define MCF_INTC0_ICR17            MCF_REG08(0xFC048051)
+#define MCF_INTC0_ICR18            MCF_REG08(0xFC048052)
+#define MCF_INTC0_ICR19            MCF_REG08(0xFC048053)
+#define MCF_INTC0_ICR20            MCF_REG08(0xFC048054)
+#define MCF_INTC0_ICR21            MCF_REG08(0xFC048055)
+#define MCF_INTC0_ICR22            MCF_REG08(0xFC048056)
+#define MCF_INTC0_ICR23            MCF_REG08(0xFC048057)
+#define MCF_INTC0_ICR24            MCF_REG08(0xFC048058)
+#define MCF_INTC0_ICR25            MCF_REG08(0xFC048059)
+#define MCF_INTC0_ICR26            MCF_REG08(0xFC04805A)
+#define MCF_INTC0_ICR27            MCF_REG08(0xFC04805B)
+#define MCF_INTC0_ICR28            MCF_REG08(0xFC04805C)
+#define MCF_INTC0_ICR29            MCF_REG08(0xFC04805D)
+#define MCF_INTC0_ICR30            MCF_REG08(0xFC04805E)
+#define MCF_INTC0_ICR31            MCF_REG08(0xFC04805F)
+#define MCF_INTC0_ICR32            MCF_REG08(0xFC048060)
+#define MCF_INTC0_ICR33            MCF_REG08(0xFC048061)
+#define MCF_INTC0_ICR34            MCF_REG08(0xFC048062)
+#define MCF_INTC0_ICR35            MCF_REG08(0xFC048063)
+#define MCF_INTC0_ICR36            MCF_REG08(0xFC048064)
+#define MCF_INTC0_ICR37            MCF_REG08(0xFC048065)
+#define MCF_INTC0_ICR38            MCF_REG08(0xFC048066)
+#define MCF_INTC0_ICR39            MCF_REG08(0xFC048067)
+#define MCF_INTC0_ICR40            MCF_REG08(0xFC048068)
+#define MCF_INTC0_ICR41            MCF_REG08(0xFC048069)
+#define MCF_INTC0_ICR42            MCF_REG08(0xFC04806A)
+#define MCF_INTC0_ICR43            MCF_REG08(0xFC04806B)
+#define MCF_INTC0_ICR44            MCF_REG08(0xFC04806C)
+#define MCF_INTC0_ICR45            MCF_REG08(0xFC04806D)
+#define MCF_INTC0_ICR46            MCF_REG08(0xFC04806E)
+#define MCF_INTC0_ICR47            MCF_REG08(0xFC04806F)
+#define MCF_INTC0_ICR48            MCF_REG08(0xFC048070)
+#define MCF_INTC0_ICR49            MCF_REG08(0xFC048071)
+#define MCF_INTC0_ICR50            MCF_REG08(0xFC048072)
+#define MCF_INTC0_ICR51            MCF_REG08(0xFC048073)
+#define MCF_INTC0_ICR52            MCF_REG08(0xFC048074)
+#define MCF_INTC0_ICR53            MCF_REG08(0xFC048075)
+#define MCF_INTC0_ICR54            MCF_REG08(0xFC048076)
+#define MCF_INTC0_ICR55            MCF_REG08(0xFC048077)
+#define MCF_INTC0_ICR56            MCF_REG08(0xFC048078)
+#define MCF_INTC0_ICR57            MCF_REG08(0xFC048079)
+#define MCF_INTC0_ICR58            MCF_REG08(0xFC04807A)
+#define MCF_INTC0_ICR59            MCF_REG08(0xFC04807B)
+#define MCF_INTC0_ICR60            MCF_REG08(0xFC04807C)
+#define MCF_INTC0_ICR61            MCF_REG08(0xFC04807D)
+#define MCF_INTC0_ICR62            MCF_REG08(0xFC04807E)
+#define MCF_INTC0_ICR63            MCF_REG08(0xFC04807F)
+#define MCF_INTC0_ICR(x)           MCF_REG08(0xFC048040+((x)*0x001))
+#define MCF_INTC0_SWIACK           MCF_REG08(0xFC0480E0)
+#define MCF_INTC0_L1IACK           MCF_REG08(0xFC0480E4)
+#define MCF_INTC0_L2IACK           MCF_REG08(0xFC0480E8)
+#define MCF_INTC0_L3IACK           MCF_REG08(0xFC0480EC)
+#define MCF_INTC0_L4IACK           MCF_REG08(0xFC0480F0)
+#define MCF_INTC0_L5IACK           MCF_REG08(0xFC0480F4)
+#define MCF_INTC0_L6IACK           MCF_REG08(0xFC0480F8)
+#define MCF_INTC0_L7IACK           MCF_REG08(0xFC0480FC)
+#define MCF_INTC0_LIACK(x)         MCF_REG08(0xFC0480E4+((x)*0x004))
+#define MCF_INTC1_IPRH             MCF_REG32(0xFC04C000)
+#define MCF_INTC1_IPRL             MCF_REG32(0xFC04C004)
+#define MCF_INTC1_IMRH             MCF_REG32(0xFC04C008)
+#define MCF_INTC1_IMRL             MCF_REG32(0xFC04C00C)
+#define MCF_INTC1_INTFRCH          MCF_REG32(0xFC04C010)
+#define MCF_INTC1_INTFRCL          MCF_REG32(0xFC04C014)
+#define MCF_INTC1_ICONFIG          MCF_REG16(0xFC04C01A)
+#define MCF_INTC1_SIMR             MCF_REG08(0xFC04C01C)
+#define MCF_INTC1_CIMR             MCF_REG08(0xFC04C01D)
+#define MCF_INTC1_CLMASK           MCF_REG08(0xFC04C01E)
+#define MCF_INTC1_SLMASK           MCF_REG08(0xFC04C01F)
+#define MCF_INTC1_ICR0             MCF_REG08(0xFC04C040)
+#define MCF_INTC1_ICR1             MCF_REG08(0xFC04C041)
+#define MCF_INTC1_ICR2             MCF_REG08(0xFC04C042)
+#define MCF_INTC1_ICR3             MCF_REG08(0xFC04C043)
+#define MCF_INTC1_ICR4             MCF_REG08(0xFC04C044)
+#define MCF_INTC1_ICR5             MCF_REG08(0xFC04C045)
+#define MCF_INTC1_ICR6             MCF_REG08(0xFC04C046)
+#define MCF_INTC1_ICR7             MCF_REG08(0xFC04C047)
+#define MCF_INTC1_ICR8             MCF_REG08(0xFC04C048)
+#define MCF_INTC1_ICR9             MCF_REG08(0xFC04C049)
+#define MCF_INTC1_ICR10            MCF_REG08(0xFC04C04A)
+#define MCF_INTC1_ICR11            MCF_REG08(0xFC04C04B)
+#define MCF_INTC1_ICR12            MCF_REG08(0xFC04C04C)
+#define MCF_INTC1_ICR13            MCF_REG08(0xFC04C04D)
+#define MCF_INTC1_ICR14            MCF_REG08(0xFC04C04E)
+#define MCF_INTC1_ICR15            MCF_REG08(0xFC04C04F)
+#define MCF_INTC1_ICR16            MCF_REG08(0xFC04C050)
+#define MCF_INTC1_ICR17            MCF_REG08(0xFC04C051)
+#define MCF_INTC1_ICR18            MCF_REG08(0xFC04C052)
+#define MCF_INTC1_ICR19            MCF_REG08(0xFC04C053)
+#define MCF_INTC1_ICR20            MCF_REG08(0xFC04C054)
+#define MCF_INTC1_ICR21            MCF_REG08(0xFC04C055)
+#define MCF_INTC1_ICR22            MCF_REG08(0xFC04C056)
+#define MCF_INTC1_ICR23            MCF_REG08(0xFC04C057)
+#define MCF_INTC1_ICR24            MCF_REG08(0xFC04C058)
+#define MCF_INTC1_ICR25            MCF_REG08(0xFC04C059)
+#define MCF_INTC1_ICR26            MCF_REG08(0xFC04C05A)
+#define MCF_INTC1_ICR27            MCF_REG08(0xFC04C05B)
+#define MCF_INTC1_ICR28            MCF_REG08(0xFC04C05C)
+#define MCF_INTC1_ICR29            MCF_REG08(0xFC04C05D)
+#define MCF_INTC1_ICR30            MCF_REG08(0xFC04C05E)
+#define MCF_INTC1_ICR31            MCF_REG08(0xFC04C05F)
+#define MCF_INTC1_ICR32            MCF_REG08(0xFC04C060)
+#define MCF_INTC1_ICR33            MCF_REG08(0xFC04C061)
+#define MCF_INTC1_ICR34            MCF_REG08(0xFC04C062)
+#define MCF_INTC1_ICR35            MCF_REG08(0xFC04C063)
+#define MCF_INTC1_ICR36            MCF_REG08(0xFC04C064)
+#define MCF_INTC1_ICR37            MCF_REG08(0xFC04C065)
+#define MCF_INTC1_ICR38            MCF_REG08(0xFC04C066)
+#define MCF_INTC1_ICR39            MCF_REG08(0xFC04C067)
+#define MCF_INTC1_ICR40            MCF_REG08(0xFC04C068)
+#define MCF_INTC1_ICR41            MCF_REG08(0xFC04C069)
+#define MCF_INTC1_ICR42            MCF_REG08(0xFC04C06A)
+#define MCF_INTC1_ICR43            MCF_REG08(0xFC04C06B)
+#define MCF_INTC1_ICR44            MCF_REG08(0xFC04C06C)
+#define MCF_INTC1_ICR45            MCF_REG08(0xFC04C06D)
+#define MCF_INTC1_ICR46            MCF_REG08(0xFC04C06E)
+#define MCF_INTC1_ICR47            MCF_REG08(0xFC04C06F)
+#define MCF_INTC1_ICR48            MCF_REG08(0xFC04C070)
+#define MCF_INTC1_ICR49            MCF_REG08(0xFC04C071)
+#define MCF_INTC1_ICR50            MCF_REG08(0xFC04C072)
+#define MCF_INTC1_ICR51            MCF_REG08(0xFC04C073)
+#define MCF_INTC1_ICR52            MCF_REG08(0xFC04C074)
+#define MCF_INTC1_ICR53            MCF_REG08(0xFC04C075)
+#define MCF_INTC1_ICR54            MCF_REG08(0xFC04C076)
+#define MCF_INTC1_ICR55            MCF_REG08(0xFC04C077)
+#define MCF_INTC1_ICR56            MCF_REG08(0xFC04C078)
+#define MCF_INTC1_ICR57            MCF_REG08(0xFC04C079)
+#define MCF_INTC1_ICR58            MCF_REG08(0xFC04C07A)
+#define MCF_INTC1_ICR59            MCF_REG08(0xFC04C07B)
+#define MCF_INTC1_ICR60            MCF_REG08(0xFC04C07C)
+#define MCF_INTC1_ICR61            MCF_REG08(0xFC04C07D)
+#define MCF_INTC1_ICR62            MCF_REG08(0xFC04C07E)
+#define MCF_INTC1_ICR63            MCF_REG08(0xFC04C07F)
+#define MCF_INTC1_ICR(x)           MCF_REG08(0xFC04C040+((x)*0x001))
+#define MCF_INTC1_SWIACK           MCF_REG08(0xFC04C0E0)
+#define MCF_INTC1_L1IACK           MCF_REG08(0xFC04C0E4)
+#define MCF_INTC1_L2IACK           MCF_REG08(0xFC04C0E8)
+#define MCF_INTC1_L3IACK           MCF_REG08(0xFC04C0EC)
+#define MCF_INTC1_L4IACK           MCF_REG08(0xFC04C0F0)
+#define MCF_INTC1_L5IACK           MCF_REG08(0xFC04C0F4)
+#define MCF_INTC1_L6IACK           MCF_REG08(0xFC04C0F8)
+#define MCF_INTC1_L7IACK           MCF_REG08(0xFC04C0FC)
+#define MCF_INTC1_LIACK(x)         MCF_REG08(0xFC04C0E4+((x)*0x004))
+#define MCF_INTC_IPRH(x)           MCF_REG32(0xFC048000+((x)*0x4000))
+#define MCF_INTC_IPRL(x)           MCF_REG32(0xFC048004+((x)*0x4000))
+#define MCF_INTC_IMRH(x)           MCF_REG32(0xFC048008+((x)*0x4000))
+#define MCF_INTC_IMRL(x)           MCF_REG32(0xFC04800C+((x)*0x4000))
+#define MCF_INTC_INTFRCH(x)        MCF_REG32(0xFC048010+((x)*0x4000))
+#define MCF_INTC_INTFRCL(x)        MCF_REG32(0xFC048014+((x)*0x4000))
+#define MCF_INTC_ICONFIG(x)        MCF_REG16(0xFC04801A+((x)*0x4000))
+#define MCF_INTC_SIMR(x)           MCF_REG08(0xFC04801C+((x)*0x4000))
+#define MCF_INTC_CIMR(x)           MCF_REG08(0xFC04801D+((x)*0x4000))
+#define MCF_INTC_CLMASK(x)         MCF_REG08(0xFC04801E+((x)*0x4000))
+#define MCF_INTC_SLMASK(x)         MCF_REG08(0xFC04801F+((x)*0x4000))
+#define MCF_INTC_ICR0(x)           MCF_REG08(0xFC048040+((x)*0x4000))
+#define MCF_INTC_ICR1(x)           MCF_REG08(0xFC048041+((x)*0x4000))
+#define MCF_INTC_ICR2(x)           MCF_REG08(0xFC048042+((x)*0x4000))
+#define MCF_INTC_ICR3(x)           MCF_REG08(0xFC048043+((x)*0x4000))
+#define MCF_INTC_ICR4(x)           MCF_REG08(0xFC048044+((x)*0x4000))
+#define MCF_INTC_ICR5(x)           MCF_REG08(0xFC048045+((x)*0x4000))
+#define MCF_INTC_ICR6(x)           MCF_REG08(0xFC048046+((x)*0x4000))
+#define MCF_INTC_ICR7(x)           MCF_REG08(0xFC048047+((x)*0x4000))
+#define MCF_INTC_ICR8(x)           MCF_REG08(0xFC048048+((x)*0x4000))
+#define MCF_INTC_ICR9(x)           MCF_REG08(0xFC048049+((x)*0x4000))
+#define MCF_INTC_ICR10(x)          MCF_REG08(0xFC04804A+((x)*0x4000))
+#define MCF_INTC_ICR11(x)          MCF_REG08(0xFC04804B+((x)*0x4000))
+#define MCF_INTC_ICR12(x)          MCF_REG08(0xFC04804C+((x)*0x4000))
+#define MCF_INTC_ICR13(x)          MCF_REG08(0xFC04804D+((x)*0x4000))
+#define MCF_INTC_ICR14(x)          MCF_REG08(0xFC04804E+((x)*0x4000))
+#define MCF_INTC_ICR15(x)          MCF_REG08(0xFC04804F+((x)*0x4000))
+#define MCF_INTC_ICR16(x)          MCF_REG08(0xFC048050+((x)*0x4000))
+#define MCF_INTC_ICR17(x)          MCF_REG08(0xFC048051+((x)*0x4000))
+#define MCF_INTC_ICR18(x)          MCF_REG08(0xFC048052+((x)*0x4000))
+#define MCF_INTC_ICR19(x)          MCF_REG08(0xFC048053+((x)*0x4000))
+#define MCF_INTC_ICR20(x)          MCF_REG08(0xFC048054+((x)*0x4000))
+#define MCF_INTC_ICR21(x)          MCF_REG08(0xFC048055+((x)*0x4000))
+#define MCF_INTC_ICR22(x)          MCF_REG08(0xFC048056+((x)*0x4000))
+#define MCF_INTC_ICR23(x)          MCF_REG08(0xFC048057+((x)*0x4000))
+#define MCF_INTC_ICR24(x)          MCF_REG08(0xFC048058+((x)*0x4000))
+#define MCF_INTC_ICR25(x)          MCF_REG08(0xFC048059+((x)*0x4000))
+#define MCF_INTC_ICR26(x)          MCF_REG08(0xFC04805A+((x)*0x4000))
+#define MCF_INTC_ICR27(x)          MCF_REG08(0xFC04805B+((x)*0x4000))
+#define MCF_INTC_ICR28(x)          MCF_REG08(0xFC04805C+((x)*0x4000))
+#define MCF_INTC_ICR29(x)          MCF_REG08(0xFC04805D+((x)*0x4000))
+#define MCF_INTC_ICR30(x)          MCF_REG08(0xFC04805E+((x)*0x4000))
+#define MCF_INTC_ICR31(x)          MCF_REG08(0xFC04805F+((x)*0x4000))
+#define MCF_INTC_ICR32(x)          MCF_REG08(0xFC048060+((x)*0x4000))
+#define MCF_INTC_ICR33(x)          MCF_REG08(0xFC048061+((x)*0x4000))
+#define MCF_INTC_ICR34(x)          MCF_REG08(0xFC048062+((x)*0x4000))
+#define MCF_INTC_ICR35(x)          MCF_REG08(0xFC048063+((x)*0x4000))
+#define MCF_INTC_ICR36(x)          MCF_REG08(0xFC048064+((x)*0x4000))
+#define MCF_INTC_ICR37(x)          MCF_REG08(0xFC048065+((x)*0x4000))
+#define MCF_INTC_ICR38(x)          MCF_REG08(0xFC048066+((x)*0x4000))
+#define MCF_INTC_ICR39(x)          MCF_REG08(0xFC048067+((x)*0x4000))
+#define MCF_INTC_ICR40(x)          MCF_REG08(0xFC048068+((x)*0x4000))
+#define MCF_INTC_ICR41(x)          MCF_REG08(0xFC048069+((x)*0x4000))
+#define MCF_INTC_ICR42(x)          MCF_REG08(0xFC04806A+((x)*0x4000))
+#define MCF_INTC_ICR43(x)          MCF_REG08(0xFC04806B+((x)*0x4000))
+#define MCF_INTC_ICR44(x)          MCF_REG08(0xFC04806C+((x)*0x4000))
+#define MCF_INTC_ICR45(x)          MCF_REG08(0xFC04806D+((x)*0x4000))
+#define MCF_INTC_ICR46(x)          MCF_REG08(0xFC04806E+((x)*0x4000))
+#define MCF_INTC_ICR47(x)          MCF_REG08(0xFC04806F+((x)*0x4000))
+#define MCF_INTC_ICR48(x)          MCF_REG08(0xFC048070+((x)*0x4000))
+#define MCF_INTC_ICR49(x)          MCF_REG08(0xFC048071+((x)*0x4000))
+#define MCF_INTC_ICR50(x)          MCF_REG08(0xFC048072+((x)*0x4000))
+#define MCF_INTC_ICR51(x)          MCF_REG08(0xFC048073+((x)*0x4000))
+#define MCF_INTC_ICR52(x)          MCF_REG08(0xFC048074+((x)*0x4000))
+#define MCF_INTC_ICR53(x)          MCF_REG08(0xFC048075+((x)*0x4000))
+#define MCF_INTC_ICR54(x)          MCF_REG08(0xFC048076+((x)*0x4000))
+#define MCF_INTC_ICR55(x)          MCF_REG08(0xFC048077+((x)*0x4000))
+#define MCF_INTC_ICR56(x)          MCF_REG08(0xFC048078+((x)*0x4000))
+#define MCF_INTC_ICR57(x)          MCF_REG08(0xFC048079+((x)*0x4000))
+#define MCF_INTC_ICR58(x)          MCF_REG08(0xFC04807A+((x)*0x4000))
+#define MCF_INTC_ICR59(x)          MCF_REG08(0xFC04807B+((x)*0x4000))
+#define MCF_INTC_ICR60(x)          MCF_REG08(0xFC04807C+((x)*0x4000))
+#define MCF_INTC_ICR61(x)          MCF_REG08(0xFC04807D+((x)*0x4000))
+#define MCF_INTC_ICR62(x)          MCF_REG08(0xFC04807E+((x)*0x4000))
+#define MCF_INTC_ICR63(x)          MCF_REG08(0xFC04807F+((x)*0x4000))
+#define MCF_INTC_SWIACK(x)         MCF_REG08(0xFC0480E0+((x)*0x4000))
+#define MCF_INTC_L1IACK(x)         MCF_REG08(0xFC0480E4+((x)*0x4000))
+#define MCF_INTC_L2IACK(x)         MCF_REG08(0xFC0480E8+((x)*0x4000))
+#define MCF_INTC_L3IACK(x)         MCF_REG08(0xFC0480EC+((x)*0x4000))
+#define MCF_INTC_L4IACK(x)         MCF_REG08(0xFC0480F0+((x)*0x4000))
+#define MCF_INTC_L5IACK(x)         MCF_REG08(0xFC0480F4+((x)*0x4000))
+#define MCF_INTC_L6IACK(x)         MCF_REG08(0xFC0480F8+((x)*0x4000))
+#define MCF_INTC_L7IACK(x)         MCF_REG08(0xFC0480FC+((x)*0x4000))
+
+/* Bit definitions and macros for MCF_INTC_IPRH */
+#define MCF_INTC_IPRH_INT32        (0x00000001)
+#define MCF_INTC_IPRH_INT33        (0x00000002)
+#define MCF_INTC_IPRH_INT34        (0x00000004)
+#define MCF_INTC_IPRH_INT35        (0x00000008)
+#define MCF_INTC_IPRH_INT36        (0x00000010)
+#define MCF_INTC_IPRH_INT37        (0x00000020)
+#define MCF_INTC_IPRH_INT38        (0x00000040)
+#define MCF_INTC_IPRH_INT39        (0x00000080)
+#define MCF_INTC_IPRH_INT40        (0x00000100)
+#define MCF_INTC_IPRH_INT41        (0x00000200)
+#define MCF_INTC_IPRH_INT42        (0x00000400)
+#define MCF_INTC_IPRH_INT43        (0x00000800)
+#define MCF_INTC_IPRH_INT44        (0x00001000)
+#define MCF_INTC_IPRH_INT45        (0x00002000)
+#define MCF_INTC_IPRH_INT46        (0x00004000)
+#define MCF_INTC_IPRH_INT47        (0x00008000)
+#define MCF_INTC_IPRH_INT48        (0x00010000)
+#define MCF_INTC_IPRH_INT49        (0x00020000)
+#define MCF_INTC_IPRH_INT50        (0x00040000)
+#define MCF_INTC_IPRH_INT51        (0x00080000)
+#define MCF_INTC_IPRH_INT52        (0x00100000)
+#define MCF_INTC_IPRH_INT53        (0x00200000)
+#define MCF_INTC_IPRH_INT54        (0x00400000)
+#define MCF_INTC_IPRH_INT55        (0x00800000)
+#define MCF_INTC_IPRH_INT56        (0x01000000)
+#define MCF_INTC_IPRH_INT57        (0x02000000)
+#define MCF_INTC_IPRH_INT58        (0x04000000)
+#define MCF_INTC_IPRH_INT59        (0x08000000)
+#define MCF_INTC_IPRH_INT60        (0x10000000)
+#define MCF_INTC_IPRH_INT61        (0x20000000)
+#define MCF_INTC_IPRH_INT62        (0x40000000)
+#define MCF_INTC_IPRH_INT63        (0x80000000)
+
+/* Bit definitions and macros for MCF_INTC_IPRL */
+#define MCF_INTC_IPRL_INT0         (0x00000001)
+#define MCF_INTC_IPRL_INT1         (0x00000002)
+#define MCF_INTC_IPRL_INT2         (0x00000004)
+#define MCF_INTC_IPRL_INT3         (0x00000008)
+#define MCF_INTC_IPRL_INT4         (0x00000010)
+#define MCF_INTC_IPRL_INT5         (0x00000020)
+#define MCF_INTC_IPRL_INT6         (0x00000040)
+#define MCF_INTC_IPRL_INT7         (0x00000080)
+#define MCF_INTC_IPRL_INT8         (0x00000100)
+#define MCF_INTC_IPRL_INT9         (0x00000200)
+#define MCF_INTC_IPRL_INT10        (0x00000400)
+#define MCF_INTC_IPRL_INT11        (0x00000800)
+#define MCF_INTC_IPRL_INT12        (0x00001000)
+#define MCF_INTC_IPRL_INT13        (0x00002000)
+#define MCF_INTC_IPRL_INT14        (0x00004000)
+#define MCF_INTC_IPRL_INT15        (0x00008000)
+#define MCF_INTC_IPRL_INT16        (0x00010000)
+#define MCF_INTC_IPRL_INT17        (0x00020000)
+#define MCF_INTC_IPRL_INT18        (0x00040000)
+#define MCF_INTC_IPRL_INT19        (0x00080000)
+#define MCF_INTC_IPRL_INT20        (0x00100000)
+#define MCF_INTC_IPRL_INT21        (0x00200000)
+#define MCF_INTC_IPRL_INT22        (0x00400000)
+#define MCF_INTC_IPRL_INT23        (0x00800000)
+#define MCF_INTC_IPRL_INT24        (0x01000000)
+#define MCF_INTC_IPRL_INT25        (0x02000000)
+#define MCF_INTC_IPRL_INT26        (0x04000000)
+#define MCF_INTC_IPRL_INT27        (0x08000000)
+#define MCF_INTC_IPRL_INT28        (0x10000000)
+#define MCF_INTC_IPRL_INT29        (0x20000000)
+#define MCF_INTC_IPRL_INT30        (0x40000000)
+#define MCF_INTC_IPRL_INT31        (0x80000000)
+
+/* Bit definitions and macros for MCF_INTC_IMRH */
+#define MCF_INTC_IMRH_INT_MASK32   (0x00000001)
+#define MCF_INTC_IMRH_INT_MASK33   (0x00000002)
+#define MCF_INTC_IMRH_INT_MASK34   (0x00000004)
+#define MCF_INTC_IMRH_INT_MASK35   (0x00000008)
+#define MCF_INTC_IMRH_INT_MASK36   (0x00000010)
+#define MCF_INTC_IMRH_INT_MASK37   (0x00000020)
+#define MCF_INTC_IMRH_INT_MASK38   (0x00000040)
+#define MCF_INTC_IMRH_INT_MASK39   (0x00000080)
+#define MCF_INTC_IMRH_INT_MASK40   (0x00000100)
+#define MCF_INTC_IMRH_INT_MASK41   (0x00000200)
+#define MCF_INTC_IMRH_INT_MASK42   (0x00000400)
+#define MCF_INTC_IMRH_INT_MASK43   (0x00000800)
+#define MCF_INTC_IMRH_INT_MASK44   (0x00001000)
+#define MCF_INTC_IMRH_INT_MASK45   (0x00002000)
+#define MCF_INTC_IMRH_INT_MASK46   (0x00004000)
+#define MCF_INTC_IMRH_INT_MASK47   (0x00008000)
+#define MCF_INTC_IMRH_INT_MASK48   (0x00010000)
+#define MCF_INTC_IMRH_INT_MASK49   (0x00020000)
+#define MCF_INTC_IMRH_INT_MASK50   (0x00040000)
+#define MCF_INTC_IMRH_INT_MASK51   (0x00080000)
+#define MCF_INTC_IMRH_INT_MASK52   (0x00100000)
+#define MCF_INTC_IMRH_INT_MASK53   (0x00200000)
+#define MCF_INTC_IMRH_INT_MASK54   (0x00400000)
+#define MCF_INTC_IMRH_INT_MASK55   (0x00800000)
+#define MCF_INTC_IMRH_INT_MASK56   (0x01000000)
+#define MCF_INTC_IMRH_INT_MASK57   (0x02000000)
+#define MCF_INTC_IMRH_INT_MASK58   (0x04000000)
+#define MCF_INTC_IMRH_INT_MASK59   (0x08000000)
+#define MCF_INTC_IMRH_INT_MASK60   (0x10000000)
+#define MCF_INTC_IMRH_INT_MASK61   (0x20000000)
+#define MCF_INTC_IMRH_INT_MASK62   (0x40000000)
+#define MCF_INTC_IMRH_INT_MASK63   (0x80000000)
+
+/* Bit definitions and macros for MCF_INTC_IMRL */
+#define MCF_INTC_IMRL_INT_MASK0    (0x00000001)
+#define MCF_INTC_IMRL_INT_MASK1    (0x00000002)
+#define MCF_INTC_IMRL_INT_MASK2    (0x00000004)
+#define MCF_INTC_IMRL_INT_MASK3    (0x00000008)
+#define MCF_INTC_IMRL_INT_MASK4    (0x00000010)
+#define MCF_INTC_IMRL_INT_MASK5    (0x00000020)
+#define MCF_INTC_IMRL_INT_MASK6    (0x00000040)
+#define MCF_INTC_IMRL_INT_MASK7    (0x00000080)
+#define MCF_INTC_IMRL_INT_MASK8    (0x00000100)
+#define MCF_INTC_IMRL_INT_MASK9    (0x00000200)
+#define MCF_INTC_IMRL_INT_MASK10   (0x00000400)
+#define MCF_INTC_IMRL_INT_MASK11   (0x00000800)
+#define MCF_INTC_IMRL_INT_MASK12   (0x00001000)
+#define MCF_INTC_IMRL_INT_MASK13   (0x00002000)
+#define MCF_INTC_IMRL_INT_MASK14   (0x00004000)
+#define MCF_INTC_IMRL_INT_MASK15   (0x00008000)
+#define MCF_INTC_IMRL_INT_MASK16   (0x00010000)
+#define MCF_INTC_IMRL_INT_MASK17   (0x00020000)
+#define MCF_INTC_IMRL_INT_MASK18   (0x00040000)
+#define MCF_INTC_IMRL_INT_MASK19   (0x00080000)
+#define MCF_INTC_IMRL_INT_MASK20   (0x00100000)
+#define MCF_INTC_IMRL_INT_MASK21   (0x00200000)
+#define MCF_INTC_IMRL_INT_MASK22   (0x00400000)
+#define MCF_INTC_IMRL_INT_MASK23   (0x00800000)
+#define MCF_INTC_IMRL_INT_MASK24   (0x01000000)
+#define MCF_INTC_IMRL_INT_MASK25   (0x02000000)
+#define MCF_INTC_IMRL_INT_MASK26   (0x04000000)
+#define MCF_INTC_IMRL_INT_MASK27   (0x08000000)
+#define MCF_INTC_IMRL_INT_MASK28   (0x10000000)
+#define MCF_INTC_IMRL_INT_MASK29   (0x20000000)
+#define MCF_INTC_IMRL_INT_MASK30   (0x40000000)
+#define MCF_INTC_IMRL_INT_MASK31   (0x80000000)
+
+/* Bit definitions and macros for MCF_INTC_INTFRCH */
+#define MCF_INTC_INTFRCH_INTFRC32  (0x00000001)
+#define MCF_INTC_INTFRCH_INTFRC33  (0x00000002)
+#define MCF_INTC_INTFRCH_INTFRC34  (0x00000004)
+#define MCF_INTC_INTFRCH_INTFRC35  (0x00000008)
+#define MCF_INTC_INTFRCH_INTFRC36  (0x00000010)
+#define MCF_INTC_INTFRCH_INTFRC37  (0x00000020)
+#define MCF_INTC_INTFRCH_INTFRC38  (0x00000040)
+#define MCF_INTC_INTFRCH_INTFRC39  (0x00000080)
+#define MCF_INTC_INTFRCH_INTFRC40  (0x00000100)
+#define MCF_INTC_INTFRCH_INTFRC41  (0x00000200)
+#define MCF_INTC_INTFRCH_INTFRC42  (0x00000400)
+#define MCF_INTC_INTFRCH_INTFRC43  (0x00000800)
+#define MCF_INTC_INTFRCH_INTFRC44  (0x00001000)
+#define MCF_INTC_INTFRCH_INTFRC45  (0x00002000)
+#define MCF_INTC_INTFRCH_INTFRC46  (0x00004000)
+#define MCF_INTC_INTFRCH_INTFRC47  (0x00008000)
+#define MCF_INTC_INTFRCH_INTFRC48  (0x00010000)
+#define MCF_INTC_INTFRCH_INTFRC49  (0x00020000)
+#define MCF_INTC_INTFRCH_INTFRC50  (0x00040000)
+#define MCF_INTC_INTFRCH_INTFRC51  (0x00080000)
+#define MCF_INTC_INTFRCH_INTFRC52  (0x00100000)
+#define MCF_INTC_INTFRCH_INTFRC53  (0x00200000)
+#define MCF_INTC_INTFRCH_INTFRC54  (0x00400000)
+#define MCF_INTC_INTFRCH_INTFRC55  (0x00800000)
+#define MCF_INTC_INTFRCH_INTFRC56  (0x01000000)
+#define MCF_INTC_INTFRCH_INTFRC57  (0x02000000)
+#define MCF_INTC_INTFRCH_INTFRC58  (0x04000000)
+#define MCF_INTC_INTFRCH_INTFRC59  (0x08000000)
+#define MCF_INTC_INTFRCH_INTFRC60  (0x10000000)
+#define MCF_INTC_INTFRCH_INTFRC61  (0x20000000)
+#define MCF_INTC_INTFRCH_INTFRC62  (0x40000000)
+#define MCF_INTC_INTFRCH_INTFRC63  (0x80000000)
+
+/* Bit definitions and macros for MCF_INTC_INTFRCL */
+#define MCF_INTC_INTFRCL_INTFRC0   (0x00000001)
+#define MCF_INTC_INTFRCL_INTFRC1   (0x00000002)
+#define MCF_INTC_INTFRCL_INTFRC2   (0x00000004)
+#define MCF_INTC_INTFRCL_INTFRC3   (0x00000008)
+#define MCF_INTC_INTFRCL_INTFRC4   (0x00000010)
+#define MCF_INTC_INTFRCL_INTFRC5   (0x00000020)
+#define MCF_INTC_INTFRCL_INTFRC6   (0x00000040)
+#define MCF_INTC_INTFRCL_INTFRC7   (0x00000080)
+#define MCF_INTC_INTFRCL_INTFRC8   (0x00000100)
+#define MCF_INTC_INTFRCL_INTFRC9   (0x00000200)
+#define MCF_INTC_INTFRCL_INTFRC10  (0x00000400)
+#define MCF_INTC_INTFRCL_INTFRC11  (0x00000800)
+#define MCF_INTC_INTFRCL_INTFRC12  (0x00001000)
+#define MCF_INTC_INTFRCL_INTFRC13  (0x00002000)
+#define MCF_INTC_INTFRCL_INTFRC14  (0x00004000)
+#define MCF_INTC_INTFRCL_INTFRC15  (0x00008000)
+#define MCF_INTC_INTFRCL_INTFRC16  (0x00010000)
+#define MCF_INTC_INTFRCL_INTFRC17  (0x00020000)
+#define MCF_INTC_INTFRCL_INTFRC18  (0x00040000)
+#define MCF_INTC_INTFRCL_INTFRC19  (0x00080000)
+#define MCF_INTC_INTFRCL_INTFRC20  (0x00100000)
+#define MCF_INTC_INTFRCL_INTFRC21  (0x00200000)
+#define MCF_INTC_INTFRCL_INTFRC22  (0x00400000)
+#define MCF_INTC_INTFRCL_INTFRC23  (0x00800000)
+#define MCF_INTC_INTFRCL_INTFRC24  (0x01000000)
+#define MCF_INTC_INTFRCL_INTFRC25  (0x02000000)
+#define MCF_INTC_INTFRCL_INTFRC26  (0x04000000)
+#define MCF_INTC_INTFRCL_INTFRC27  (0x08000000)
+#define MCF_INTC_INTFRCL_INTFRC28  (0x10000000)
+#define MCF_INTC_INTFRCL_INTFRC29  (0x20000000)
+#define MCF_INTC_INTFRCL_INTFRC30  (0x40000000)
+#define MCF_INTC_INTFRCL_INTFRC31  (0x80000000)
+
+/* Bit definitions and macros for MCF_INTC_ICONFIG */
+#define MCF_INTC_ICONFIG_EMASK     (0x0020)
+#define MCF_INTC_ICONFIG_ELVLPRI1  (0x0200)
+#define MCF_INTC_ICONFIG_ELVLPRI2  (0x0400)
+#define MCF_INTC_ICONFIG_ELVLPRI3  (0x0800)
+#define MCF_INTC_ICONFIG_ELVLPRI4  (0x1000)
+#define MCF_INTC_ICONFIG_ELVLPRI5  (0x2000)
+#define MCF_INTC_ICONFIG_ELVLPRI6  (0x4000)
+#define MCF_INTC_ICONFIG_ELVLPRI7  (0x8000)
+
+/* Bit definitions and macros for MCF_INTC_SIMR */
+#define MCF_INTC_SIMR_SIMR(x)      (((x)&0x7F)<<0)
+
+/* Bit definitions and macros for MCF_INTC_CIMR */
+#define MCF_INTC_CIMR_CIMR(x)      (((x)&0x7F)<<0)
+
+/* Bit definitions and macros for MCF_INTC_CLMASK */
+#define MCF_INTC_CLMASK_CLMASK(x)  (((x)&0x0F)<<0)
+
+/* Bit definitions and macros for MCF_INTC_SLMASK */
+#define MCF_INTC_SLMASK_SLMASK(x)  (((x)&0x0F)<<0)
+
+/* Bit definitions and macros for MCF_INTC_ICR */
+#define MCF_INTC_ICR_IL(x)         (((x)&0x07)<<0)
+
+/* Bit definitions and macros for MCF_INTC_SWIACK */
+#define MCF_INTC_SWIACK_VECTOR(x)  (((x)&0xFF)<<0)
+
+/* Bit definitions and macros for MCF_INTC_LIACK */
+#define MCF_INTC_LIACK_VECTOR(x)   (((x)&0xFF)<<0)
+
+/********************************************************************/
+/*********************************************************************
+*
+* LCD Controller (LCDC)
+*
+*********************************************************************/
+
+/* Register read/write macros */
+#define MCF_LCDC_LSSAR                  MCF_REG32(0xFC0AC000)
+#define MCF_LCDC_LSR                    MCF_REG32(0xFC0AC004)
+#define MCF_LCDC_LVPWR                  MCF_REG32(0xFC0AC008)
+#define MCF_LCDC_LCPR                   MCF_REG32(0xFC0AC00C)
+#define MCF_LCDC_LCWHBR                 MCF_REG32(0xFC0AC010)
+#define MCF_LCDC_LCCMR                  MCF_REG32(0xFC0AC014)
+#define MCF_LCDC_LPCR                   MCF_REG32(0xFC0AC018)
+#define MCF_LCDC_LHCR                   MCF_REG32(0xFC0AC01C)
+#define MCF_LCDC_LVCR                   MCF_REG32(0xFC0AC020)
+#define MCF_LCDC_LPOR                   MCF_REG32(0xFC0AC024)
+#define MCF_LCDC_LSCR                   MCF_REG32(0xFC0AC028)
+#define MCF_LCDC_LPCCR                  MCF_REG32(0xFC0AC02C)
+#define MCF_LCDC_LDCR                   MCF_REG32(0xFC0AC030)
+#define MCF_LCDC_LRMCR                  MCF_REG32(0xFC0AC034)
+#define MCF_LCDC_LICR                   MCF_REG32(0xFC0AC038)
+#define MCF_LCDC_LIER                   MCF_REG32(0xFC0AC03C)
+#define MCF_LCDC_LISR                   MCF_REG32(0xFC0AC040)
+#define MCF_LCDC_LGWSAR                 MCF_REG32(0xFC0AC050)
+#define MCF_LCDC_LGWSR                  MCF_REG32(0xFC0AC054)
+#define MCF_LCDC_LGWVPWR                MCF_REG32(0xFC0AC058)
+#define MCF_LCDC_LGWPOR                 MCF_REG32(0xFC0AC05C)
+#define MCF_LCDC_LGWPR                  MCF_REG32(0xFC0AC060)
+#define MCF_LCDC_LGWCR                  MCF_REG32(0xFC0AC064)
+#define MCF_LCDC_LGWDCR                 MCF_REG32(0xFC0AC068)
+#define MCF_LCDC_BPLUT_BASE             MCF_REG32(0xFC0AC800)
+#define MCF_LCDC_GWLUT_BASE             MCF_REG32(0xFC0ACC00)
+
+/* Bit definitions and macros for MCF_LCDC_LSSAR */
+#define MCF_LCDC_LSSAR_SSA(x)           (((x)&0x3FFFFFFF)<<2)
+
+/* Bit definitions and macros for MCF_LCDC_LSR */
+#define MCF_LCDC_LSR_YMAX(x)            (((x)&0x000003FF)<<0)
+#define MCF_LCDC_LSR_XMAX(x)            (((x)&0x0000003F)<<20)
+
+/* Bit definitions and macros for MCF_LCDC_LVPWR */
+#define MCF_LCDC_LVPWR_VPW(x)           (((x)&0x000003FF)<<0)
+
+/* Bit definitions and macros for MCF_LCDC_LCPR */
+#define MCF_LCDC_LCPR_CYP(x)            (((x)&0x000003FF)<<0)
+#define MCF_LCDC_LCPR_CXP(x)            (((x)&0x000003FF)<<16)
+#define MCF_LCDC_LCPR_OP                (0x10000000)
+#define MCF_LCDC_LCPR_CC(x)             (((x)&0x00000003)<<30)
+#define MCF_LCDC_LCPR_CC_TRANSPARENT    (0x00000000)
+#define MCF_LCDC_LCPR_CC_OR             (0x40000000)
+#define MCF_LCDC_LCPR_CC_XOR            (0x80000000)
+#define MCF_LCDC_LCPR_CC_AND            (0xC0000000)
+#define MCF_LCDC_LCPR_OP_ON             (0x10000000)
+#define MCF_LCDC_LCPR_OP_OFF            (0x00000000)
+
+/* Bit definitions and macros for MCF_LCDC_LCWHBR */
+#define MCF_LCDC_LCWHBR_BD(x)           (((x)&0x000000FF)<<0)
+#define MCF_LCDC_LCWHBR_CH(x)           (((x)&0x0000001F)<<16)
+#define MCF_LCDC_LCWHBR_CW(x)           (((x)&0x0000001F)<<24)
+#define MCF_LCDC_LCWHBR_BK_EN           (0x80000000)
+#define MCF_LCDC_LCWHBR_BK_EN_ON        (0x80000000)
+#define MCF_LCDC_LCWHBR_BK_EN_OFF       (0x00000000)
+
+/* Bit definitions and macros for MCF_LCDC_LCCMR */
+#define MCF_LCDC_LCCMR_CUR_COL_B(x)     (((x)&0x0000003F)<<0)
+#define MCF_LCDC_LCCMR_CUR_COL_G(x)     (((x)&0x0000003F)<<6)
+#define MCF_LCDC_LCCMR_CUR_COL_R(x)     (((x)&0x0000003F)<<12)
+
+/* Bit definitions and macros for MCF_LCDC_LPCR */
+#define MCF_LCDC_LPCR_PCD(x)            (((x)&0x0000003F)<<0)
+#define MCF_LCDC_LPCR_SHARP             (0x00000040)
+#define MCF_LCDC_LPCR_SCLKSEL           (0x00000080)
+#define MCF_LCDC_LPCR_ACD(x)            (((x)&0x0000007F)<<8)
+#define MCF_LCDC_LPCR_ACDSEL            (0x00008000)
+#define MCF_LCDC_LPCR_REV_VS            (0x00010000)
+#define MCF_LCDC_LPCR_SWAP_SEL          (0x00020000)
+#define MCF_LCDC_LPCR_ENDSEL            (0x00040000)
+#define MCF_LCDC_LPCR_SCLKIDLE          (0x00080000)
+#define MCF_LCDC_LPCR_OEPOL             (0x00100000)
+#define MCF_LCDC_LPCR_CLKPOL            (0x00200000)
+#define MCF_LCDC_LPCR_LPPOL             (0x00400000)
+#define MCF_LCDC_LPCR_FLM               (0x00800000)
+#define MCF_LCDC_LPCR_PIXPOL            (0x01000000)
+#define MCF_LCDC_LPCR_BPIX(x)           (((x)&0x00000007)<<25)
+#define MCF_LCDC_LPCR_PBSIZ(x)          (((x)&0x00000003)<<28)
+#define MCF_LCDC_LPCR_COLOR             (0x40000000)
+#define MCF_LCDC_LPCR_TFT               (0x80000000)
+#define MCF_LCDC_LPCR_MODE_MONOCGROME   (0x00000000)
+#define MCF_LCDC_LPCR_MODE_CSTN         (0x40000000)
+#define MCF_LCDC_LPCR_MODE_TFT          (0xC0000000)
+#define MCF_LCDC_LPCR_PBSIZ_1           (0x00000000)
+#define MCF_LCDC_LPCR_PBSIZ_2           (0x10000000)
+#define MCF_LCDC_LPCR_PBSIZ_4           (0x20000000)
+#define MCF_LCDC_LPCR_PBSIZ_8           (0x30000000)
+#define MCF_LCDC_LPCR_BPIX_1bpp         (0x00000000)
+#define MCF_LCDC_LPCR_BPIX_2bpp         (0x02000000)
+#define MCF_LCDC_LPCR_BPIX_4bpp         (0x04000000)
+#define MCF_LCDC_LPCR_BPIX_8bpp         (0x06000000)
+#define MCF_LCDC_LPCR_BPIX_12bpp        (0x08000000)
+#define MCF_LCDC_LPCR_BPIX_16bpp        (0x0A000000)
+#define MCF_LCDC_LPCR_BPIX_18bpp        (0x0C000000)
+
+#define MCF_LCDC_LPCR_PANEL_TYPE(x)     (((x)&0x00000003)<<30) 
+
+/* Bit definitions and macros for MCF_LCDC_LHCR */
+#define MCF_LCDC_LHCR_H_WAIT_2(x)       (((x)&0x000000FF)<<0)
+#define MCF_LCDC_LHCR_H_WAIT_1(x)       (((x)&0x000000FF)<<8)
+#define MCF_LCDC_LHCR_H_WIDTH(x)        (((x)&0x0000003F)<<26)
+
+/* Bit definitions and macros for MCF_LCDC_LVCR */
+#define MCF_LCDC_LVCR_V_WAIT_2(x)       (((x)&0x000000FF)<<0)
+#define MCF_LCDC_LVCR_V_WAIT_1(x)       (((x)&0x000000FF)<<8)
+#define MCF_LCDC_LVCR_V_WIDTH(x)      (((x)&0x0000003F)<<26)
+
+/* Bit definitions and macros for MCF_LCDC_LPOR */
+#define MCF_LCDC_LPOR_POS(x)            (((x)&0x0000001F)<<0)
+
+/* Bit definitions and macros for MCF_LCDC_LPCCR */
+#define MCF_LCDC_LPCCR_PW(x)            (((x)&0x000000FF)<<0)
+#define MCF_LCDC_LPCCR_CC_EN            (0x00000100)
+#define MCF_LCDC_LPCCR_SCR(x)           (((x)&0x00000003)<<9)
+#define MCF_LCDC_LPCCR_LDMSK            (0x00008000)
+#define MCF_LCDC_LPCCR_CLS_HI_WIDTH(x)  (((x)&0x000001FF)<<16)
+#define MCF_LCDC_LPCCR_SCR_LINEPULSE    (0x00000000)
+#define MCF_LCDC_LPCCR_SCR_PIXELCLK     (0x00002000)
+#define MCF_LCDC_LPCCR_SCR_LCDCLOCK     (0x00004000)
+
+/* Bit definitions and macros for MCF_LCDC_LDCR */
+#define MCF_LCDC_LDCR_TM(x)             (((x)&0x0000001F)<<0)
+#define MCF_LCDC_LDCR_HM(x)             (((x)&0x0000001F)<<16)
+#define MCF_LCDC_LDCR_BURST             (0x80000000)
+
+/* Bit definitions and macros for MCF_LCDC_LRMCR */
+#define MCF_LCDC_LRMCR_SEL_REF          (0x00000001)
+
+/* Bit definitions and macros for MCF_LCDC_LICR */
+#define MCF_LCDC_LICR_INTCON            (0x00000001)
+#define MCF_LCDC_LICR_INTSYN            (0x00000004)
+#define MCF_LCDC_LICR_GW_INT_CON        (0x00000010)
+
+/* Bit definitions and macros for MCF_LCDC_LIER */
+#define MCF_LCDC_LIER_BOF_EN            (0x00000001)
+#define MCF_LCDC_LIER_EOF_EN            (0x00000002)
+#define MCF_LCDC_LIER_ERR_RES_EN        (0x00000004)
+#define MCF_LCDC_LIER_UDR_ERR_EN        (0x00000008)
+#define MCF_LCDC_LIER_GW_BOF_EN         (0x00000010)
+#define MCF_LCDC_LIER_GW_EOF_EN         (0x00000020)
+#define MCF_LCDC_LIER_GW_ERR_RES_EN     (0x00000040)
+#define MCF_LCDC_LIER_GW_UDR_ERR_EN     (0x00000080)
+
+/* Bit definitions and macros for MCF_LCDC_LISR */
+#define MCF_LCDC_LISR_BOF               (0x00000001)
+#define MCF_LCDC_LISR_EOF               (0x00000002)
+#define MCF_LCDC_LISR_ERR_RES           (0x00000004)
+#define MCF_LCDC_LISR_UDR_ERR           (0x00000008)
+#define MCF_LCDC_LISR_GW_BOF            (0x00000010)
+#define MCF_LCDC_LISR_GW_EOF            (0x00000020)
+#define MCF_LCDC_LISR_GW_ERR_RES        (0x00000040)
+#define MCF_LCDC_LISR_GW_UDR_ERR        (0x00000080)
+
+/* Bit definitions and macros for MCF_LCDC_LGWSAR */
+#define MCF_LCDC_LGWSAR_GWSA(x)         (((x)&0x3FFFFFFF)<<2)
+
+/* Bit definitions and macros for MCF_LCDC_LGWSR */
+#define MCF_LCDC_LGWSR_GWH(x)           (((x)&0x000003FF)<<0)
+#define MCF_LCDC_LGWSR_GWW(x)           (((x)&0x0000003F)<<20)
+
+/* Bit definitions and macros for MCF_LCDC_LGWVPWR */
+#define MCF_LCDC_LGWVPWR_GWVPW(x)       (((x)&0x000003FF)<<0)
+
+/* Bit definitions and macros for MCF_LCDC_LGWPOR */
+#define MCF_LCDC_LGWPOR_GWPO(x)         (((x)&0x0000001F)<<0)
+
+/* Bit definitions and macros for MCF_LCDC_LGWPR */
+#define MCF_LCDC_LGWPR_GWYP(x)          (((x)&0x000003FF)<<0)
+#define MCF_LCDC_LGWPR_GWXP(x)          (((x)&0x000003FF)<<16)
+
+/* Bit definitions and macros for MCF_LCDC_LGWCR */
+#define MCF_LCDC_LGWCR_GWCKB(x)         (((x)&0x0000003F)<<0)
+#define MCF_LCDC_LGWCR_GWCKG(x)         (((x)&0x0000003F)<<6)
+#define MCF_LCDC_LGWCR_GWCKR(x)         (((x)&0x0000003F)<<12)
+#define MCF_LCDC_LGWCR_GW_RVS           (0x00200000)
+#define MCF_LCDC_LGWCR_GWE              (0x00400000)
+#define MCF_LCDC_LGWCR_GWCKE            (0x00800000)
+#define MCF_LCDC_LGWCR_GWAV(x)          (((x)&0x000000FF)<<24)
+
+/* Bit definitions and macros for MCF_LCDC_LGWDCR */
+#define MCF_LCDC_LGWDCR_GWTM(x)         (((x)&0x0000001F)<<0)
+#define MCF_LCDC_LGWDCR_GWHM(x)         (((x)&0x0000001F)<<16)
+#define MCF_LCDC_LGWDCR_GWBT            (0x80000000)
+
+/* Bit definitions and macros for MCF_LCDC_LSCR */
+#define MCF_LCDC_LSCR_PS_RISE_DELAY(x)    (((x)&0x0000003F)<<26)
+#define MCF_LCDC_LSCR_CLS_RISE_DELAY(x)   (((x)&0x000000FF)<<16)
+#define MCF_LCDC_LSCR_REV_TOGGLE_DELAY(x) (((x)&0x0000000F)<<8)
+#define MCF_LCDC_LSCR_GRAY_2(x)  		  (((x)&0x0000000F)<<4)
+#define MCF_LCDC_LSCR_GRAY_1(x)  		  (((x)&0x0000000F)<<0)
+
+/* Bit definitions and macros for MCF_LCDC_BPLUT_BASE */
+#define MCF_LCDC_BPLUT_BASE_BASE(x)     (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_LCDC_GWLUT_BASE */
+#define MCF_LCDC_GWLUT_BASE_BASE(x)     (((x)&0xFFFFFFFF)<<0)
+
+/*********************************************************************
+ *
+ * Phase Locked Loop (PLL)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_PLL_PODR              MCF_REG08(0xFC0C0000)
+#define MCF_PLL_PLLCR             MCF_REG08(0xFC0C0004)
+#define MCF_PLL_PMDR              MCF_REG08(0xFC0C0008)
+#define MCF_PLL_PFDR              MCF_REG08(0xFC0C000C)
+
+/* Bit definitions and macros for MCF_PLL_PODR */
+#define MCF_PLL_PODR_BUSDIV(x)    (((x)&0x0F)<<0)
+#define MCF_PLL_PODR_CPUDIV(x)    (((x)&0x0F)<<4)
+
+/* Bit definitions and macros for MCF_PLL_PLLCR */
+#define MCF_PLL_PLLCR_DITHDEV(x)  (((x)&0x07)<<0)
+#define MCF_PLL_PLLCR_DITHEN      (0x80)
+
+/* Bit definitions and macros for MCF_PLL_PMDR */
+#define MCF_PLL_PMDR_MODDIV(x)    (((x)&0xFF)<<0)
+
+/* Bit definitions and macros for MCF_PLL_PFDR */
+#define MCF_PLL_PFDR_MFD(x)       (((x)&0xFF)<<0)
+
+/*********************************************************************
+ *
+ * System Control Module Registers (SCM)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_SCM_MPR			MCF_REG32(0xFC000000)
+#define MCF_SCM_PACRA			MCF_REG32(0xFC000020)
+#define MCF_SCM_PACRB			MCF_REG32(0xFC000024)
+#define MCF_SCM_PACRC			MCF_REG32(0xFC000028)
+#define MCF_SCM_PACRD			MCF_REG32(0xFC00002C)
+#define MCF_SCM_PACRE			MCF_REG32(0xFC000040)
+#define MCF_SCM_PACRF			MCF_REG32(0xFC000044)
+
+#define MCF_SCM_BCR			MCF_REG32(0xFC040024)
+
+/*********************************************************************
+ *
+ * SDRAM Controller (SDRAMC)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_SDRAMC_SDMR			MCF_REG32(0xFC0B8000)
+#define MCF_SDRAMC_SDCR			MCF_REG32(0xFC0B8004)
+#define MCF_SDRAMC_SDCFG1		MCF_REG32(0xFC0B8008)
+#define MCF_SDRAMC_SDCFG2		MCF_REG32(0xFC0B800C)
+#define MCF_SDRAMC_LIMP_FIX		MCF_REG32(0xFC0B8080)
+#define MCF_SDRAMC_SDDS			MCF_REG32(0xFC0B8100)
+#define MCF_SDRAMC_SDCS0		MCF_REG32(0xFC0B8110)
+#define MCF_SDRAMC_SDCS1		MCF_REG32(0xFC0B8114)
+#define MCF_SDRAMC_SDCS2		MCF_REG32(0xFC0B8118)
+#define MCF_SDRAMC_SDCS3		MCF_REG32(0xFC0B811C)
+#define MCF_SDRAMC_SDCS(x)		MCF_REG32(0xFC0B8110+((x)*0x004))
+
+/* Bit definitions and macros for MCF_SDRAMC_SDMR */
+#define MCF_SDRAMC_SDMR_CMD		(0x00010000)
+#define MCF_SDRAMC_SDMR_AD(x)		(((x)&0x00000FFF)<<18)
+#define MCF_SDRAMC_SDMR_BNKAD(x)	(((x)&0x00000003)<<30)
+#define MCF_SDRAMC_SDMR_BNKAD_LMR	(0x00000000)
+#define MCF_SDRAMC_SDMR_BNKAD_LEMR	(0x40000000)
+
+/* Bit definitions and macros for MCF_SDRAMC_SDCR */
+#define MCF_SDRAMC_SDCR_IPALL		(0x00000002)
+#define MCF_SDRAMC_SDCR_IREF		(0x00000004)
+#define MCF_SDRAMC_SDCR_DQS_OE(x)	(((x)&0x0000000F)<<8)
+#define MCF_SDRAMC_SDCR_PS(x)		(((x)&0x00000003)<<12)
+#define MCF_SDRAMC_SDCR_RCNT(x)		(((x)&0x0000003F)<<16)
+#define MCF_SDRAMC_SDCR_OE_RULE		(0x00400000)
+#define MCF_SDRAMC_SDCR_MUX(x)		(((x)&0x00000003)<<24)
+#define MCF_SDRAMC_SDCR_REF		(0x10000000)
+#define MCF_SDRAMC_SDCR_DDR		(0x20000000)
+#define MCF_SDRAMC_SDCR_CKE		(0x40000000)
+#define MCF_SDRAMC_SDCR_MODE_EN		(0x80000000)
+#define MCF_SDRAMC_SDCR_PS_16		(0x00002000)
+#define MCF_SDRAMC_SDCR_PS_32		(0x00000000)
+
+/* Bit definitions and macros for MCF_SDRAMC_SDCFG1 */
+#define MCF_SDRAMC_SDCFG1_WTLAT(x)	(((x)&0x00000007)<<4)
+#define MCF_SDRAMC_SDCFG1_REF2ACT(x)	(((x)&0x0000000F)<<8)
+#define MCF_SDRAMC_SDCFG1_PRE2ACT(x)	(((x)&0x00000007)<<12)
+#define MCF_SDRAMC_SDCFG1_ACT2RW(x)	(((x)&0x00000007)<<16)
+#define MCF_SDRAMC_SDCFG1_RDLAT(x)	(((x)&0x0000000F)<<20)
+#define MCF_SDRAMC_SDCFG1_SWT2RD(x)	(((x)&0x00000007)<<24)
+#define MCF_SDRAMC_SDCFG1_SRD2RW(x)	(((x)&0x0000000F)<<28)
+
+/* Bit definitions and macros for MCF_SDRAMC_SDCFG2 */
+#define MCF_SDRAMC_SDCFG2_BL(x)		(((x)&0x0000000F)<<16)
+#define MCF_SDRAMC_SDCFG2_BRD2WT(x)	(((x)&0x0000000F)<<20)
+#define MCF_SDRAMC_SDCFG2_BWT2RW(x)	(((x)&0x0000000F)<<24)
+#define MCF_SDRAMC_SDCFG2_BRD2PRE(x)	(((x)&0x0000000F)<<28)
+
+/* Device Errata - LIMP mode work around */
+#define MCF_SDRAMC_REFRESH		(0x40000000)
+
+/* Bit definitions and macros for MCF_SDRAMC_SDDS */
+#define MCF_SDRAMC_SDDS_SB_D(x)		(((x)&0x00000003)<<0)
+#define MCF_SDRAMC_SDDS_SB_S(x)		(((x)&0x00000003)<<2)
+#define MCF_SDRAMC_SDDS_SB_A(x)		(((x)&0x00000003)<<4)
+#define MCF_SDRAMC_SDDS_SB_C(x)		(((x)&0x00000003)<<6)
+#define MCF_SDRAMC_SDDS_SB_E(x)		(((x)&0x00000003)<<8)
+
+/* Bit definitions and macros for MCF_SDRAMC_SDCS */
+#define MCF_SDRAMC_SDCS_CSSZ(x)		(((x)&0x0000001F)<<0)
+#define MCF_SDRAMC_SDCS_BASE(x)		(((x)&0x00000FFF)<<20)
+#define MCF_SDRAMC_SDCS_BA(x)		((x)&0xFFF00000)
+#define MCF_SDRAMC_SDCS_CSSZ_DIABLE	(0x00000000)
+#define MCF_SDRAMC_SDCS_CSSZ_1MBYTE	(0x00000013)
+#define MCF_SDRAMC_SDCS_CSSZ_2MBYTE	(0x00000014)
+#define MCF_SDRAMC_SDCS_CSSZ_4MBYTE	(0x00000015)
+#define MCF_SDRAMC_SDCS_CSSZ_8MBYTE	(0x00000016)
+#define MCF_SDRAMC_SDCS_CSSZ_16MBYTE	(0x00000017)
+#define MCF_SDRAMC_SDCS_CSSZ_32MBYTE	(0x00000018)
+#define MCF_SDRAMC_SDCS_CSSZ_64MBYTE	(0x00000019)
+#define MCF_SDRAMC_SDCS_CSSZ_128MBYTE	(0x0000001A)
+#define MCF_SDRAMC_SDCS_CSSZ_256MBYTE	(0x0000001B)
+#define MCF_SDRAMC_SDCS_CSSZ_512MBYTE	(0x0000001C)
+#define MCF_SDRAMC_SDCS_CSSZ_1GBYTE	(0x0000001D)
+#define MCF_SDRAMC_SDCS_CSSZ_2GBYTE	(0x0000001E)
+#define MCF_SDRAMC_SDCS_CSSZ_4GBYTE	(0x0000001F)
+
+/*********************************************************************
+ *
+ *      FlexCAN module registers
+ *
+ *********************************************************************/
+#define MCF_FLEXCAN_BASEADDR(x)		(0xFC020000+(x)*0x0800)
+#define MCF_FLEXCAN_CANMCR(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x00)
+#define MCF_FLEXCAN_CANCTRL(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x04)
+#define MCF_FLEXCAN_TIMER(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x08)
+#define MCF_FLEXCAN_RXGMASK(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x10)
+#define MCF_FLEXCAN_RX14MASK(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x14)
+#define MCF_FLEXCAN_RX15MASK(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x18)
+#define MCF_FLEXCAN_ERRCNT(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x1C)
+#define MCF_FLEXCAN_ERRSTAT(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x20)
+#define MCF_FLEXCAN_IMASK(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x28)
+#define MCF_FLEXCAN_IFLAG(x)		MCF_REG32(0xFC020000+(x)*0x0800+0x30)
+
+#define MCF_FLEXCAN_MB_CNT(x,y)		MCF_REG32(0xFC020080+(x)*0x0800+(y)*0x10+0x0)
+#define MCF_FLEXCAN_MB_ID(x,y)		MCF_REG32(0xFC020080+(x)*0x0800+(y)*0x10+0x4)
+#define MCF_FLEXCAN_MB_DB(x,y,z)	MCF_REG08(0xFC020080+(x)*0x0800+(y)*0x10+0x8+(z)*0x1)
+
+/*
+ *      FlexCAN Module Configuration Register
+ */
+#define CANMCR_MDIS		(0x80000000)
+#define CANMCR_FRZ		(0x40000000)
+#define CANMCR_HALT		(0x10000000)
+#define CANMCR_SOFTRST		(0x02000000)
+#define CANMCR_FRZACK		(0x01000000)
+#define CANMCR_SUPV		(0x00800000)
+#define CANMCR_MAXMB(x)         ((x)&0x0F)
+
+/*
+ *      FlexCAN Control Register
+ */
+#define CANCTRL_PRESDIV(x)      (((x)&0xFF)<<24)
+#define CANCTRL_RJW(x)          (((x)&0x03)<<22)
+#define CANCTRL_PSEG1(x)        (((x)&0x07)<<19)
+#define CANCTRL_PSEG2(x)        (((x)&0x07)<<16)
+#define CANCTRL_BOFFMSK         (0x00008000)
+#define CANCTRL_ERRMSK	        (0x00004000)
+#define CANCTRL_CLKSRC		(0x00002000)
+#define CANCTRL_LPB	        (0x00001000)
+#define CANCTRL_SAMP	        (0x00000080)
+#define CANCTRL_BOFFREC         (0x00000040)
+#define CANCTRL_TSYNC           (0x00000020)
+#define CANCTRL_LBUF            (0x00000010)
+#define CANCTRL_LOM             (0x00000008)
+#define CANCTRL_PROPSEG(x)      ((x)&0x07)
+
+/*
+ *      FlexCAN Error Counter Register
+ */
+#define ERRCNT_RXECTR(x)        (((x)&0xFF)<<8)
+#define ERRCNT_TXECTR(x)        ((x)&0xFF)
+
+/*
+ *      FlexCAN Error and Status Register
+ */
+#define ERRSTAT_BITERR(x)       (((x)&0x03)<<14)
+#define ERRSTAT_ACKERR           (0x00002000)
+#define ERRSTAT_CRCERR           (0x00001000)
+#define ERRSTAT_FRMERR           (0x00000800)
+#define ERRSTAT_STFERR           (0x00000400)
+#define ERRSTAT_TXWRN            (0x00000200)
+#define ERRSTAT_RXWRN            (0x00000100)
+#define ERRSTAT_IDLE             (0x00000080)
+#define ERRSTAT_TXRX             (0x00000040)
+#define ERRSTAT_FLTCONF(x)       (((x)&0x03)<<4)
+#define ERRSTAT_BOFFINT          (0x00000004)
+#define ERRSTAT_ERRINT           (0x00000002)
+
+/*
+ *      Interrupt Mask Register
+ */
+#define IMASK_BUF15M		(0x8000)
+#define IMASK_BUF14M		(0x4000)
+#define IMASK_BUF13M		(0x2000)
+#define IMASK_BUF12M		(0x1000)
+#define IMASK_BUF11M		(0x0800)
+#define IMASK_BUF10M		(0x0400)
+#define IMASK_BUF9M		(0x0200)
+#define IMASK_BUF8M		(0x0100)
+#define IMASK_BUF7M		(0x0080)
+#define IMASK_BUF6M		(0x0040)
+#define IMASK_BUF5M		(0x0020)
+#define IMASK_BUF4M		(0x0010)
+#define IMASK_BUF3M		(0x0008)
+#define IMASK_BUF2M		(0x0004)
+#define IMASK_BUF1M		(0x0002)
+#define IMASK_BUF0M		(0x0001)
+#define IMASK_BUFnM(x)		(0x1<<(x))
+#define IMASK_BUFF_ENABLE_ALL	(0x1111)
+#define IMASK_BUFF_DISABLE_ALL	(0x0000)
+
+/*
+ *      Interrupt Flag Register
+ */
+#define IFLAG_BUF15M		(0x8000)
+#define IFLAG_BUF14M		(0x4000)
+#define IFLAG_BUF13M		(0x2000)
+#define IFLAG_BUF12M		(0x1000)
+#define IFLAG_BUF11M		(0x0800)
+#define IFLAG_BUF10M		(0x0400)
+#define IFLAG_BUF9M		(0x0200)
+#define IFLAG_BUF8M		(0x0100)
+#define IFLAG_BUF7M		(0x0080)
+#define IFLAG_BUF6M		(0x0040)
+#define IFLAG_BUF5M		(0x0020)
+#define IFLAG_BUF4M		(0x0010)
+#define IFLAG_BUF3M		(0x0008)
+#define IFLAG_BUF2M		(0x0004)
+#define IFLAG_BUF1M		(0x0002)
+#define IFLAG_BUF0M		(0x0001)
+#define IFLAG_BUFF_SET_ALL	(0xFFFF)
+#define IFLAG_BUFF_CLEAR_ALL	(0x0000)
+#define IFLAG_BUFnM(x)		(0x1<<(x))
+
+/*
+ *      Message Buffers
+ */
+#define MB_CNT_CODE(x)		(((x)&0x0F)<<24)
+#define MB_CNT_SRR		(0x00400000)
+#define MB_CNT_IDE		(0x00200000)
+#define MB_CNT_RTR		(0x00100000)
+#define MB_CNT_LENGTH(x)	(((x)&0x0F)<<16)
+#define MB_CNT_TIMESTAMP(x)	((x)&0xFFFF)
+#define MB_ID_STD(x)		(((x)&0x07FF)<<18)
+#define MB_ID_EXT(x)		((x)&0x3FFFF)
+
+/*********************************************************************
+ *
+ * Edge Port Module (EPORT)
+ *
+ *********************************************************************/
+
+/* Register read/write macros */
+#define MCF_EPORT_EPPAR                MCF_REG16(0xFC094000)
+#define MCF_EPORT_EPDDR                MCF_REG08(0xFC094002)
+#define MCF_EPORT_EPIER                MCF_REG08(0xFC094003)
+#define MCF_EPORT_EPDR                 MCF_REG08(0xFC094004)
+#define MCF_EPORT_EPPDR                MCF_REG08(0xFC094005)
+#define MCF_EPORT_EPFR                 MCF_REG08(0xFC094006)
+
+/* Bit definitions and macros for MCF_EPORT_EPPAR */
+#define MCF_EPORT_EPPAR_EPPA1(x)       (((x)&0x0003)<<2)
+#define MCF_EPORT_EPPAR_EPPA2(x)       (((x)&0x0003)<<4)
+#define MCF_EPORT_EPPAR_EPPA3(x)       (((x)&0x0003)<<6)
+#define MCF_EPORT_EPPAR_EPPA4(x)       (((x)&0x0003)<<8)
+#define MCF_EPORT_EPPAR_EPPA5(x)       (((x)&0x0003)<<10)
+#define MCF_EPORT_EPPAR_EPPA6(x)       (((x)&0x0003)<<12)
+#define MCF_EPORT_EPPAR_EPPA7(x)       (((x)&0x0003)<<14)
+#define MCF_EPORT_EPPAR_LEVEL          (0)
+#define MCF_EPORT_EPPAR_RISING         (1)
+#define MCF_EPORT_EPPAR_FALLING        (2)
+#define MCF_EPORT_EPPAR_BOTH           (3)
+#define MCF_EPORT_EPPAR_EPPA7_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA7_RISING   (0x4000)
+#define MCF_EPORT_EPPAR_EPPA7_FALLING  (0x8000)
+#define MCF_EPORT_EPPAR_EPPA7_BOTH     (0xC000)
+#define MCF_EPORT_EPPAR_EPPA6_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA6_RISING   (0x1000)
+#define MCF_EPORT_EPPAR_EPPA6_FALLING  (0x2000)
+#define MCF_EPORT_EPPAR_EPPA6_BOTH     (0x3000)
+#define MCF_EPORT_EPPAR_EPPA5_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA5_RISING   (0x0400)
+#define MCF_EPORT_EPPAR_EPPA5_FALLING  (0x0800)
+#define MCF_EPORT_EPPAR_EPPA5_BOTH     (0x0C00)
+#define MCF_EPORT_EPPAR_EPPA4_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA4_RISING   (0x0100)
+#define MCF_EPORT_EPPAR_EPPA4_FALLING  (0x0200)
+#define MCF_EPORT_EPPAR_EPPA4_BOTH     (0x0300)
+#define MCF_EPORT_EPPAR_EPPA3_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA3_RISING   (0x0040)
+#define MCF_EPORT_EPPAR_EPPA3_FALLING  (0x0080)
+#define MCF_EPORT_EPPAR_EPPA3_BOTH     (0x00C0)
+#define MCF_EPORT_EPPAR_EPPA2_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA2_RISING   (0x0010)
+#define MCF_EPORT_EPPAR_EPPA2_FALLING  (0x0020)
+#define MCF_EPORT_EPPAR_EPPA2_BOTH     (0x0030)
+#define MCF_EPORT_EPPAR_EPPA1_LEVEL    (0x0000)
+#define MCF_EPORT_EPPAR_EPPA1_RISING   (0x0004)
+#define MCF_EPORT_EPPAR_EPPA1_FALLING  (0x0008)
+#define MCF_EPORT_EPPAR_EPPA1_BOTH     (0x000C)
+
+/* Bit definitions and macros for MCF_EPORT_EPDDR */
+#define MCF_EPORT_EPDDR_EPDD1          (0x02)
+#define MCF_EPORT_EPDDR_EPDD2          (0x04)
+#define MCF_EPORT_EPDDR_EPDD3          (0x08)
+#define MCF_EPORT_EPDDR_EPDD4          (0x10)
+#define MCF_EPORT_EPDDR_EPDD5          (0x20)
+#define MCF_EPORT_EPDDR_EPDD6          (0x40)
+#define MCF_EPORT_EPDDR_EPDD7          (0x80)
+
+/* Bit definitions and macros for MCF_EPORT_EPIER */
+#define MCF_EPORT_EPIER_EPIE1          (0x02)
+#define MCF_EPORT_EPIER_EPIE2          (0x04)
+#define MCF_EPORT_EPIER_EPIE3          (0x08)
+#define MCF_EPORT_EPIER_EPIE4          (0x10)
+#define MCF_EPORT_EPIER_EPIE5          (0x20)
+#define MCF_EPORT_EPIER_EPIE6          (0x40)
+#define MCF_EPORT_EPIER_EPIE7          (0x80)
+
+/* Bit definitions and macros for MCF_EPORT_EPDR */
+#define MCF_EPORT_EPDR_EPD1            (0x02)
+#define MCF_EPORT_EPDR_EPD2            (0x04)
+#define MCF_EPORT_EPDR_EPD3            (0x08)
+#define MCF_EPORT_EPDR_EPD4            (0x10)
+#define MCF_EPORT_EPDR_EPD5            (0x20)
+#define MCF_EPORT_EPDR_EPD6            (0x40)
+#define MCF_EPORT_EPDR_EPD7            (0x80)
+
+/* Bit definitions and macros for MCF_EPORT_EPPDR */
+#define MCF_EPORT_EPPDR_EPPD1          (0x02)
+#define MCF_EPORT_EPPDR_EPPD2          (0x04)
+#define MCF_EPORT_EPPDR_EPPD3          (0x08)
+#define MCF_EPORT_EPPDR_EPPD4          (0x10)
+#define MCF_EPORT_EPPDR_EPPD5          (0x20)
+#define MCF_EPORT_EPPDR_EPPD6          (0x40)
+#define MCF_EPORT_EPPDR_EPPD7          (0x80)
+
+/* Bit definitions and macros for MCF_EPORT_EPFR */
+#define MCF_EPORT_EPFR_EPF1            (0x02)
+#define MCF_EPORT_EPFR_EPF2            (0x04)
+#define MCF_EPORT_EPFR_EPF3            (0x08)
+#define MCF_EPORT_EPFR_EPF4            (0x10)
+#define MCF_EPORT_EPFR_EPF5            (0x20)
+#define MCF_EPORT_EPFR_EPF6            (0x40)
+#define MCF_EPORT_EPFR_EPF7            (0x80)
+
+/********************************************************************/
+#endif	/* m532xsim_h */
diff --git a/include/asm-m68knommu/mcfcache.h b/include/asm-m68knommu/mcfcache.h
index 45d1ac5..7b61a8a 100644
--- a/include/asm-m68knommu/mcfcache.h
+++ b/include/asm-m68knommu/mcfcache.h
@@ -92,6 +92,21 @@
 .endm
 #endif /* CONFIG_M5249 || CONFIG_M5307 */
 
+#if defined(CONFIG_M532x)
+.macro CACHE_ENABLE
+	movel	#0x01000000,%d0		/* invalidate cache cmd */
+	movec	%d0,%CACR		/* do invalidate cache */
+	nop
+	movel	#0x4001C000,%d0		/* set SDRAM cached (write-thru) */
+	movec	%d0,%ACR0
+	movel	#0x00000000,%d0		/* no other regions cached */
+	movec	%d0,%ACR1
+	movel	#0x80000200,%d0		/* setup cache mask */
+	movec	%d0,%CACR		/* enable cache */
+	nop
+.endm
+#endif /* CONFIG_M532x */
+
 #if defined(CONFIG_M5407)
 /*
  *	Version 4 cores have a true harvard style separate instruction
diff --git a/include/asm-m68knommu/mcfpit.h b/include/asm-m68knommu/mcfpit.h
index 0d2672d..f570cf6 100644
--- a/include/asm-m68knommu/mcfpit.h
+++ b/include/asm-m68knommu/mcfpit.h
@@ -28,11 +28,9 @@
 /*
  *	Define the PIT timer register set addresses.
  */
-struct mcfpit {
-	unsigned short	pcsr;			/* PIT control and status */
-	unsigned short	pmr;			/* PIT modulus register */
-	unsigned short	pcntr;			/* PIT count register */
-} __attribute__((packed));
+#define	MCFPIT_PCSR		0x0		/* PIT control register */
+#define	MCFPIT_PMR		0x2		/* PIT modulus register */
+#define	MCFPIT_PCNTR		0x4		/* PIT count register */
 
 /*
  *	Bit definitions for the PIT Control and Status register.
diff --git a/include/asm-m68knommu/mcfsim.h b/include/asm-m68knommu/mcfsim.h
index 97a0c27..1074ae7 100644
--- a/include/asm-m68knommu/mcfsim.h
+++ b/include/asm-m68knommu/mcfsim.h
@@ -35,6 +35,8 @@
 #include <asm/m528xsim.h>
 #elif defined(CONFIG_M5307)
 #include <asm/m5307sim.h>
+#elif defined(CONFIG_M532x)
+#include <asm/m532xsim.h>
 #elif defined(CONFIG_M5407)
 #include <asm/m5407sim.h>
 #endif
@@ -100,6 +102,7 @@
 #define	MCFSIM_IMR_MASKALL	0x3ffe		/* All intr sources */
 #endif
 
+
 /*
  *	PIT interrupt settings, if not found in mXXXXsim.h file.
  */
diff --git a/include/asm-m68knommu/mcftimer.h b/include/asm-m68knommu/mcftimer.h
index 68bf33a..6f4d796 100644
--- a/include/asm-m68knommu/mcftimer.h
+++ b/include/asm-m68knommu/mcftimer.h
@@ -3,7 +3,7 @@
 /*
  *	mcftimer.h -- ColdFire internal TIMER support defines.
  *
- *	(C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *	(C) Copyright 1999-2006, Greg Ungerer <gerg@snapgear.com>
  * 	(C) Copyright 2000, Lineo Inc. (www.lineo.com) 
  */
 
@@ -27,6 +27,11 @@
 #elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
 #define MCFTIMER_BASE1		0x140           /* Base address of TIMER1 */
 #define MCFTIMER_BASE2		0x180           /* Base address of TIMER2 */
+#elif defined(CONFIG_M532x)
+#define MCFTIMER_BASE1		0xfc070000	/* Base address of TIMER1 */
+#define MCFTIMER_BASE2		0xfc074000	/* Base address of TIMER2 */
+#define MCFTIMER_BASE3		0xfc078000	/* Base address of TIMER3 */
+#define MCFTIMER_BASE4		0xfc07c000	/* Base address of TIMER4 */
 #endif
 
 
@@ -34,23 +39,14 @@
  *	Define the TIMER register set addresses.
  */
 #define	MCFTIMER_TMR		0x00		/* Timer Mode reg (r/w) */
-#define	MCFTIMER_TRR		0x02		/* Timer Reference (r/w) */
-#define	MCFTIMER_TCR		0x04		/* Timer Capture reg (r/w) */
-#define	MCFTIMER_TCN		0x06		/* Timer Counter reg (r/w) */
+#define	MCFTIMER_TRR		0x04		/* Timer Reference (r/w) */
+#define	MCFTIMER_TCR		0x08		/* Timer Capture reg (r/w) */
+#define	MCFTIMER_TCN		0x0C		/* Timer Counter reg (r/w) */
+#if defined(CONFIG_M532x)
+#define	MCFTIMER_TER		0x03		/* Timer Event reg (r/w) */
+#else
 #define	MCFTIMER_TER		0x11		/* Timer Event reg (r/w) */
-
-struct mcftimer {
-	unsigned short	tmr;			/* Timer Mode reg (r/w) */
-	unsigned short	reserved1;
-	unsigned short	trr;			/* Timer Reference (r/w) */
-	unsigned short	reserved2;
-	unsigned short	tcr;			/* Timer Capture reg (r/w) */
-	unsigned short	reserved3;
-	unsigned short	tcn;			/* Timer Counter reg (r/w) */
-	unsigned short	reserved4;
-	unsigned char	reserved5;
-	unsigned char	ter;			/* Timer Event reg (r/w) */
-} __attribute__((packed));
+#endif
 
 /*
  *	Bit definitions for the Timer Mode Register (TMR).
diff --git a/include/asm-m68knommu/mcfuart.h b/include/asm-m68knommu/mcfuart.h
index 8040e43..dc0146c 100644
--- a/include/asm-m68knommu/mcfuart.h
+++ b/include/asm-m68knommu/mcfuart.h
@@ -44,6 +44,10 @@
 #define MCFUART_BASE1		0x60000		/* Base address of UART1 */
 #define MCFUART_BASE2		0x64000		/* Base address of UART2 */
 #define MCFUART_BASE3		0x68000		/* Base address of UART2 */
+#elif defined(CONFIG_M532x)
+#define MCFUART_BASE1		0xfc060000	/* Base address of UART1 */
+#define MCFUART_BASE2		0xfc064000	/* Base address of UART2 */
+#define MCFUART_BASE3		0xfc068000	/* Base address of UART3 */
 #endif
 
 
diff --git a/include/asm-m68knommu/page_offset.h b/include/asm-m68knommu/page_offset.h
index 8ed6d7b..d4e73e0 100644
--- a/include/asm-m68knommu/page_offset.h
+++ b/include/asm-m68knommu/page_offset.h
@@ -1,46 +1,5 @@
 
 
 /* This handles the memory map.. */
-
-#ifdef CONFIG_COLDFIRE
-#if defined(CONFIG_SMALL)
-#define PAGE_OFFSET_RAW		0x30020000
-#elif defined(CONFIG_CFV240)
-#define PAGE_OFFSET_RAW		0x02000000
-#else
-#define PAGE_OFFSET_RAW		0x00000000
-#endif
-#endif
-
-#ifdef CONFIG_M68360
-#define PAGE_OFFSET_RAW     0x00000000
-#endif
-
-#ifdef CONFIG_PILOT
-#ifdef CONFIG_M68328
-#define PAGE_OFFSET_RAW		0x10000000
-#endif
-#ifdef CONFIG_M68EZ328
-#define PAGE_OFFSET_RAW		0x00000000
-#endif
-#endif
-#ifdef CONFIG_UCSIMM
-#define PAGE_OFFSET_RAW		0x00000000
-#endif
-
-#if defined(CONFIG_UCDIMM) || defined(CONFIG_DRAGEN2)
-#ifdef CONFIG_M68VZ328 
-#define PAGE_OFFSET_RAW		0x00000000
-#endif /* CONFIG_M68VZ328 */
-#endif /* CONFIG_UCDIMM */
-
-#ifdef CONFIG_M68EZ328ADS
-#define PAGE_OFFSET_RAW		0x00000000
-#endif
-#ifdef CONFIG_ALMA_ANS
-#define PAGE_OFFSET_RAW		0x00000000
-#endif
-#ifdef CONFIG_M68EN302
-#define PAGE_OFFSET_RAW		0x00000000
-#endif
+#define	PAGE_OFFSET_RAW		CONFIG_RAMBASE
 
diff --git a/include/asm-m68knommu/processor.h b/include/asm-m68knommu/processor.h
index 278b00b..0ee158e 100644
--- a/include/asm-m68knommu/processor.h
+++ b/include/asm-m68knommu/processor.h
@@ -78,19 +78,31 @@
 }
 
 /*
+ * Coldfire stacks need to be re-aligned on trap exit, conventional
+ * 68k can handle this case cleanly.
+ */
+#if defined(CONFIG_COLDFIRE)
+#define	reformat(_regs)		do { (_regs)->format = 0x4; } while(0)
+#else
+#define	reformat(_regs)		do { } while (0)
+#endif
+
+/*
  * Do necessary setup to start up a newly executed thread.
  *
  * pass the data segment into user programs if it exists,
  * it can't hurt anything as far as I can tell
  */
-#define start_thread(_regs, _pc, _usp)           \
-do {                                             \
-	set_fs(USER_DS); /* reads from user space */ \
-	(_regs)->pc = (_pc);                         \
-	if (current->mm)                             \
-		(_regs)->d5 = current->mm->start_data;   \
-	(_regs)->sr &= ~0x2000;                      \
-	wrusp(_usp);                                 \
+#define start_thread(_regs, _pc, _usp)			\
+do {							\
+	set_fs(USER_DS); /* reads from user space */	\
+	(_regs)->pc = (_pc);				\
+	((struct switch_stack *)(_regs))[-1].a6 = 0;	\
+	reformat(_regs);				\
+	if (current->mm)				\
+		(_regs)->d5 = current->mm->start_data;	\
+	(_regs)->sr &= ~0x2000;				\
+	wrusp(_usp);					\
 } while(0)
 
 /* Forward declaration, a strange C thing */
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 986511d..900f472 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -145,8 +145,5 @@
 
 	return (void __user *) (regs->regs[29] - len);
 }
-#if defined (__MIPSEL__)
-#define __COMPAT_ENDIAN_SWAP__ 	1
-#endif
 
 #endif /* _ASM_COMPAT_H */
diff --git a/include/asm-mips/mach-generic/floppy.h b/include/asm-mips/mach-generic/floppy.h
index 682a585..83cd69e 100644
--- a/include/asm-mips/mach-generic/floppy.h
+++ b/include/asm-mips/mach-generic/floppy.h
@@ -98,7 +98,7 @@
 static inline int fd_request_irq(void)
 {
 	return request_irq(FLOPPY_IRQ, floppy_interrupt,
-	                   SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
+	                   SA_INTERRUPT, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
diff --git a/include/asm-mips/mach-jazz/floppy.h b/include/asm-mips/mach-jazz/floppy.h
index c9dad99..9413117 100644
--- a/include/asm-mips/mach-jazz/floppy.h
+++ b/include/asm-mips/mach-jazz/floppy.h
@@ -90,7 +90,7 @@
 static inline int fd_request_irq(void)
 {
 	return request_irq(FLOPPY_IRQ, floppy_interrupt,
-	                   SA_INTERRUPT | SA_SAMPLE_RANDOM, "floppy", NULL);
+	                   SA_INTERRUPT, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
diff --git a/include/asm-parisc/floppy.h b/include/asm-parisc/floppy.h
index ca3aed7..458cdb2 100644
--- a/include/asm-parisc/floppy.h
+++ b/include/asm-parisc/floppy.h
@@ -159,10 +159,8 @@
 		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
 						   "floppy", NULL);
 	else
-		return request_irq(FLOPPY_IRQ, floppy_interrupt,
-						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
-						   "floppy", NULL);	
-
+		return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+				   "floppy", NULL);
 }
 
 static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/include/asm-powerpc/backlight.h b/include/asm-powerpc/backlight.h
index 1ba1f27..a5e9e65 100644
--- a/include/asm-powerpc/backlight.h
+++ b/include/asm-powerpc/backlight.h
@@ -2,30 +2,30 @@
  * Routines for handling backlight control on PowerBooks
  *
  * For now, implementation resides in
- * arch/powerpc/platforms/powermac/pmac_support.c
+ * arch/powerpc/platforms/powermac/backlight.c
  *
  */
 #ifndef __ASM_POWERPC_BACKLIGHT_H
 #define __ASM_POWERPC_BACKLIGHT_H
 #ifdef __KERNEL__
 
-/* Abstract values */
-#define BACKLIGHT_OFF	0
-#define BACKLIGHT_MIN	1
-#define BACKLIGHT_MAX	0xf
+#include <linux/fb.h>
+#include <linux/mutex.h>
 
-struct backlight_controller {
-	int (*set_enable)(int enable, int level, void *data);
-	int (*set_level)(int level, void *data);
-};
+/* For locking instructions, see the implementation file */
+extern struct backlight_device *pmac_backlight;
+extern struct mutex pmac_backlight_mutex;
 
-extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type);
-extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data);
+extern void pmac_backlight_calc_curve(struct fb_info*);
+extern int pmac_backlight_curve_lookup(struct fb_info *info, int value);
 
-extern int set_backlight_enable(int enable);
-extern int get_backlight_enable(void);
-extern int set_backlight_level(int level);
-extern int get_backlight_level(void);
+extern int pmac_has_backlight_type(const char *type);
+
+extern void pmac_backlight_key_up(void);
+extern void pmac_backlight_key_down(void);
+
+extern int pmac_backlight_set_legacy_brightness(int brightness);
+extern int pmac_backlight_get_legacy_brightness(void);
 
 #endif /* __KERNEL__ */
 #endif
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h
index 7e2d169..9c8d91b 100644
--- a/include/asm-powerpc/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -27,8 +27,7 @@
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
 #define fd_cacheflush(addr,size) /* nothing */
 #define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
-					    SA_INTERRUPT|SA_SAMPLE_RANDOM, \
-				            "floppy", NULL)
+					    SA_INTERRUPT, "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
 
 #ifdef CONFIG_PCI
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h
index c01786a..532bfee 100644
--- a/include/asm-powerpc/kdebug.h
+++ b/include/asm-powerpc/kdebug.h
@@ -18,6 +18,8 @@
 
 extern int register_die_notifier(struct notifier_block *);
 extern int unregister_die_notifier(struct notifier_block *);
+extern int register_page_fault_notifier(struct notifier_block *);
+extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head powerpc_die_chain;
 
 /* Grossly misnamed. */
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index f466bc8..2d0af52 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -50,6 +50,8 @@
 			IS_TWI(instr) || IS_TDI(instr))
 
 #define ARCH_SUPPORTS_KRETPROBES
+#define  ARCH_INACTIVE_KPROBE_COUNT 1
+
 void kretprobe_trampoline(void);
 extern void arch_remove_kprobe(struct kprobe *p);
 
diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h
index 184a7a4..faa1fc7 100644
--- a/include/asm-powerpc/percpu.h
+++ b/include/asm-powerpc/percpu.h
@@ -22,6 +22,7 @@
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)			\
@@ -41,6 +42,7 @@
 
 #define per_cpu(var, cpu)			(*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)			per_cpu__##var
+#define __raw_get_cpu_var(var)			per_cpu__##var
 
 #endif	/* SMP */
 
diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
index 8ccd4a2..2ba191e 100644
--- a/include/asm-ppc/floppy.h
+++ b/include/asm-ppc/floppy.h
@@ -99,10 +99,8 @@
 		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
 						   "floppy", NULL);
 	else
-		return request_irq(FLOPPY_IRQ, floppy_interrupt,
-						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
-						   "floppy", NULL);
-
+		return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+				   "floppy", NULL);
 }
 
 static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
index 436d216..d9a8cca 100644
--- a/include/asm-s390/percpu.h
+++ b/include/asm-s390/percpu.h
@@ -40,6 +40,7 @@
     __typeof__(type) per_cpu__##name
 
 #define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
+#define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
 #define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu])
 
 /* A macro to avoid #include hell... */
@@ -57,6 +58,7 @@
     __typeof__(type) per_cpu__##name
 
 #define __get_cpu_var(var) __reloc_hide(var,0)
+#define __raw_get_cpu_var(var) __reloc_hide(var,0)
 #define per_cpu(var,cpu) __reloc_hide(var,0)
 
 #endif /* SMP */
diff --git a/include/asm-sh/floppy.h b/include/asm-sh/floppy.h
index 38d7a29..307d9ce 100644
--- a/include/asm-sh/floppy.h
+++ b/include/asm-sh/floppy.h
@@ -147,11 +147,10 @@
 {
 	if(can_use_virtual_dma)
 		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
-						   "floppy", NULL);
+				   "floppy", NULL);
 	else
-		return request_irq(FLOPPY_IRQ, floppy_interrupt,
-						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
-						   "floppy", NULL);	
+		return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+				   "floppy", NULL);
 
 }
 
diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h
index a42df20..cab0b85 100644
--- a/include/asm-sparc/io.h
+++ b/include/asm-sparc/io.h
@@ -249,6 +249,22 @@
 #define ioremap_nocache(X,Y)	ioremap((X),(Y))
 extern void iounmap(volatile void __iomem *addr);
 
+#define ioread8(X)			readb(X)
+#define ioread16(X)			readw(X)
+#define ioread32(X)			readl(X)
+#define iowrite8(val,X)			writeb(val,X)
+#define iowrite16(val,X)		writew(val,X)
+#define iowrite32(val,X)		writel(val,X)
+
+/* Create a virtual mapping cookie for an IO port range */
+extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+extern void ioport_unmap(void __iomem *);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+
 /*
  * Bus number may be in res->flags... somewhere.
  */
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index c5e3d26..f9cf44c 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -35,6 +35,8 @@
 	int	length;
 	void	*value;
 	struct property *next;
+	unsigned long _flags;
+	unsigned int unique_id;
 };
 
 struct device_node {
@@ -58,8 +60,15 @@
 	struct  kref kref;
 	unsigned long _flags;
 	void	*data;
+	unsigned int unique_id;
 };
 
+/* flag descriptions */
+#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
+
+#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
+#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
+
 static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
 {
 	dn->pde = de;
@@ -88,6 +97,7 @@
 extern int of_device_is_compatible(struct device_node *device, const char *);
 extern void *of_get_property(struct device_node *node, const char *name,
 			     int *lenp);
+extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
 				 const char *name,
 				 int def);
diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h
index 3c2b5bc..0f5b89c 100644
--- a/include/asm-sparc64/dma-mapping.h
+++ b/include/asm-sparc64/dma-mapping.h
@@ -162,4 +162,47 @@
 
 #endif /* PCI */
 
+
+/* Now for the API extensions over the pci_ one */
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d)	(1)
+
+static inline int
+dma_get_cache_alignment(void)
+{
+	/* no easy way to get cache size on all processors, so return
+	 * the maximum possible, to be safe */
+	return (1 << INTERNODE_CACHE_SHIFT);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			      unsigned long offset, size_t size,
+			      enum dma_data_direction direction)
+{
+	/* just sync everything, that's all the pci API can do */
+	dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+				 unsigned long offset, size_t size,
+				 enum dma_data_direction direction)
+{
+	/* just sync everything, that's all the pci API can do */
+	dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
+}
+
+static inline void
+dma_cache_sync(void *vaddr, size_t size,
+	       enum dma_data_direction direction)
+{
+	/* could define this in terms of the dma_cache ... operations,
+	 * but if you get this on a platform, you should convert the platform
+	 * to using the generic device DMA API */
+	BUG();
+}
+
 #endif /* _ASM_SPARC64_DMA_MAPPING_H */
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index f8d57bb..b591d0e 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -208,7 +208,55 @@
 	pdma_areasize = pdma_size;
 }
 
-extern irqreturn_t sparc_floppy_irq(int, void *, struct pt_regs *);
+irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+{
+	if (likely(doing_pdma)) {
+		void __iomem *stat = (void __iomem *) fdc_status;
+		unsigned char *vaddr = pdma_vaddr;
+		unsigned long size = pdma_size;
+		u8 val;
+
+		while (size) {
+			val = readb(stat);
+			if (unlikely(!(val & 0x80))) {
+				pdma_vaddr = vaddr;
+				pdma_size = size;
+				return IRQ_HANDLED;
+			}
+			if (unlikely(!(val & 0x20))) {
+				pdma_vaddr = vaddr;
+				pdma_size = size;
+				doing_pdma = 0;
+				goto main_interrupt;
+			}
+			if (val & 0x40) {
+				/* read */
+				*vaddr++ = readb(stat + 1);
+			} else {
+				unsigned char data = *vaddr++;
+
+				/* write */
+				writeb(data, stat + 1);
+			}
+			size--;
+		}
+
+		pdma_vaddr = vaddr;
+		pdma_size = size;
+
+		/* Send Terminal Count pulse to floppy controller. */
+		val = readb(auxio_register);
+		val |= AUXIO_AUX1_FTCNT;
+		writeb(val, auxio_register);
+		val &= ~AUXIO_AUX1_FTCNT;
+		writeb(val, auxio_register);
+
+		doing_pdma = 0;
+	}
+
+main_interrupt:
+	return floppy_interrupt(irq, dev_cookie, regs);
+}
 
 static int sun_fd_request_irq(void)
 {
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
index 4040d12..11251bd 100644
--- a/include/asm-sparc64/kdebug.h
+++ b/include/asm-sparc64/kdebug.h
@@ -17,6 +17,8 @@
 
 extern int register_die_notifier(struct notifier_block *);
 extern int unregister_die_notifier(struct notifier_block *);
+extern int register_page_fault_notifier(struct notifier_block *);
+extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head sparc64die_chain;
 
 extern void bad_trap(struct pt_regs *, long);
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
index e9bb26f..15065af 100644
--- a/include/asm-sparc64/kprobes.h
+++ b/include/asm-sparc64/kprobes.h
@@ -12,6 +12,7 @@
 
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)pentry
 #define arch_remove_kprobe(p)	do {} while (0)
+#define  ARCH_INACTIVE_KPROBE_COUNT 0
 
 /* Architecture specific copy of original instruction*/
 struct arch_specific_insn {
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
index baef13b..a6ece06 100644
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -21,6 +21,7 @@
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)			\
@@ -37,6 +38,7 @@
 
 #define per_cpu(var, cpu)			(*((void)cpu, &per_cpu__##var))
 #define __get_cpu_var(var)			per_cpu__##var
+#define __raw_get_cpu_var(var)			per_cpu__##var
 
 #endif	/* SMP */
 
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
index 6d1556c..265614d 100644
--- a/include/asm-sparc64/prom.h
+++ b/include/asm-sparc64/prom.h
@@ -35,6 +35,8 @@
 	int	length;
 	void	*value;
 	struct property *next;
+	unsigned long _flags;
+	unsigned int unique_id;
 };
 
 struct device_node {
@@ -58,8 +60,15 @@
 	struct  kref kref;
 	unsigned long _flags;
 	void	*data;
+	unsigned int unique_id;
 };
 
+/* flag descriptions */
+#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
+
+#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
+#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
+
 static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
 {
 	dn->pde = de;
@@ -88,6 +97,7 @@
 extern int of_device_is_compatible(struct device_node *device, const char *);
 extern void *of_get_property(struct device_node *node, const char *name,
 			     int *lenp);
+extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
 				 const char *name,
 				 int def);
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
new file mode 100644
index 0000000..387c8f6
--- /dev/null
+++ b/include/asm-x86_64/alternative.h
@@ -0,0 +1,146 @@
+#ifndef _X86_64_ALTERNATIVE_H
+#define _X86_64_ALTERNATIVE_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+
+struct alt_instr {
+	u8 *instr; 		/* original instruction */
+	u8 *replacement;
+	u8  cpuid;		/* cpuid bit set for replacement */
+	u8  instrlen;		/* length of original instruction */
+	u8  replacementlen; 	/* length of new instruction, <= instrlen */
+	u8  pad[5];
+};
+
+extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
+
+struct module;
+extern void alternatives_smp_module_add(struct module *mod, char *name,
+					void *locks, void *locks_end,
+					void *text, void *text_end);
+extern void alternatives_smp_module_del(struct module *mod);
+extern void alternatives_smp_switch(int smp);
+
+#endif
+
+/*
+ * Alternative instructions for different CPU types or capabilities.
+ *
+ * This allows to use optimized instructions even on generic binary
+ * kernels.
+ *
+ * length of oldinstr must be longer or equal the length of newinstr
+ * It can be padded with nops as needed.
+ *
+ * For non barrier like inlines please define new variants
+ * without volatile and memory clobber.
+ */
+#define alternative(oldinstr, newinstr, feature) 	\
+	asm volatile ("661:\n\t" oldinstr "\n662:\n" 		     \
+		      ".section .altinstructions,\"a\"\n"     	     \
+		      "  .align 8\n"				       \
+		      "  .quad 661b\n"            /* label */          \
+		      "  .quad 663f\n"		  /* new instruction */ \
+		      "  .byte %c0\n"             /* feature bit */    \
+		      "  .byte 662b-661b\n"       /* sourcelen */      \
+		      "  .byte 664f-663f\n"       /* replacementlen */ \
+		      ".previous\n"					\
+		      ".section .altinstr_replacement,\"ax\"\n"		\
+		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
+		      ".previous" :: "i" (feature) : "memory")
+
+/*
+ * Alternative inline assembly with input.
+ *
+ * Pecularities:
+ * No memory clobber here.
+ * Argument numbers start with 1.
+ * Best is to use constraints that are fixed size (like (%1) ... "r")
+ * If you use variable sized constraints like "m" or "g" in the
+ * replacement make sure to pad to the worst case length.
+ */
+#define alternative_input(oldinstr, newinstr, feature, input...)	\
+	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
+		      ".section .altinstructions,\"a\"\n"		\
+		      "  .align 8\n"					\
+		      "  .quad 661b\n"            /* label */		\
+		      "  .quad 663f\n"		  /* new instruction */	\
+		      "  .byte %c0\n"             /* feature bit */	\
+		      "  .byte 662b-661b\n"       /* sourcelen */	\
+		      "  .byte 664f-663f\n"       /* replacementlen */	\
+		      ".previous\n"					\
+		      ".section .altinstr_replacement,\"ax\"\n"		\
+		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
+		      ".previous" :: "i" (feature), ##input)
+
+/* Like alternative_input, but with a single output argument */
+#define alternative_io(oldinstr, newinstr, feature, output, input...) \
+	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
+		      ".section .altinstructions,\"a\"\n"		\
+		      "  .align 8\n"					\
+		      "  .quad 661b\n"            /* label */		\
+		      "  .quad 663f\n"		  /* new instruction */	\
+		      "  .byte %c[feat]\n"        /* feature bit */	\
+		      "  .byte 662b-661b\n"       /* sourcelen */	\
+		      "  .byte 664f-663f\n"       /* replacementlen */	\
+		      ".previous\n"					\
+		      ".section .altinstr_replacement,\"ax\"\n"		\
+		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
+		      ".previous" : output : [feat] "i" (feature), ##input)
+
+/*
+ * Alternative inline assembly for SMP.
+ *
+ * alternative_smp() takes two versions (SMP first, UP second) and is
+ * for more complex stuff such as spinlocks.
+ *
+ * The LOCK_PREFIX macro defined here replaces the LOCK and
+ * LOCK_PREFIX macros used everywhere in the source tree.
+ *
+ * SMP alternatives use the same data structures as the other
+ * alternatives and the X86_FEATURE_UP flag to indicate the case of a
+ * UP system running a SMP kernel.  The existing apply_alternatives()
+ * works fine for patching a SMP kernel for UP.
+ *
+ * The SMP alternative tables can be kept after boot and contain both
+ * UP and SMP versions of the instructions to allow switching back to
+ * SMP at runtime, when hotplugging in a new CPU, which is especially
+ * useful in virtualized environments.
+ *
+ * The very common lock prefix is handled as special case in a
+ * separate table which is a pure address list without replacement ptr
+ * and size information.  That keeps the table sizes small.
+ */
+
+#ifdef CONFIG_SMP
+#define alternative_smp(smpinstr, upinstr, args...)			\
+	asm volatile ("661:\n\t" smpinstr "\n662:\n"			\
+		      ".section .smp_altinstructions,\"a\"\n"		\
+		      "  .align 8\n"					\
+		      "  .quad 661b\n"            /* label */		\
+		      "  .quad 663f\n"		  /* new instruction */	\
+		      "  .byte 0x66\n"            /* X86_FEATURE_UP */	\
+		      "  .byte 662b-661b\n"       /* sourcelen */	\
+		      "  .byte 664f-663f\n"       /* replacementlen */	\
+		      ".previous\n"					\
+		      ".section .smp_altinstr_replacement,\"awx\"\n"	\
+		      "663:\n\t" upinstr "\n"     /* replacement */	\
+		      "664:\n\t.fill 662b-661b,1,0x42\n" /* space for original */ \
+		      ".previous" : args)
+
+#define LOCK_PREFIX \
+		".section .smp_locks,\"a\"\n"	\
+		"  .align 8\n"			\
+		"  .quad 661f\n" /* address */	\
+		".previous\n"			\
+	       	"661:\n\tlock; "
+
+#else /* ! CONFIG_SMP */
+#define alternative_smp(smpinstr, upinstr, args...) \
+	asm volatile (upinstr : args)
+#define LOCK_PREFIX ""
+#endif
+
+#endif /* _X86_64_ALTERNATIVE_H */
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index a731be2..9c96a0a 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -49,7 +49,8 @@
 
 static __inline__ void apic_wait_icr_idle(void)
 {
-	while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
+	while (apic_read( APIC_ICR ) & APIC_ICR_BUSY)
+		cpu_relax();
 }
 
 static inline void ack_APIC_irq(void)
@@ -79,30 +80,23 @@
 extern void smp_local_timer_interrupt (struct pt_regs * regs);
 extern void setup_boot_APIC_clock (void);
 extern void setup_secondary_APIC_clock (void);
-extern void setup_apic_nmi_watchdog (void);
-extern int reserve_lapic_nmi(void);
-extern void release_lapic_nmi(void);
-extern void disable_timer_nmi_watchdog(void);
-extern void enable_timer_nmi_watchdog(void);
-extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
 extern int APIC_init_uniprocessor (void);
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
 extern void clustered_apic_check(void);
 
-extern void nmi_watchdog_default(void);
-extern int setup_nmi_watchdog(char *);
+extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
+				   unsigned char msg_type, unsigned char mask);
 
-extern unsigned int nmi_watchdog;
-#define NMI_DEFAULT	-1
-#define NMI_NONE	0
-#define NMI_IO_APIC	1
-#define NMI_LOCAL_APIC	2
-#define NMI_INVALID	3
+#define K8_APIC_EXT_LVT_BASE    0x500
+#define K8_APIC_EXT_INT_MSG_FIX 0x0
+#define K8_APIC_EXT_INT_MSG_SMI 0x2
+#define K8_APIC_EXT_INT_MSG_NMI 0x4
+#define K8_APIC_EXT_INT_MSG_EXT 0x7
+#define K8_APIC_EXT_LVT_ENTRY_THRESHOLD    0
 
 extern int disable_timer_pin_1;
 
-extern void setup_threshold_lvt(unsigned long lvt_off);
 
 void smp_send_timer_broadcast_ipi(void);
 void switch_APIC_timer_to_ipi(void *cpumask);
diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h
index bd3fa67..007e88d 100644
--- a/include/asm-x86_64/atomic.h
+++ b/include/asm-x86_64/atomic.h
@@ -1,7 +1,7 @@
 #ifndef __ARCH_X86_64_ATOMIC__
 #define __ARCH_X86_64_ATOMIC__
 
-#include <asm/types.h>
+#include <asm/alternative.h>
 
 /* atomic_t should be 32 bit signed type */
 
@@ -52,7 +52,7 @@
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "addl %1,%0"
+		LOCK_PREFIX "addl %1,%0"
 		:"=m" (v->counter)
 		:"ir" (i), "m" (v->counter));
 }
@@ -67,7 +67,7 @@
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "subl %1,%0"
+		LOCK_PREFIX "subl %1,%0"
 		:"=m" (v->counter)
 		:"ir" (i), "m" (v->counter));
 }
@@ -86,7 +86,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "subl %2,%0; sete %1"
+		LOCK_PREFIX "subl %2,%0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"ir" (i), "m" (v->counter) : "memory");
 	return c;
@@ -101,7 +101,7 @@
 static __inline__ void atomic_inc(atomic_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "incl %0"
+		LOCK_PREFIX "incl %0"
 		:"=m" (v->counter)
 		:"m" (v->counter));
 }
@@ -115,7 +115,7 @@
 static __inline__ void atomic_dec(atomic_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "decl %0"
+		LOCK_PREFIX "decl %0"
 		:"=m" (v->counter)
 		:"m" (v->counter));
 }
@@ -133,7 +133,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "decl %0; sete %1"
+		LOCK_PREFIX "decl %0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"m" (v->counter) : "memory");
 	return c != 0;
@@ -152,7 +152,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "incl %0; sete %1"
+		LOCK_PREFIX "incl %0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"m" (v->counter) : "memory");
 	return c != 0;
@@ -172,7 +172,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "addl %2,%0; sets %1"
+		LOCK_PREFIX "addl %2,%0; sets %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"ir" (i), "m" (v->counter) : "memory");
 	return c;
@@ -189,7 +189,7 @@
 {
 	int __i = i;
 	__asm__ __volatile__(
-		LOCK "xaddl %0, %1;"
+		LOCK_PREFIX "xaddl %0, %1;"
 		:"=r"(i)
 		:"m"(v->counter), "0"(i));
 	return i + __i;
@@ -237,7 +237,7 @@
 static __inline__ void atomic64_add(long i, atomic64_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "addq %1,%0"
+		LOCK_PREFIX "addq %1,%0"
 		:"=m" (v->counter)
 		:"ir" (i), "m" (v->counter));
 }
@@ -252,7 +252,7 @@
 static __inline__ void atomic64_sub(long i, atomic64_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "subq %1,%0"
+		LOCK_PREFIX "subq %1,%0"
 		:"=m" (v->counter)
 		:"ir" (i), "m" (v->counter));
 }
@@ -271,7 +271,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "subq %2,%0; sete %1"
+		LOCK_PREFIX "subq %2,%0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"ir" (i), "m" (v->counter) : "memory");
 	return c;
@@ -286,7 +286,7 @@
 static __inline__ void atomic64_inc(atomic64_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "incq %0"
+		LOCK_PREFIX "incq %0"
 		:"=m" (v->counter)
 		:"m" (v->counter));
 }
@@ -300,7 +300,7 @@
 static __inline__ void atomic64_dec(atomic64_t *v)
 {
 	__asm__ __volatile__(
-		LOCK "decq %0"
+		LOCK_PREFIX "decq %0"
 		:"=m" (v->counter)
 		:"m" (v->counter));
 }
@@ -318,7 +318,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "decq %0; sete %1"
+		LOCK_PREFIX "decq %0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"m" (v->counter) : "memory");
 	return c != 0;
@@ -337,7 +337,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "incq %0; sete %1"
+		LOCK_PREFIX "incq %0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"m" (v->counter) : "memory");
 	return c != 0;
@@ -357,7 +357,7 @@
 	unsigned char c;
 
 	__asm__ __volatile__(
-		LOCK "addq %2,%0; sets %1"
+		LOCK_PREFIX "addq %2,%0; sets %1"
 		:"=m" (v->counter), "=qm" (c)
 		:"ir" (i), "m" (v->counter) : "memory");
 	return c;
@@ -374,7 +374,7 @@
 {
 	long __i = i;
 	__asm__ __volatile__(
-		LOCK "xaddq %0, %1;"
+		LOCK_PREFIX "xaddq %0, %1;"
 		:"=r"(i)
 		:"m"(v->counter), "0"(i));
 	return i + __i;
@@ -418,11 +418,11 @@
 
 /* These are x86-specific, used by some header files */
 #define atomic_clear_mask(mask, addr) \
-__asm__ __volatile__(LOCK "andl %0,%1" \
+__asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \
 : : "r" (~(mask)),"m" (*addr) : "memory")
 
 #define atomic_set_mask(mask, addr) \
-__asm__ __volatile__(LOCK "orl %0,%1" \
+__asm__ __volatile__(LOCK_PREFIX "orl %0,%1" \
 : : "r" ((unsigned)mask),"m" (*(addr)) : "memory")
 
 /* Atomic operations are already serializing on x86 */
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index e9bf933..f7ba57b 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -5,12 +5,7 @@
  * Copyright 1992, Linus Torvalds.
  */
 
-
-#ifdef CONFIG_SMP
-#define LOCK_PREFIX "lock ; "
-#else
-#define LOCK_PREFIX ""
-#endif
+#include <asm/alternative.h>
 
 #define ADDR (*(volatile long *) addr)
 
diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86_64/calgary.h
new file mode 100644
index 0000000..6e1654f
--- /dev/null
+++ b/include/asm-x86_64/calgary.h
@@ -0,0 +1,66 @@
+/*
+ * Derived from include/asm-powerpc/iommu.h
+ *
+ * Copyright (C) 2006 Jon Mason <jdmason@us.ibm.com>, IBM Corporation
+ * Copyright (C) 2006 Muli Ben-Yehuda <muli@il.ibm.com>, 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
+ */
+
+#ifndef _ASM_X86_64_CALGARY_H
+#define _ASM_X86_64_CALGARY_H
+
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/types.h>
+
+struct iommu_table {
+	unsigned long  it_base;      /* mapped address of tce table */
+	unsigned long  it_hint;      /* Hint for next alloc */
+	unsigned long *it_map;       /* A simple allocation bitmap for now */
+	spinlock_t     it_lock;      /* Protects it_map */
+	unsigned int   it_size;      /* Size of iommu table in entries */
+	unsigned char  it_busno;     /* Bus number this table belongs to */
+	void __iomem  *bbar;
+	u64	       tar_val;
+	struct timer_list watchdog_timer;
+};
+
+#define TCE_TABLE_SIZE_UNSPECIFIED	~0
+#define TCE_TABLE_SIZE_64K		0
+#define TCE_TABLE_SIZE_128K		1
+#define TCE_TABLE_SIZE_256K		2
+#define TCE_TABLE_SIZE_512K		3
+#define TCE_TABLE_SIZE_1M		4
+#define TCE_TABLE_SIZE_2M		5
+#define TCE_TABLE_SIZE_4M		6
+#define TCE_TABLE_SIZE_8M		7
+
+#ifdef CONFIG_CALGARY_IOMMU
+extern int calgary_iommu_init(void);
+extern void detect_calgary(void);
+#else
+static inline int calgary_iommu_init(void) { return 1; }
+static inline void detect_calgary(void) { return; }
+#endif
+
+static inline unsigned int bus_to_phb(unsigned char busno)
+{
+	return ((busno % 15 == 0) ? 0 : busno / 2 + 1);
+}
+
+#endif /* _ASM_X86_64_CALGARY_H */
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
index 662964b..ee792fa 100644
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -46,6 +46,7 @@
 #define X86_FEATURE_SYSCALL	(1*32+11) /* SYSCALL/SYSRET */
 #define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
 #define X86_FEATURE_FXSR_OPT	(1*32+25) /* FXSR optimizations */
+#define X86_FEATURE_RDTSCP	(1*32+27) /* RDTSCP */
 #define X86_FEATURE_LM		(1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT	(1*32+30) /* AMD 3DNow! extensions */
 #define X86_FEATURE_3DNOW	(1*32+31) /* 3DNow! */
@@ -65,6 +66,8 @@
 #define X86_FEATURE_CONSTANT_TSC (3*32+5) /* TSC runs at constant rate */
 #define X86_FEATURE_SYNC_RDTSC  (3*32+6)  /* RDTSC syncs CPU core */
 #define X86_FEATURE_FXSAVE_LEAK (3*32+7)  /* FIP/FOP/FDP leaks through FXSAVE */
+#define X86_FEATURE_UP		(3*32+8) /* SMP kernel running on UP */
+#define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index 498f66d..b6da83d 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -55,6 +55,13 @@
 extern struct dma_mapping_ops* dma_ops;
 extern int iommu_merge;
 
+static inline int valid_dma_direction(int dma_direction)
+{
+	return ((dma_direction == DMA_BIDIRECTIONAL) ||
+		(dma_direction == DMA_TO_DEVICE) ||
+		(dma_direction == DMA_FROM_DEVICE));
+}
+
 static inline int dma_mapping_error(dma_addr_t dma_addr)
 {
 	if (dma_ops->mapping_error)
@@ -72,6 +79,7 @@
 dma_map_single(struct device *hwdev, void *ptr, size_t size,
 	       int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	return dma_ops->map_single(hwdev, ptr, size, direction);
 }
 
@@ -79,6 +87,7 @@
 dma_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
 		 int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	dma_ops->unmap_single(dev, addr, size, direction);
 }
 
@@ -91,6 +100,7 @@
 dma_sync_single_for_cpu(struct device *hwdev, dma_addr_t dma_handle,
 			size_t size, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	if (dma_ops->sync_single_for_cpu)
 		dma_ops->sync_single_for_cpu(hwdev, dma_handle, size,
 					     direction);
@@ -101,6 +111,7 @@
 dma_sync_single_for_device(struct device *hwdev, dma_addr_t dma_handle,
 			   size_t size, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	if (dma_ops->sync_single_for_device)
 		dma_ops->sync_single_for_device(hwdev, dma_handle, size,
 						direction);
@@ -111,6 +122,7 @@
 dma_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dma_handle,
 			      unsigned long offset, size_t size, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	if (dma_ops->sync_single_range_for_cpu) {
 		dma_ops->sync_single_range_for_cpu(hwdev, dma_handle, offset, size, direction);
 	}
@@ -122,6 +134,7 @@
 dma_sync_single_range_for_device(struct device *hwdev, dma_addr_t dma_handle,
 				 unsigned long offset, size_t size, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	if (dma_ops->sync_single_range_for_device)
 		dma_ops->sync_single_range_for_device(hwdev, dma_handle,
 						      offset, size, direction);
@@ -133,6 +146,7 @@
 dma_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
 		    int nelems, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	if (dma_ops->sync_sg_for_cpu)
 		dma_ops->sync_sg_for_cpu(hwdev, sg, nelems, direction);
 	flush_write_buffers();
@@ -142,6 +156,7 @@
 dma_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
 		       int nelems, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	if (dma_ops->sync_sg_for_device) {
 		dma_ops->sync_sg_for_device(hwdev, sg, nelems, direction);
 	}
@@ -152,6 +167,7 @@
 static inline int
 dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	return dma_ops->map_sg(hwdev, sg, nents, direction);
 }
 
@@ -159,6 +175,7 @@
 dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
 	     int direction)
 {
+	BUG_ON(!valid_dma_direction(direction));
 	dma_ops->unmap_sg(hwdev, sg, nents, direction);
 }
 
diff --git a/include/asm-x86_64/dma.h b/include/asm-x86_64/dma.h
index c556208..a37c16f 100644
--- a/include/asm-x86_64/dma.h
+++ b/include/asm-x86_64/dma.h
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.1.1.1 2001/04/19 20:00:38 ak Exp $
+/*
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h
index 52825ce..006291e 100644
--- a/include/asm-x86_64/floppy.h
+++ b/include/asm-x86_64/floppy.h
@@ -147,10 +147,8 @@
 		return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
 						   "floppy", NULL);
 	else
-		return request_irq(FLOPPY_IRQ, floppy_interrupt,
-						   SA_INTERRUPT|SA_SAMPLE_RANDOM,
-						   "floppy", NULL);	
-
+		return request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT,
+				   "floppy", NULL);
 }
 
 static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/include/asm-x86_64/gart-mapping.h b/include/asm-x86_64/gart-mapping.h
deleted file mode 100644
index ada497b..0000000
--- a/include/asm-x86_64/gart-mapping.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _X8664_GART_MAPPING_H
-#define _X8664_GART_MAPPING_H 1
-
-#include <linux/types.h>
-#include <asm/types.h>
-
-struct device;
-
-extern void*
-gart_alloc_coherent(struct device *dev, size_t size,
-        dma_addr_t *dma_handle, gfp_t gfp);
-
-extern int
-gart_dma_supported(struct device *hwdev, u64 mask);
-
-#endif /* _X8664_GART_MAPPING_H */
diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h
index 18ff7ee..b390984 100644
--- a/include/asm-x86_64/hpet.h
+++ b/include/asm-x86_64/hpet.h
@@ -55,7 +55,7 @@
 
 extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
-extern int oem_force_hpet_timer(void);
+extern int apic_is_clustered_box(void);
 
 extern int hpet_use_timer;
 
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 3de96fd..1b2ac55 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -12,8 +12,6 @@
  *	<tomsoft@informatik.tu-chemnitz.de>
  *
  *	hacked by Andi Kleen for x86-64.
- * 
- *  $Id: hw_irq.h,v 1.24 2001/09/14 20:55:03 vojtech Exp $
  */
 
 #ifndef __ASSEMBLY__
diff --git a/include/asm-x86_64/ia32_unistd.h b/include/asm-x86_64/ia32_unistd.h
index b4f4b17..5b52ce5 100644
--- a/include/asm-x86_64/ia32_unistd.h
+++ b/include/asm-x86_64/ia32_unistd.h
@@ -4,317 +4,15 @@
 /*
  * This file contains the system call numbers of the ia32 port,
  * this is for the kernel only.
+ * Only add syscalls here where some part of the kernel needs to know
+ * the number. This should be otherwise in sync with asm-i386/unistd.h. -AK
  */
 
 #define __NR_ia32_restart_syscall 0
 #define __NR_ia32_exit		  1
-#define __NR_ia32_fork		  2
 #define __NR_ia32_read		  3
 #define __NR_ia32_write		  4
-#define __NR_ia32_open		  5
-#define __NR_ia32_close		  6
-#define __NR_ia32_waitpid		  7
-#define __NR_ia32_creat		  8
-#define __NR_ia32_link		  9
-#define __NR_ia32_unlink		 10
-#define __NR_ia32_execve		 11
-#define __NR_ia32_chdir		 12
-#define __NR_ia32_time		 13
-#define __NR_ia32_mknod		 14
-#define __NR_ia32_chmod		 15
-#define __NR_ia32_lchown		 16
-#define __NR_ia32_break		 17
-#define __NR_ia32_oldstat		 18
-#define __NR_ia32_lseek		 19
-#define __NR_ia32_getpid		 20
-#define __NR_ia32_mount		 21
-#define __NR_ia32_umount		 22
-#define __NR_ia32_setuid		 23
-#define __NR_ia32_getuid		 24
-#define __NR_ia32_stime		 25
-#define __NR_ia32_ptrace		 26
-#define __NR_ia32_alarm		 27
-#define __NR_ia32_oldfstat		 28
-#define __NR_ia32_pause		 29
-#define __NR_ia32_utime		 30
-#define __NR_ia32_stty		 31
-#define __NR_ia32_gtty		 32
-#define __NR_ia32_access		 33
-#define __NR_ia32_nice		 34
-#define __NR_ia32_ftime		 35
-#define __NR_ia32_sync		 36
-#define __NR_ia32_kill		 37
-#define __NR_ia32_rename		 38
-#define __NR_ia32_mkdir		 39
-#define __NR_ia32_rmdir		 40
-#define __NR_ia32_dup		 41
-#define __NR_ia32_pipe		 42
-#define __NR_ia32_times		 43
-#define __NR_ia32_prof		 44
-#define __NR_ia32_brk		 45
-#define __NR_ia32_setgid		 46
-#define __NR_ia32_getgid		 47
-#define __NR_ia32_signal		 48
-#define __NR_ia32_geteuid		 49
-#define __NR_ia32_getegid		 50
-#define __NR_ia32_acct		 51
-#define __NR_ia32_umount2		 52
-#define __NR_ia32_lock		 53
-#define __NR_ia32_ioctl		 54
-#define __NR_ia32_fcntl		 55
-#define __NR_ia32_mpx		 56
-#define __NR_ia32_setpgid		 57
-#define __NR_ia32_ulimit		 58
-#define __NR_ia32_oldolduname	 59
-#define __NR_ia32_umask		 60
-#define __NR_ia32_chroot		 61
-#define __NR_ia32_ustat		 62
-#define __NR_ia32_dup2		 63
-#define __NR_ia32_getppid		 64
-#define __NR_ia32_getpgrp		 65
-#define __NR_ia32_setsid		 66
-#define __NR_ia32_sigaction		 67
-#define __NR_ia32_sgetmask		 68
-#define __NR_ia32_ssetmask		 69
-#define __NR_ia32_setreuid		 70
-#define __NR_ia32_setregid		 71
-#define __NR_ia32_sigsuspend		 72
-#define __NR_ia32_sigpending		 73
-#define __NR_ia32_sethostname	 74
-#define __NR_ia32_setrlimit		 75
-#define __NR_ia32_getrlimit		 76	/* Back compatible 2Gig limited rlimit */
-#define __NR_ia32_getrusage		 77
-#define __NR_ia32_gettimeofday	 78
-#define __NR_ia32_settimeofday	 79
-#define __NR_ia32_getgroups		 80
-#define __NR_ia32_setgroups		 81
-#define __NR_ia32_select		 82
-#define __NR_ia32_symlink		 83
-#define __NR_ia32_oldlstat		 84
-#define __NR_ia32_readlink		 85
-#define __NR_ia32_uselib		 86
-#define __NR_ia32_swapon		 87
-#define __NR_ia32_reboot		 88
-#define __NR_ia32_readdir		 89
-#define __NR_ia32_mmap		 90
-#define __NR_ia32_munmap		 91
-#define __NR_ia32_truncate		 92
-#define __NR_ia32_ftruncate		 93
-#define __NR_ia32_fchmod		 94
-#define __NR_ia32_fchown		 95
-#define __NR_ia32_getpriority	 96
-#define __NR_ia32_setpriority	 97
-#define __NR_ia32_profil		 98
-#define __NR_ia32_statfs		 99
-#define __NR_ia32_fstatfs		100
-#define __NR_ia32_ioperm		101
-#define __NR_ia32_socketcall		102
-#define __NR_ia32_syslog		103
-#define __NR_ia32_setitimer		104
-#define __NR_ia32_getitimer		105
-#define __NR_ia32_stat		106
-#define __NR_ia32_lstat		107
-#define __NR_ia32_fstat		108
-#define __NR_ia32_olduname		109
-#define __NR_ia32_iopl		110
-#define __NR_ia32_vhangup		111
-#define __NR_ia32_idle		112
-#define __NR_ia32_vm86old		113
-#define __NR_ia32_wait4		114
-#define __NR_ia32_swapoff		115
-#define __NR_ia32_sysinfo		116
-#define __NR_ia32_ipc		117
-#define __NR_ia32_fsync		118
-#define __NR_ia32_sigreturn		119
-#define __NR_ia32_clone		120
-#define __NR_ia32_setdomainname	121
-#define __NR_ia32_uname		122
-#define __NR_ia32_modify_ldt		123
-#define __NR_ia32_adjtimex		124
-#define __NR_ia32_mprotect		125
-#define __NR_ia32_sigprocmask	126
-#define __NR_ia32_create_module	127
-#define __NR_ia32_init_module	128
-#define __NR_ia32_delete_module	129
-#define __NR_ia32_get_kernel_syms	130
-#define __NR_ia32_quotactl		131
-#define __NR_ia32_getpgid		132
-#define __NR_ia32_fchdir		133
-#define __NR_ia32_bdflush		134
-#define __NR_ia32_sysfs		135
-#define __NR_ia32_personality	136
-#define __NR_ia32_afs_syscall	137 /* Syscall for Andrew File System */
-#define __NR_ia32_setfsuid		138
-#define __NR_ia32_setfsgid		139
-#define __NR_ia32__llseek		140
-#define __NR_ia32_getdents		141
-#define __NR_ia32__newselect		142
-#define __NR_ia32_flock		143
-#define __NR_ia32_msync		144
-#define __NR_ia32_readv		145
-#define __NR_ia32_writev		146
-#define __NR_ia32_getsid		147
-#define __NR_ia32_fdatasync		148
-#define __NR_ia32__sysctl		149
-#define __NR_ia32_mlock		150
-#define __NR_ia32_munlock		151
-#define __NR_ia32_mlockall		152
-#define __NR_ia32_munlockall		153
-#define __NR_ia32_sched_setparam		154
-#define __NR_ia32_sched_getparam		155
-#define __NR_ia32_sched_setscheduler		156
-#define __NR_ia32_sched_getscheduler		157
-#define __NR_ia32_sched_yield		158
-#define __NR_ia32_sched_get_priority_max	159
-#define __NR_ia32_sched_get_priority_min	160
-#define __NR_ia32_sched_rr_get_interval	161
-#define __NR_ia32_nanosleep		162
-#define __NR_ia32_mremap		163
-#define __NR_ia32_setresuid		164
-#define __NR_ia32_getresuid		165
-#define __NR_ia32_vm86		166
-#define __NR_ia32_query_module	167
-#define __NR_ia32_poll		168
-#define __NR_ia32_nfsservctl		169
-#define __NR_ia32_setresgid		170
-#define __NR_ia32_getresgid		171
-#define __NR_ia32_prctl              172
+#define __NR_ia32_sigreturn	119
 #define __NR_ia32_rt_sigreturn	173
-#define __NR_ia32_rt_sigaction	174
-#define __NR_ia32_rt_sigprocmask	175
-#define __NR_ia32_rt_sigpending	176
-#define __NR_ia32_rt_sigtimedwait	177
-#define __NR_ia32_rt_sigqueueinfo	178
-#define __NR_ia32_rt_sigsuspend	179
-#define __NR_ia32_pread		180
-#define __NR_ia32_pwrite		181
-#define __NR_ia32_chown		182
-#define __NR_ia32_getcwd		183
-#define __NR_ia32_capget		184
-#define __NR_ia32_capset		185
-#define __NR_ia32_sigaltstack	186
-#define __NR_ia32_sendfile		187
-#define __NR_ia32_getpmsg		188	/* some people actually want streams */
-#define __NR_ia32_putpmsg		189	/* some people actually want streams */
-#define __NR_ia32_vfork		190
-#define __NR_ia32_ugetrlimit		191	/* SuS compliant getrlimit */
-#define __NR_ia32_mmap2		192
-#define __NR_ia32_truncate64		193
-#define __NR_ia32_ftruncate64	194
-#define __NR_ia32_stat64		195
-#define __NR_ia32_lstat64		196
-#define __NR_ia32_fstat64		197
-#define __NR_ia32_lchown32		198
-#define __NR_ia32_getuid32		199
-#define __NR_ia32_getgid32		200
-#define __NR_ia32_geteuid32		201
-#define __NR_ia32_getegid32		202
-#define __NR_ia32_setreuid32		203
-#define __NR_ia32_setregid32		204
-#define __NR_ia32_getgroups32	205
-#define __NR_ia32_setgroups32	206
-#define __NR_ia32_fchown32		207
-#define __NR_ia32_setresuid32	208
-#define __NR_ia32_getresuid32	209
-#define __NR_ia32_setresgid32	210
-#define __NR_ia32_getresgid32	211
-#define __NR_ia32_chown32		212
-#define __NR_ia32_setuid32		213
-#define __NR_ia32_setgid32		214
-#define __NR_ia32_setfsuid32		215
-#define __NR_ia32_setfsgid32		216
-#define __NR_ia32_pivot_root		217
-#define __NR_ia32_mincore		218
-#define __NR_ia32_madvise		219
-#define __NR_ia32_madvise1		219	/* delete when C lib stub is removed */
-#define __NR_ia32_getdents64		220
-#define __NR_ia32_fcntl64		221
-#define __NR_ia32_tuxcall		222
-#define __NR_ia32_security		223
-#define __NR_ia32_gettid		224
-#define __NR_ia32_readahead		225
-#define __NR_ia32_setxattr		226
-#define __NR_ia32_lsetxattr		227
-#define __NR_ia32_fsetxattr		228
-#define __NR_ia32_getxattr		229
-#define __NR_ia32_lgetxattr		230
-#define __NR_ia32_fgetxattr		231
-#define __NR_ia32_listxattr		232
-#define __NR_ia32_llistxattr		233
-#define __NR_ia32_flistxattr		234
-#define __NR_ia32_removexattr	235
-#define __NR_ia32_lremovexattr	236
-#define __NR_ia32_fremovexattr	237
-#define __NR_ia32_tkill		238
-#define __NR_ia32_sendfile64		239
-#define __NR_ia32_futex		240
-#define __NR_ia32_sched_setaffinity	241
-#define __NR_ia32_sched_getaffinity	242
-#define __NR_ia32_set_thread_area   243
-#define __NR_ia32_get_thread_area	244
-#define __NR_ia32_io_setup		245
-#define __NR_ia32_io_destroy		246
-#define __NR_ia32_io_getevents	247
-#define __NR_ia32_io_submit		248
-#define __NR_ia32_io_cancel		249
-#define __NR_ia32_exit_group		252
-#define __NR_ia32_lookup_dcookie	253
-#define __NR_ia32_sys_epoll_create	254
-#define __NR_ia32_sys_epoll_ctl	255
-#define __NR_ia32_sys_epoll_wait	256
-#define __NR_ia32_remap_file_pages	257
-#define __NR_ia32_set_tid_address	258
-#define __NR_ia32_timer_create		259
-#define __NR_ia32_timer_settime	(__NR_ia32_timer_create+1)
-#define __NR_ia32_timer_gettime	(__NR_ia32_timer_create+2)
-#define __NR_ia32_timer_getoverrun	(__NR_ia32_timer_create+3)
-#define __NR_ia32_timer_delete	(__NR_ia32_timer_create+4)
-#define __NR_ia32_clock_settime	(__NR_ia32_timer_create+5)
-#define __NR_ia32_clock_gettime	(__NR_ia32_timer_create+6)
-#define __NR_ia32_clock_getres	(__NR_ia32_timer_create+7)
-#define __NR_ia32_clock_nanosleep	(__NR_ia32_timer_create+8)
-#define __NR_ia32_statfs64		268
-#define __NR_ia32_fstatfs64		269
-#define __NR_ia32_tgkill		270
-#define __NR_ia32_utimes		271
-#define __NR_ia32_fadvise64_64		272
-#define __NR_ia32_vserver		273
-#define __NR_ia32_mbind		274
-#define __NR_ia32_get_mempolicy	275
-#define __NR_ia32_set_mempolicy	276
-#define __NR_ia32_mq_open 		277
-#define __NR_ia32_mq_unlink		(__NR_ia32_mq_open+1)
-#define __NR_ia32_mq_timedsend	(__NR_ia32_mq_open+2)
-#define __NR_ia32_mq_timedreceive	(__NR_ia32_mq_open+3)
-#define __NR_ia32_mq_notify		(__NR_ia32_mq_open+4)
-#define __NR_ia32_mq_getsetattr	(__NR_ia32_mq_open+5)
-#define __NR_ia32_kexec		283
-#define __NR_ia32_waitid		284
-/* #define __NR_sys_setaltroot	285 */
-#define __NR_ia32_add_key		286
-#define __NR_ia32_request_key	287
-#define __NR_ia32_keyctl		288
-#define __NR_ia32_ioprio_set		289
-#define __NR_ia32_ioprio_get		290
-#define __NR_ia32_inotify_init		291
-#define __NR_ia32_inotify_add_watch	292
-#define __NR_ia32_inotify_rm_watch	293
-#define __NR_ia32_migrate_pages		294
-#define __NR_ia32_openat		295
-#define __NR_ia32_mkdirat		296
-#define __NR_ia32_mknodat		297
-#define __NR_ia32_fchownat		298
-#define __NR_ia32_futimesat		299
-#define __NR_ia32_fstatat64		300
-#define __NR_ia32_unlinkat		301
-#define __NR_ia32_renameat		302
-#define __NR_ia32_linkat		303
-#define __NR_ia32_symlinkat		304
-#define __NR_ia32_readlinkat		305
-#define __NR_ia32_fchmodat		306
-#define __NR_ia32_faccessat		307
-#define __NR_ia32_pselect6		308
-#define __NR_ia32_ppoll			309
-#define __NR_ia32_unshare		310
 
 #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
diff --git a/include/asm-x86_64/intel_arch_perfmon.h b/include/asm-x86_64/intel_arch_perfmon.h
new file mode 100644
index 0000000..59c3964
--- /dev/null
+++ b/include/asm-x86_64/intel_arch_perfmon.h
@@ -0,0 +1,19 @@
+#ifndef X86_64_INTEL_ARCH_PERFMON_H
+#define X86_64_INTEL_ARCH_PERFMON_H 1
+
+#define MSR_ARCH_PERFMON_PERFCTR0		0xc1
+#define MSR_ARCH_PERFMON_PERFCTR1		0xc2
+
+#define MSR_ARCH_PERFMON_EVENTSEL0		0x186
+#define MSR_ARCH_PERFMON_EVENTSEL1		0x187
+
+#define ARCH_PERFMON_EVENTSEL0_ENABLE      (1 << 22)
+#define ARCH_PERFMON_EVENTSEL_INT          (1 << 20)
+#define ARCH_PERFMON_EVENTSEL_OS           (1 << 17)
+#define ARCH_PERFMON_EVENTSEL_USR          (1 << 16)
+
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL	(0x3c)
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK	(0x00 << 8)
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
+
+#endif	/* X86_64_INTEL_ARCH_PERFMON_H */
diff --git a/include/asm-x86_64/k8.h b/include/asm-x86_64/k8.h
new file mode 100644
index 0000000..699dd69
--- /dev/null
+++ b/include/asm-x86_64/k8.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_K8_H
+#define _ASM_K8_H 1
+
+#include <linux/pci.h>
+
+extern struct pci_device_id k8_nb_ids[];
+
+extern int early_is_k8_nb(u32 value);
+extern struct pci_dev **k8_northbridges;
+extern int num_k8_northbridges;
+extern int cache_k8_northbridges(void);
+extern void k8_flush_garts(void);
+
+#endif
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
index cf79563..cd52c7f 100644
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -15,6 +15,8 @@
 
 extern int register_die_notifier(struct notifier_block *);
 extern int unregister_die_notifier(struct notifier_block *);
+extern int register_page_fault_notifier(struct notifier_block *);
+extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head die_chain;
 
 /* Grossly misnamed. */
diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86_64/kprobes.h
index 98a1e95d..d36febd 100644
--- a/include/asm-x86_64/kprobes.h
+++ b/include/asm-x86_64/kprobes.h
@@ -43,6 +43,7 @@
 
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)pentry
 #define ARCH_SUPPORTS_KRETPROBES
+#define  ARCH_INACTIVE_KPROBE_COUNT 1
 
 void kretprobe_trampoline(void);
 extern void arch_remove_kprobe(struct kprobe *p);
diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h
index cd17945..e769e62 100644
--- a/include/asm-x86_64/local.h
+++ b/include/asm-x86_64/local.h
@@ -59,12 +59,26 @@
  * This could be done better if we moved the per cpu data directly
  * after GS.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(v)	 	\
+	({ local_t res__;		\
+	   preempt_disable(); 		\
+	   res__ = (v);			\
+	   preempt_enable();		\
+	   res__; })
+#define cpu_local_wrap(v)		\
+	({ preempt_disable();		\
+	   v;				\
+	   preempt_enable(); })		\
+
+#define cpu_local_read(v)    cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
+#define cpu_local_set(v, i)  cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
+#define cpu_local_inc(v)     cpu_local_wrap(local_inc(&__get_cpu_var(v)))
+#define cpu_local_dec(v)     cpu_local_wrap(local_dec(&__get_cpu_var(v)))
+#define cpu_local_add(i, v)  cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
+#define cpu_local_sub(i, v)  cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
 
 #define __cpu_local_inc(v)	cpu_local_inc(v)
 #define __cpu_local_dec(v)	cpu_local_dec(v)
diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h
index 7229785..d13687d 100644
--- a/include/asm-x86_64/mce.h
+++ b/include/asm-x86_64/mce.h
@@ -67,13 +67,22 @@
 /* Software defined banks */
 #define MCE_EXTENDED_BANK	128
 #define MCE_THERMAL_BANK	MCE_EXTENDED_BANK + 0
-#define MCE_THRESHOLD_BASE      MCE_EXTENDED_BANK + 1 /* MCE_AMD */
-#define MCE_THRESHOLD_DRAM_ECC  MCE_THRESHOLD_BASE + 4
+
+#define K8_MCE_THRESHOLD_BASE      (MCE_EXTENDED_BANK + 1)      /* MCE_AMD */
+#define K8_MCE_THRESHOLD_BANK_0    (MCE_THRESHOLD_BASE + 0 * 9)
+#define K8_MCE_THRESHOLD_BANK_1    (MCE_THRESHOLD_BASE + 1 * 9)
+#define K8_MCE_THRESHOLD_BANK_2    (MCE_THRESHOLD_BASE + 2 * 9)
+#define K8_MCE_THRESHOLD_BANK_3    (MCE_THRESHOLD_BASE + 3 * 9)
+#define K8_MCE_THRESHOLD_BANK_4    (MCE_THRESHOLD_BASE + 4 * 9)
+#define K8_MCE_THRESHOLD_BANK_5    (MCE_THRESHOLD_BASE + 5 * 9)
+#define K8_MCE_THRESHOLD_DRAM_ECC  (MCE_THRESHOLD_BANK_4 + 0)
 
 #ifdef __KERNEL__
 #include <asm/atomic.h>
 
 void mce_log(struct mce *m);
+DECLARE_PER_CPU(struct sys_device, device_mce);
+
 #ifdef CONFIG_X86_MCE_INTEL
 void mce_intel_feature_init(struct cpuinfo_x86 *c);
 #else
diff --git a/include/asm-x86_64/mutex.h b/include/asm-x86_64/mutex.h
index 11fbee2..06fab6d 100644
--- a/include/asm-x86_64/mutex.h
+++ b/include/asm-x86_64/mutex.h
@@ -24,7 +24,7 @@
 	typecheck_fn(fastcall void (*)(atomic_t *), fail_fn);		\
 									\
 	__asm__ __volatile__(						\
-		LOCK	"   decl (%%rdi)	\n"			\
+		LOCK_PREFIX "   decl (%%rdi)	\n"			\
 			"   js 2f		\n"			\
 			"1:			\n"			\
 									\
@@ -74,7 +74,7 @@
 	typecheck_fn(fastcall void (*)(atomic_t *), fail_fn);		\
 									\
 	__asm__ __volatile__(						\
-		LOCK	"   incl (%%rdi)	\n"			\
+		LOCK_PREFIX "   incl (%%rdi)	\n"			\
 			"   jle 2f		\n"			\
 			"1:			\n"			\
 									\
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index d3abfc6..efb45c8 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -5,26 +5,27 @@
 #define ASM_NMI_H
 
 #include <linux/pm.h>
+#include <asm/io.h>
  
 struct pt_regs;
- 
+
 typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
- 
-/** 
+
+/**
  * set_nmi_callback
  *
  * Set a handler for an NMI. Only one handler may be
  * set. Return 1 if the NMI was handled.
  */
 void set_nmi_callback(nmi_callback_t callback);
- 
-/** 
+
+/**
  * unset_nmi_callback
  *
  * Remove the handler previously set.
  */
 void unset_nmi_callback(void);
- 
+
 #ifdef CONFIG_PM
  
 /** Replace the PM callback routine for NMI. */
@@ -56,4 +57,21 @@
 
 extern int check_nmi_watchdog(void);
  
+extern void setup_apic_nmi_watchdog (void);
+extern int reserve_lapic_nmi(void);
+extern void release_lapic_nmi(void);
+extern void disable_timer_nmi_watchdog(void);
+extern void enable_timer_nmi_watchdog(void);
+extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
+
+extern void nmi_watchdog_default(void);
+extern int setup_nmi_watchdog(char *);
+
+extern unsigned int nmi_watchdog;
+#define NMI_DEFAULT	-1
+#define NMI_NONE	0
+#define NMI_IO_APIC	1
+#define NMI_LOCAL_APIC	2
+#define NMI_INVALID	3
+
 #endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index 2db0620..49c5e92 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -39,8 +39,8 @@
 #include <asm/scatterlist.h>
 #include <linux/string.h>
 #include <asm/page.h>
-#include <linux/dma-mapping.h> /* for have_iommu */
 
+extern void pci_iommu_alloc(void);
 extern int iommu_setup(char *opt);
 
 /* The PCI address space does equal the physical memory
@@ -52,7 +52,7 @@
  */
 #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
 
-#ifdef CONFIG_GART_IOMMU
+#if defined(CONFIG_IOMMU) || defined(CONFIG_CALGARY_IOMMU)
 
 /*
  * x86-64 always supports DAC, but sometimes it is useful to force
diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
index 7f33aaf..549eb92 100644
--- a/include/asm-x86_64/percpu.h
+++ b/include/asm-x86_64/percpu.h
@@ -21,6 +21,7 @@
 /* var is in discarded region: offset to particular copy we want */
 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
 #define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
+#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
 
 /* A macro to avoid #include hell... */
 #define percpu_modcopy(pcpudst, src, size)			\
@@ -40,6 +41,7 @@
 
 #define per_cpu(var, cpu)			(*((void)(cpu), &per_cpu__##var))
 #define __get_cpu_var(var)			per_cpu__##var
+#define __raw_get_cpu_var(var)			per_cpu__##var
 
 #endif	/* SMP */
 
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 31e83c3..a31ab4e 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -337,14 +337,8 @@
 /* to find an entry in a page-table-directory. */
 #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
 #define pud_offset(pgd, address) ((pud_t *) pgd_page(*(pgd)) + pud_index(address))
-#define pud_offset_k(pgd, addr) pud_offset(pgd, addr)
 #define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
 
-static inline pud_t *__pud_offset_k(pud_t *pud, unsigned long address)
-{ 
-	return pud + pud_index(address);
-} 
-
 /* PMD  - Level 2 access */
 #define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
 #define pmd_page(pmd)		(pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 3061a38..3b3c121 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -69,7 +69,11 @@
 	cpumask_t llc_shared_map;	/* cpus sharing the last level cache */
 #endif
 	__u8	apicid;
+#ifdef CONFIG_SMP
 	__u8	booted_cores;	/* number of cores as seen by OS */
+	__u8	phys_proc_id;	/* Physical Processor id. */
+	__u8	cpu_core_id;	/* Core id. */
+#endif
 } ____cacheline_aligned;
 
 #define X86_VENDOR_INTEL 0
@@ -96,6 +100,7 @@
 extern void identify_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
 extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
+extern unsigned short num_cache_leaves;
 
 /*
  * EFLAGS bits
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 8abf2a4..038fe1f4 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -37,7 +37,6 @@
 
 extern void config_acpi_tables(void);
 extern void ia32_syscall(void);
-extern void iommu_hole_init(void);
 
 extern int pmtimer_mark_offset(void);
 extern void pmtimer_resume(void);
@@ -75,7 +74,7 @@
 
 extern unsigned long end_pfn_map; 
 
-extern void show_trace(unsigned long * rsp);
+extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp);
 extern void show_registers(struct pt_regs *regs);
 
 extern void exception_table_check(void);
@@ -101,13 +100,9 @@
 
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 
-extern void gart_parse_options(char *);
-extern void __init no_iommu_init(void);
-
 extern unsigned long table_start, table_end;
 
 extern int exception_trace;
-extern int force_iommu, no_iommu;
 extern int using_apic_timer;
 extern int disable_apic;
 extern unsigned cpu_khz;
@@ -116,7 +111,13 @@
 extern int acpi_ht;
 extern int acpi_disabled;
 
-#ifdef CONFIG_GART_IOMMU
+extern void no_iommu_init(void);
+extern int force_iommu, no_iommu;
+extern int iommu_detected;
+#ifdef CONFIG_IOMMU
+extern void gart_iommu_init(void);
+extern void gart_parse_options(char *);
+extern void iommu_hole_init(void);
 extern int fallback_aper_order;
 extern int fallback_aper_force;
 extern int iommu_aperture;
diff --git a/include/asm-x86_64/rwlock.h b/include/asm-x86_64/rwlock.h
index 9942cc3..dea0e94 100644
--- a/include/asm-x86_64/rwlock.h
+++ b/include/asm-x86_64/rwlock.h
@@ -24,7 +24,7 @@
 #define RW_LOCK_BIAS_STR	"0x01000000"
 
 #define __build_read_lock_ptr(rw, helper)   \
-	asm volatile(LOCK "subl $1,(%0)\n\t" \
+	asm volatile(LOCK_PREFIX "subl $1,(%0)\n\t" \
 		     "js 2f\n" \
 		     "1:\n" \
 		    LOCK_SECTION_START("") \
@@ -34,7 +34,7 @@
 		     ::"a" (rw) : "memory")
 
 #define __build_read_lock_const(rw, helper)   \
-	asm volatile(LOCK "subl $1,%0\n\t" \
+	asm volatile(LOCK_PREFIX "subl $1,%0\n\t" \
 		     "js 2f\n" \
 		     "1:\n" \
 		    LOCK_SECTION_START("") \
@@ -54,7 +54,7 @@
 					} while (0)
 
 #define __build_write_lock_ptr(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+	asm volatile(LOCK_PREFIX "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
 		     "jnz 2f\n" \
 		     "1:\n" \
 		     LOCK_SECTION_START("") \
@@ -64,7 +64,7 @@
 		     ::"a" (rw) : "memory")
 
 #define __build_write_lock_const(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+	asm volatile(LOCK_PREFIX "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
 		     "jnz 2f\n" \
 		     "1:\n" \
 		    LOCK_SECTION_START("") \
diff --git a/include/asm-x86_64/semaphore.h b/include/asm-x86_64/semaphore.h
index a389aa6..064df08 100644
--- a/include/asm-x86_64/semaphore.h
+++ b/include/asm-x86_64/semaphore.h
@@ -106,7 +106,7 @@
 
 	__asm__ __volatile__(
 		"# atomic down operation\n\t"
-		LOCK "decl %0\n\t"     /* --sem->count */
+		LOCK_PREFIX "decl %0\n\t"     /* --sem->count */
 		"js 2f\n"
 		"1:\n"
 		LOCK_SECTION_START("")
@@ -130,7 +130,7 @@
 
 	__asm__ __volatile__(
 		"# atomic interruptible down operation\n\t"
-		LOCK "decl %1\n\t"     /* --sem->count */
+		LOCK_PREFIX "decl %1\n\t"     /* --sem->count */
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
@@ -154,7 +154,7 @@
 
 	__asm__ __volatile__(
 		"# atomic interruptible down operation\n\t"
-		LOCK "decl %1\n\t"     /* --sem->count */
+		LOCK_PREFIX "decl %1\n\t"     /* --sem->count */
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
@@ -178,7 +178,7 @@
 {
 	__asm__ __volatile__(
 		"# atomic up operation\n\t"
-		LOCK "incl %0\n\t"     /* ++sem->count */
+		LOCK_PREFIX "incl %0\n\t"     /* ++sem->count */
 		"jle 2f\n"
 		"1:\n"
 		LOCK_SECTION_START("")
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index 7686b9b..6805e1f 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -53,8 +53,6 @@
 
 extern cpumask_t cpu_sibling_map[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
-extern u8 phys_proc_id[NR_CPUS];
-extern u8 cpu_core_id[NR_CPUS];
 extern u8 cpu_llc_id[NR_CPUS];
 
 #define SMP_TRAMPOLINE_BASE 0x6000
diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h
index 5d8a5e3..8d34219 100644
--- a/include/asm-x86_64/spinlock.h
+++ b/include/asm-x86_64/spinlock.h
@@ -31,15 +31,19 @@
 	"jmp 1b\n" \
 	LOCK_SECTION_END
 
+#define __raw_spin_lock_string_up \
+	"\n\tdecl %0"
+
 #define __raw_spin_unlock_string \
 	"movl $1,%0" \
 		:"=m" (lock->slock) : : "memory"
 
 static inline void __raw_spin_lock(raw_spinlock_t *lock)
 {
-	__asm__ __volatile__(
-		__raw_spin_lock_string
-		:"=m" (lock->slock) : : "memory");
+	alternative_smp(
+		__raw_spin_lock_string,
+		__raw_spin_lock_string_up,
+		"=m" (lock->slock) : : "memory");
 }
 
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
diff --git a/include/asm-x86_64/string.h b/include/asm-x86_64/string.h
index ee6bf27..9505d9f 100644
--- a/include/asm-x86_64/string.h
+++ b/include/asm-x86_64/string.h
@@ -6,7 +6,8 @@
 /* Written 2002 by Andi Kleen */ 
 
 /* Only used for special circumstances. Stolen from i386/string.h */ 
-static inline void * __inline_memcpy(void * to, const void * from, size_t n)
+static __always_inline void *
+__inline_memcpy(void * to, const void * from, size_t n)
 {
 unsigned long d0, d1, d2;
 __asm__ __volatile__(
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index f48e0da..68e559f 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -3,15 +3,10 @@
 
 #include <linux/kernel.h>
 #include <asm/segment.h>
+#include <asm/alternative.h>
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_SMP
-#define LOCK_PREFIX "lock ; "
-#else
-#define LOCK_PREFIX ""
-#endif
-
 #define __STR(x) #x
 #define STR(x) __STR(x)
 
@@ -34,7 +29,7 @@
 		     "thread_return:\n\t"					    \
 		     "movq %%gs:%P[pda_pcurrent],%%rsi\n\t"			  \
 		     "movq %P[thread_info](%%rsi),%%r8\n\t"			  \
-		     LOCK "btr  %[tif_fork],%P[ti_flags](%%r8)\n\t"		  \
+		     LOCK_PREFIX "btr  %[tif_fork],%P[ti_flags](%%r8)\n\t"	  \
 		     "movq %%rax,%%rdi\n\t" 					  \
 		     "jc   ret_from_fork\n\t"					  \
 		     RESTORE_CONTEXT						    \
@@ -69,82 +64,6 @@
 		".previous"			\
 		: :"r" (value), "r" (0))
 
-#ifdef __KERNEL__
-struct alt_instr { 
-	__u8 *instr; 		/* original instruction */
-	__u8 *replacement;
-	__u8  cpuid;		/* cpuid bit set for replacement */
-	__u8  instrlen;		/* length of original instruction */
-	__u8  replacementlen; 	/* length of new instruction, <= instrlen */ 
-	__u8  pad[5];
-}; 
-#endif
-
-/*
- * Alternative instructions for different CPU types or capabilities.
- * 
- * This allows to use optimized instructions even on generic binary
- * kernels.
- * 
- * length of oldinstr must be longer or equal the length of newinstr
- * It can be padded with nops as needed.
- * 
- * For non barrier like inlines please define new variants
- * without volatile and memory clobber.
- */
-#define alternative(oldinstr, newinstr, feature) 	\
-	asm volatile ("661:\n\t" oldinstr "\n662:\n" 		     \
-		      ".section .altinstructions,\"a\"\n"     	     \
-		      "  .align 8\n"				       \
-		      "  .quad 661b\n"            /* label */          \
-		      "  .quad 663f\n"		  /* new instruction */ \
-		      "  .byte %c0\n"             /* feature bit */    \
-		      "  .byte 662b-661b\n"       /* sourcelen */      \
-		      "  .byte 664f-663f\n"       /* replacementlen */ \
-		      ".previous\n"					\
-		      ".section .altinstr_replacement,\"ax\"\n"		\
-		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
-		      ".previous" :: "i" (feature) : "memory")  
-
-/*
- * Alternative inline assembly with input.
- * 
- * Peculiarities:
- * No memory clobber here. 
- * Argument numbers start with 1.
- * Best is to use constraints that are fixed size (like (%1) ... "r")
- * If you use variable sized constraints like "m" or "g" in the 
- * replacement make sure to pad to the worst case length.
- */
-#define alternative_input(oldinstr, newinstr, feature, input...)	\
-	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
-		      ".section .altinstructions,\"a\"\n"		\
-		      "  .align 8\n"					\
-		      "  .quad 661b\n"            /* label */		\
-		      "  .quad 663f\n"		  /* new instruction */	\
-		      "  .byte %c0\n"             /* feature bit */	\
-		      "  .byte 662b-661b\n"       /* sourcelen */	\
-		      "  .byte 664f-663f\n"       /* replacementlen */	\
-		      ".previous\n"					\
-		      ".section .altinstr_replacement,\"ax\"\n"		\
-		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
-		      ".previous" :: "i" (feature), ##input)
-
-/* Like alternative_input, but with a single output argument */
-#define alternative_io(oldinstr, newinstr, feature, output, input...) \
-	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
-		      ".section .altinstructions,\"a\"\n"		\
-		      "  .align 8\n"					\
-		      "  .quad 661b\n"            /* label */		\
-		      "  .quad 663f\n"		  /* new instruction */	\
-		      "  .byte %c[feat]\n"        /* feature bit */	\
-		      "  .byte 662b-661b\n"       /* sourcelen */	\
-		      "  .byte 664f-663f\n"       /* replacementlen */	\
-		      ".previous\n"					\
-		      ".section .altinstr_replacement,\"ax\"\n"		\
-		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
-		      ".previous" : output : [feat] "i" (feature), ##input)
-
 /*
  * Clear and set 'TS' bit respectively
  */
@@ -366,5 +285,6 @@
 void cpu_idle_wait(void);
 
 extern unsigned long arch_align_stack(unsigned long sp);
+extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
 
 #endif
diff --git a/include/asm-x86_64/tce.h b/include/asm-x86_64/tce.h
new file mode 100644
index 0000000..ee51d31
--- /dev/null
+++ b/include/asm-x86_64/tce.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <muli@il.ibm.com>, IBM Corporation
+ * Copyright (C) 2006 Jon Mason <jdmason@us.ibm.com>, IBM Corporation
+ *
+ * This file is derived from asm-powerpc/tce.h.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _ASM_X86_64_TCE_H
+#define _ASM_X86_64_TCE_H
+
+extern void* tce_table_kva[];
+extern unsigned int specified_table_size;
+struct iommu_table;
+
+#define TCE_ENTRY_SIZE   8   /* in bytes */
+
+#define TCE_READ_SHIFT   0
+#define TCE_WRITE_SHIFT  1
+#define TCE_HUBID_SHIFT  2   /* unused */
+#define TCE_RSVD_SHIFT   8   /* unused */
+#define TCE_RPN_SHIFT    12
+#define TCE_UNUSED_SHIFT 48  /* unused */
+
+#define TCE_RPN_MASK     0x0000fffffffff000ULL
+
+extern void tce_build(struct iommu_table *tbl, unsigned long index,
+        unsigned int npages, unsigned long uaddr, int direction);
+extern void tce_free(struct iommu_table *tbl, long index, unsigned int npages);
+extern void* alloc_tce_table(void);
+extern void free_tce_table(void *tbl);
+extern int build_tce_table(struct pci_dev *dev, void __iomem *bbar);
+
+#endif /* _ASM_X86_64_TCE_H */
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 4ac0e0a..2029b00 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -73,8 +73,21 @@
 }
 
 /* thread information allocation */
+#ifdef CONFIG_DEBUG_STACK_USAGE
+#define alloc_thread_info(tsk)					\
+    ({								\
+	struct thread_info *ret;				\
+								\
+	ret = ((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER)); \
+	if (ret)						\
+		memset(ret, 0, THREAD_SIZE);			\
+	ret;							\
+    })
+#else
 #define alloc_thread_info(tsk) \
 	((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER))
+#endif
+
 #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER)
 
 #else /* !__ASSEMBLY__ */
@@ -101,7 +114,7 @@
 #define TIF_IRET		5	/* force IRET */
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
-#define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+/* 16 free */
 #define TIF_IA32		17	/* 32bit process */ 
 #define TIF_FORK		18	/* ret_from_fork */
 #define TIF_ABI_PENDING		19
@@ -115,7 +128,6 @@
 #define _TIF_IRET		(1<<TIF_IRET)
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
 #define _TIF_IA32		(1<<TIF_IA32)
 #define _TIF_FORK		(1<<TIF_FORK)
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
@@ -137,6 +149,9 @@
  */
 #define TS_USEDFPU		0x0001	/* FPU was used by this task this quantum (SMP) */
 #define TS_COMPAT		0x0002	/* 32bit syscall active */
+#define TS_POLLING		0x0004	/* true if in idle loop and not sleeping */
+
+#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 80c4e44..c4e46e7 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -7,8 +7,6 @@
 #include <asm/mpspec.h>
 #include <asm/bitops.h>
 
-/* Map the K8 CPU local memory controllers to a simple 1:1 CPU:NODE topology */
-
 extern cpumask_t cpu_online_map;
 
 extern unsigned char cpu_to_node[];
@@ -57,10 +55,8 @@
 #endif
 
 #ifdef CONFIG_SMP
-#define topology_physical_package_id(cpu)				\
-	(phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
-#define topology_core_id(cpu)						\
-	(cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_physical_package_id(cpu)	(cpu_data[cpu].phys_proc_id)
+#define topology_core_id(cpu)			(cpu_data[cpu].cpu_core_id)
 #define topology_core_siblings(cpu)		(cpu_core_map[cpu])
 #define topology_thread_siblings(cpu)		(cpu_sibling_map[cpu])
 #endif
diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86_64/unwind.h
new file mode 100644
index 0000000..f3e7124
--- /dev/null
+++ b/include/asm-x86_64/unwind.h
@@ -0,0 +1,106 @@
+#ifndef _ASM_X86_64_UNWIND_H
+#define _ASM_X86_64_UNWIND_H
+
+/*
+ * Copyright (C) 2002-2006 Novell, Inc.
+ *	Jan Beulich <jbeulich@novell.com>
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+#ifdef CONFIG_STACK_UNWIND
+
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+#include <asm/vsyscall.h>
+
+struct unwind_frame_info
+{
+	struct pt_regs regs;
+	struct task_struct *task;
+};
+
+#define UNW_PC(frame)        (frame)->regs.rip
+#define UNW_SP(frame)        (frame)->regs.rsp
+#ifdef CONFIG_FRAME_POINTER
+#define UNW_FP(frame)        (frame)->regs.rbp
+#define FRAME_RETADDR_OFFSET 8
+#define FRAME_LINK_OFFSET    0
+#define STACK_BOTTOM(tsk)    (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1))
+#define STACK_TOP(tsk)       ((tsk)->thread.rsp0)
+#endif
+/* Might need to account for the special exception and interrupt handling
+   stacks here, since normally
+	EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER,
+   but the construct is needed only for getting across the stack switch to
+   the interrupt stack - thus considering the IRQ stack itself is unnecessary,
+   and the overhead of comparing against all exception handling stacks seems
+   not desirable. */
+#define STACK_LIMIT(ptr)     (((ptr) - 1) & ~(THREAD_SIZE - 1))
+
+#define UNW_REGISTER_INFO \
+	PTREGS_INFO(rax), \
+	PTREGS_INFO(rdx), \
+	PTREGS_INFO(rcx), \
+	PTREGS_INFO(rbx), \
+	PTREGS_INFO(rsi), \
+	PTREGS_INFO(rdi), \
+	PTREGS_INFO(rbp), \
+	PTREGS_INFO(rsp), \
+	PTREGS_INFO(r8), \
+	PTREGS_INFO(r9), \
+	PTREGS_INFO(r10), \
+	PTREGS_INFO(r11), \
+	PTREGS_INFO(r12), \
+	PTREGS_INFO(r13), \
+	PTREGS_INFO(r14), \
+	PTREGS_INFO(r15), \
+	PTREGS_INFO(rip)
+
+static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
+                                            /*const*/ struct pt_regs *regs)
+{
+	info->regs = *regs;
+}
+
+static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
+{
+	extern const char thread_return[];
+
+	memset(&info->regs, 0, sizeof(info->regs));
+	info->regs.rip = (unsigned long)thread_return;
+	info->regs.cs = __KERNEL_CS;
+	__get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp);
+	info->regs.rsp = info->task->thread.rsp;
+	info->regs.ss = __KERNEL_DS;
+}
+
+extern int arch_unwind_init_running(struct unwind_frame_info *,
+                                    int (*callback)(struct unwind_frame_info *,
+                                                    void *arg),
+                                    void *arg);
+
+static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
+{
+#if 0 /* This can only work when selector register saves/restores
+         are properly annotated (and tracked in UNW_REGISTER_INFO). */
+	return user_mode(&info->regs);
+#else
+	return (long)info->regs.rip >= 0
+	       || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END)
+	       || (long)info->regs.rsp >= 0;
+#endif
+}
+
+#else
+
+#define UNW_PC(frame) ((void)(frame), 0)
+
+static inline int arch_unw_user_mode(const void *info)
+{
+	return 0;
+}
+
+#endif
+
+#endif /* _ASM_X86_64_UNWIND_H */
diff --git a/include/keys/user-type.h b/include/keys/user-type.h
index a3dae18..c37c342 100644
--- a/include/keys/user-type.h
+++ b/include/keys/user-type.h
@@ -37,6 +37,7 @@
 extern int user_instantiate(struct key *key, const void *data, size_t datalen);
 extern int user_update(struct key *key, const void *data, size_t datalen);
 extern int user_match(const struct key *key, const void *criterion);
+extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
 extern void user_describe(const struct key *user, struct seq_file *m);
 extern long user_read(const struct key *key,
diff --git a/include/linux/acct.h b/include/linux/acct.h
index 3d54fbc..e86bae7 100644
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -121,13 +121,17 @@
 struct super_block;
 extern void acct_auto_close_mnt(struct vfsmount *m);
 extern void acct_auto_close(struct super_block *sb);
-extern void acct_process(long exitcode);
+extern void acct_init_pacct(struct pacct_struct *pacct);
+extern void acct_collect(long exitcode, int group_dead);
+extern void acct_process(void);
 extern void acct_update_integrals(struct task_struct *tsk);
 extern void acct_clear_integrals(struct task_struct *tsk);
 #else
 #define acct_auto_close_mnt(x)	do { } while (0)
 #define acct_auto_close(x)	do { } while (0)
-#define acct_process(x)		do { } while (0)
+#define acct_init_pacct(x)	do { } while (0)
+#define acct_collect(x,y)	do { } while (0)
+#define acct_process()		do { } while (0)
 #define acct_update_integrals(x)		do { } while (0)
 #define acct_clear_integrals(task)	do { } while (0)
 #endif
diff --git a/include/linux/bio.h b/include/linux/bio.h
index b60ffe3..76bdaea 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -47,7 +47,7 @@
 #define BIO_BUG_ON
 #endif
 
-#define BIO_MAX_PAGES		(256)
+#define BIO_MAX_PAGES		256
 #define BIO_MAX_SIZE		(BIO_MAX_PAGES << PAGE_CACHE_SHIFT)
 #define BIO_MAX_SECTORS		(BIO_MAX_SIZE >> 9)
 
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index d9ed279..dcc5de7c 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -24,6 +24,9 @@
  * The available bitmap operations and their rough meaning in the
  * case that the bitmap is a single unsigned long are thus:
  *
+ * Note that nbits should be always a compile time evaluable constant.
+ * Otherwise many inlines will generate horrible code.
+ *
  * bitmap_zero(dst, nbits)			*dst = 0UL
  * bitmap_fill(dst, nbits)			*dst = ~0UL
  * bitmap_copy(dst, src, nbits)			*dst = *src
@@ -244,6 +247,8 @@
 
 static inline int bitmap_weight(const unsigned long *src, int nbits)
 {
+	if (nbits <= BITS_PER_LONG)
+		return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
 	return __bitmap_weight(src, nbits);
 }
 
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
new file mode 100644
index 0000000..d852024
--- /dev/null
+++ b/include/linux/clocksource.h
@@ -0,0 +1,185 @@
+/*  linux/include/linux/clocksource.h
+ *
+ *  This file contains the structure definitions for clocksources.
+ *
+ *  If you are not a clocksource, or timekeeping code, you should
+ *  not be including this file!
+ */
+#ifndef _LINUX_CLOCKSOURCE_H
+#define _LINUX_CLOCKSOURCE_H
+
+#include <linux/types.h>
+#include <linux/timex.h>
+#include <linux/time.h>
+#include <linux/list.h>
+#include <asm/div64.h>
+#include <asm/io.h>
+
+/* clocksource cycle base type */
+typedef u64 cycle_t;
+
+/**
+ * struct clocksource - hardware abstraction for a free running counter
+ *	Provides mostly state-free accessors to the underlying hardware.
+ *
+ * @name:		ptr to clocksource name
+ * @list:		list head for registration
+ * @rating:		rating value for selection (higher is better)
+ *			To avoid rating inflation the following
+ *			list should give you a guide as to how
+ *			to assign your clocksource a rating
+ *			1-99: Unfit for real use
+ *				Only available for bootup and testing purposes.
+ *			100-199: Base level usability.
+ *				Functional for real use, but not desired.
+ *			200-299: Good.
+ *				A correct and usable clocksource.
+ *			300-399: Desired.
+ *				A reasonably fast and accurate clocksource.
+ *			400-499: Perfect
+ *				The ideal clocksource. A must-use where
+ *				available.
+ * @read:		returns a cycle value
+ * @mask:		bitmask for two's complement
+ *			subtraction of non 64 bit counters
+ * @mult:		cycle to nanosecond multiplier
+ * @shift:		cycle to nanosecond divisor (power of two)
+ * @update_callback:	called when safe to alter clocksource values
+ * @is_continuous:	defines if clocksource is free-running.
+ * @cycle_interval:	Used internally by timekeeping core, please ignore.
+ * @xtime_interval:	Used internally by timekeeping core, please ignore.
+ */
+struct clocksource {
+	char *name;
+	struct list_head list;
+	int rating;
+	cycle_t (*read)(void);
+	cycle_t mask;
+	u32 mult;
+	u32 shift;
+	int (*update_callback)(void);
+	int is_continuous;
+
+	/* timekeeping specific data, ignore */
+	cycle_t cycle_last, cycle_interval;
+	u64 xtime_nsec, xtime_interval;
+	s64 error;
+};
+
+/* simplify initialization of mask field */
+#define CLOCKSOURCE_MASK(bits) (cycle_t)(bits<64 ? ((1ULL<<bits)-1) : -1)
+
+/**
+ * clocksource_khz2mult - calculates mult from khz and shift
+ * @khz:		Clocksource frequency in KHz
+ * @shift_constant:	Clocksource shift factor
+ *
+ * Helper functions that converts a khz counter frequency to a timsource
+ * multiplier, given the clocksource shift value
+ */
+static inline u32 clocksource_khz2mult(u32 khz, u32 shift_constant)
+{
+	/*  khz = cyc/(Million ns)
+	 *  mult/2^shift  = ns/cyc
+	 *  mult = ns/cyc * 2^shift
+	 *  mult = 1Million/khz * 2^shift
+	 *  mult = 1000000 * 2^shift / khz
+	 *  mult = (1000000<<shift) / khz
+	 */
+	u64 tmp = ((u64)1000000) << shift_constant;
+
+	tmp += khz/2; /* round for do_div */
+	do_div(tmp, khz);
+
+	return (u32)tmp;
+}
+
+/**
+ * clocksource_hz2mult - calculates mult from hz and shift
+ * @hz:			Clocksource frequency in Hz
+ * @shift_constant:	Clocksource shift factor
+ *
+ * Helper functions that converts a hz counter
+ * frequency to a timsource multiplier, given the
+ * clocksource shift value
+ */
+static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant)
+{
+	/*  hz = cyc/(Billion ns)
+	 *  mult/2^shift  = ns/cyc
+	 *  mult = ns/cyc * 2^shift
+	 *  mult = 1Billion/hz * 2^shift
+	 *  mult = 1000000000 * 2^shift / hz
+	 *  mult = (1000000000<<shift) / hz
+	 */
+	u64 tmp = ((u64)1000000000) << shift_constant;
+
+	tmp += hz/2; /* round for do_div */
+	do_div(tmp, hz);
+
+	return (u32)tmp;
+}
+
+/**
+ * clocksource_read: - Access the clocksource's current cycle value
+ * @cs:		pointer to clocksource being read
+ *
+ * Uses the clocksource to return the current cycle_t value
+ */
+static inline cycle_t clocksource_read(struct clocksource *cs)
+{
+	return cs->read();
+}
+
+/**
+ * cyc2ns - converts clocksource cycles to nanoseconds
+ * @cs:		Pointer to clocksource
+ * @cycles:	Cycles
+ *
+ * Uses the clocksource and ntp ajdustment to convert cycle_ts to nanoseconds.
+ *
+ * XXX - This could use some mult_lxl_ll() asm optimization
+ */
+static inline s64 cyc2ns(struct clocksource *cs, cycle_t cycles)
+{
+	u64 ret = (u64)cycles;
+	ret = (ret * cs->mult) >> cs->shift;
+	return ret;
+}
+
+/**
+ * clocksource_calculate_interval - Calculates a clocksource interval struct
+ *
+ * @c:		Pointer to clocksource.
+ * @length_nsec: Desired interval length in nanoseconds.
+ *
+ * Calculates a fixed cycle/nsec interval for a given clocksource/adjustment
+ * pair and interval request.
+ *
+ * Unless you're the timekeeping code, you should not be using this!
+ */
+static inline void clocksource_calculate_interval(struct clocksource *c,
+						unsigned long length_nsec)
+{
+	u64 tmp;
+
+	/* XXX - All of this could use a whole lot of optimization */
+	tmp = length_nsec;
+	tmp <<= c->shift;
+	tmp += c->mult/2;
+	do_div(tmp, c->mult);
+
+	c->cycle_interval = (cycle_t)tmp;
+	if (c->cycle_interval == 0)
+		c->cycle_interval = 1;
+
+	c->xtime_interval = (u64)c->cycle_interval * c->mult;
+}
+
+
+/* used to install a new clocksource */
+int clocksource_register(struct clocksource*);
+void clocksource_reselect(void);
+struct clocksource* clocksource_get_next(void);
+
+#endif /* _LINUX_CLOCKSOURCE_H */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index dda1697..9760753 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -226,5 +226,7 @@
 
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
 
+extern int compat_printk(const char *fmt, ...);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index 89ab677..917d62e 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -673,6 +673,11 @@
 COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
 COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
 COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
+/* Siemens Gigaset */
+COMPATIBLE_IOCTL(GIGASET_REDIR)
+COMPATIBLE_IOCTL(GIGASET_CONFIG)
+COMPATIBLE_IOCTL(GIGASET_BRKCHARS)
+COMPATIBLE_IOCTL(GIGASET_VERSION)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
diff --git a/include/linux/console.h b/include/linux/console.h
index 08734e6..3bdf215 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -63,9 +63,11 @@
 extern const struct consw newport_con;	/* SGI Newport console  */
 extern const struct consw prom_con;	/* SPARC PROM console */
 
+int con_is_bound(const struct consw *csw);
+int register_con_driver(const struct consw *csw, int first, int last);
+int unregister_con_driver(const struct consw *csw);
 int take_over_console(const struct consw *sw, int first, int last, int deflt);
 void give_up_console(const struct consw *sw);
-
 /* scroll */
 #define SM_UP       (1)
 #define SM_DOWN     (2)
@@ -87,6 +89,7 @@
 #define CON_CONSDEV	(2) /* Last on the command line */
 #define CON_ENABLED	(4)
 #define CON_BOOT	(8)
+#define CON_ANYTIME	(16) /* Safe to call when cpu is offline */
 
 struct console
 {
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 9cbb781..b268a3c 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -317,7 +317,8 @@
 		(cpu) < NR_CPUS;		\
 		(cpu) = next_cpu((cpu), (mask)))
 #else /* NR_CPUS == 1 */
-#define for_each_cpu_mask(cpu, mask) for ((cpu) = 0; (cpu) < 1; (cpu)++)
+#define for_each_cpu_mask(cpu, mask)		\
+	for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 #endif /* NR_CPUS */
 
 /*
@@ -405,7 +406,6 @@
 #define any_online_cpu(mask)		0
 #endif
 
-#define for_each_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
 #define for_each_possible_cpu(cpu)  for_each_cpu_mask((cpu), cpu_possible_map)
 #define for_each_online_cpu(cpu)  for_each_cpu_mask((cpu), cpu_online_map)
 #define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map)
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 5a0470e..7f94624 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -66,7 +66,7 @@
 
 struct cipher_desc {
 	struct crypto_tfm *tfm;
-	void (*crfn)(void *ctx, u8 *dst, const u8 *src);
+	void (*crfn)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 	unsigned int (*prfn)(const struct cipher_desc *desc, u8 *dst,
 			     const u8 *src, unsigned int nbytes);
 	void *info;
@@ -79,10 +79,10 @@
 struct cipher_alg {
 	unsigned int cia_min_keysize;
 	unsigned int cia_max_keysize;
-	int (*cia_setkey)(void *ctx, const u8 *key,
+	int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
 	                  unsigned int keylen, u32 *flags);
-	void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src);
-	void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src);
+	void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+	void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 
 	unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
 					u8 *dst, const u8 *src,
@@ -100,20 +100,19 @@
 
 struct digest_alg {
 	unsigned int dia_digestsize;
-	void (*dia_init)(void *ctx);
-	void (*dia_update)(void *ctx, const u8 *data, unsigned int len);
-	void (*dia_final)(void *ctx, u8 *out);
-	int (*dia_setkey)(void *ctx, const u8 *key,
+	void (*dia_init)(struct crypto_tfm *tfm);
+	void (*dia_update)(struct crypto_tfm *tfm, const u8 *data,
+			   unsigned int len);
+	void (*dia_final)(struct crypto_tfm *tfm, u8 *out);
+	int (*dia_setkey)(struct crypto_tfm *tfm, const u8 *key,
 	                  unsigned int keylen, u32 *flags);
 };
 
 struct compress_alg {
-	int (*coa_init)(void *ctx);
-	void (*coa_exit)(void *ctx);
-	int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen,
-	                    u8 *dst, unsigned int *dlen);
-	int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen,
-	                      u8 *dst, unsigned int *dlen);
+	int (*coa_compress)(struct crypto_tfm *tfm, const u8 *src,
+			    unsigned int slen, u8 *dst, unsigned int *dlen);
+	int (*coa_decompress)(struct crypto_tfm *tfm, const u8 *src,
+			      unsigned int slen, u8 *dst, unsigned int *dlen);
 };
 
 #define cra_cipher	cra_u.cipher
@@ -129,14 +128,17 @@
 
 	int cra_priority;
 
-	const char cra_name[CRYPTO_MAX_ALG_NAME];
-	const char cra_driver_name[CRYPTO_MAX_ALG_NAME];
+	char cra_name[CRYPTO_MAX_ALG_NAME];
+	char cra_driver_name[CRYPTO_MAX_ALG_NAME];
 
 	union {
 		struct cipher_alg cipher;
 		struct digest_alg digest;
 		struct compress_alg compress;
 	} cra_u;
+
+	int (*cra_init)(struct crypto_tfm *tfm);
+	void (*cra_exit)(struct crypto_tfm *tfm);
 	
 	struct module *cra_module;
 };
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index aee10b2..e3d1c33 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -8,9 +8,12 @@
 #ifndef _LINUX_DEVICE_MAPPER_H
 #define _LINUX_DEVICE_MAPPER_H
 
+#ifdef __KERNEL__
+
 struct dm_target;
 struct dm_table;
 struct dm_dev;
+struct mapped_device;
 
 typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
 
@@ -78,7 +81,7 @@
 struct target_type {
 	const char *name;
 	struct module *module;
-        unsigned version[3];
+	unsigned version[3];
 	dm_ctr_fn ctr;
 	dm_dtr_fn dtr;
 	dm_map_fn map;
@@ -128,4 +131,108 @@
 int dm_register_target(struct target_type *t);
 int dm_unregister_target(struct target_type *t);
 
-#endif				/* _LINUX_DEVICE_MAPPER_H */
+
+/*-----------------------------------------------------------------
+ * Functions for creating and manipulating mapped devices.
+ * Drop the reference with dm_put when you finish with the object.
+ *---------------------------------------------------------------*/
+
+/*
+ * DM_ANY_MINOR chooses the next available minor number.
+ */
+#define DM_ANY_MINOR (-1)
+int dm_create(int minor, struct mapped_device **md);
+
+/*
+ * Reference counting for md.
+ */
+struct mapped_device *dm_get_md(dev_t dev);
+void dm_get(struct mapped_device *md);
+void dm_put(struct mapped_device *md);
+
+/*
+ * An arbitrary pointer may be stored alongside a mapped device.
+ */
+void dm_set_mdptr(struct mapped_device *md, void *ptr);
+void *dm_get_mdptr(struct mapped_device *md);
+
+/*
+ * A device can still be used while suspended, but I/O is deferred.
+ */
+int dm_suspend(struct mapped_device *md, int with_lockfs);
+int dm_resume(struct mapped_device *md);
+
+/*
+ * Event functions.
+ */
+uint32_t dm_get_event_nr(struct mapped_device *md);
+int dm_wait_event(struct mapped_device *md, int event_nr);
+
+/*
+ * Info functions.
+ */
+const char *dm_device_name(struct mapped_device *md);
+struct gendisk *dm_disk(struct mapped_device *md);
+int dm_suspended(struct mapped_device *md);
+
+/*
+ * Geometry functions.
+ */
+int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
+int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
+
+
+/*-----------------------------------------------------------------
+ * Functions for manipulating device-mapper tables.
+ *---------------------------------------------------------------*/
+
+/*
+ * First create an empty table.
+ */
+int dm_table_create(struct dm_table **result, int mode,
+		    unsigned num_targets, struct mapped_device *md);
+
+/*
+ * Then call this once for each target.
+ */
+int dm_table_add_target(struct dm_table *t, const char *type,
+			sector_t start, sector_t len, char *params);
+
+/*
+ * Finally call this to make the table ready for use.
+ */
+int dm_table_complete(struct dm_table *t);
+
+/*
+ * Table reference counting.
+ */
+struct dm_table *dm_get_table(struct mapped_device *md);
+void dm_table_get(struct dm_table *t);
+void dm_table_put(struct dm_table *t);
+
+/*
+ * Queries
+ */
+sector_t dm_table_get_size(struct dm_table *t);
+unsigned int dm_table_get_num_targets(struct dm_table *t);
+int dm_table_get_mode(struct dm_table *t);
+struct mapped_device *dm_table_get_md(struct dm_table *t);
+
+/*
+ * Trigger an event.
+ */
+void dm_table_event(struct dm_table *t);
+
+/*
+ * The device must be suspended before calling this method.
+ */
+int dm_swap_table(struct mapped_device *md, struct dm_table *t);
+
+/*
+ * Prepare a table for a device that will error all I/O.
+ * To make it active, call dm_suspend(), dm_swap_table() then dm_resume().
+ */
+int dm_create_error_table(struct dm_table **result, struct mapped_device *md);
+
+#endif	/* __KERNEL__ */
+#endif	/* _LINUX_DEVICE_MAPPER_H */
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index c67c678..9623bb6 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -285,9 +285,9 @@
 #define DM_DEV_SET_GEOMETRY	_IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR	4
-#define DM_VERSION_MINOR	6
+#define DM_VERSION_MINOR	7
 #define DM_VERSION_PATCHLEVEL	0
-#define DM_VERSION_EXTRA	"-ioctl (2006-02-17)"
+#define DM_VERSION_EXTRA	"-ioctl (2006-06-24)"
 
 /* Status bits */
 #define DM_READONLY_FLAG	(1 << 0) /* In/Out */
@@ -314,7 +314,7 @@
 #define DM_BUFFER_FULL_FLAG	(1 << 8) /* Out */
 
 /*
- * Set this to improve performance when you aren't going to use open_count.
+ * This flag is now ignored.
  */
 #define DM_SKIP_BDGET_FLAG	(1 << 9) /* In */
 
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 2787b8a..c6a2353 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -88,20 +88,6 @@
 #define DMX_PES_PCR      DMX_PES_PCR0
 
 
-typedef enum
-{
-	DMX_SCRAMBLING_EV,
-	DMX_FRONTEND_EV
-} dmx_event_t;
-
-
-typedef enum
-{
-	DMX_SCRAMBLING_OFF,
-	DMX_SCRAMBLING_ON
-} dmx_scrambling_status_t;
-
-
 typedef struct dmx_filter
 {
 	__u8  filter[DMX_FILTER_SIZE];
@@ -132,17 +118,6 @@
 	__u32          flags;
 };
 
-
-struct dmx_event
-{
-	dmx_event_t         event;
-	time_t              timeStamp;
-	union
-	{
-		dmx_scrambling_status_t scrambling;
-	} u;
-};
-
 typedef struct dmx_caps {
 	__u32 caps;
 	int num_decoders;
@@ -171,7 +146,6 @@
 #define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
 #define DMX_SET_PES_FILTER       _IOW('o', 44, struct dmx_pes_filter_params)
 #define DMX_SET_BUFFER_SIZE      _IO('o', 45)
-#define DMX_GET_EVENT            _IOR('o', 46, struct dmx_event)
 #define DMX_GET_PES_PIDS         _IOR('o', 47, __u16[5])
 #define DMX_GET_CAPS             _IOR('o', 48, dmx_caps_t)
 #define DMX_SET_SOURCE           _IOW('o', 49, dmx_source_t)
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
index 1e4bdfc..84cfa8b 100644
--- a/include/linux/eventpoll.h
+++ b/include/linux/eventpoll.h
@@ -1,6 +1,6 @@
 /*
  *  include/linux/eventpoll.h ( Efficent event polling implementation )
- *  Copyright (C) 2001,...,2003	 Davide Libenzi
+ *  Copyright (C) 2001,...,2006	 Davide Libenzi
  *
  *  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
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 757d54d..5607e64 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -710,6 +710,14 @@
 	__u32		next_hash;
 };
 
+/* calculate the first block number of the group */
+static inline ext3_fsblk_t
+ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
+{
+	return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
+		le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
+}
+
 /*
  * Special error return code only used by dx_probe() and its callers.
  */
@@ -730,14 +738,16 @@
 /* balloc.c */
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
-extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
-extern int ext3_new_blocks (handle_t *, struct inode *, unsigned long,
-			unsigned long *, int *);
-extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
-			      unsigned long);
-extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
-				 unsigned long, unsigned long, int *);
-extern unsigned long ext3_count_free_blocks (struct super_block *);
+extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode,
+			ext3_fsblk_t goal, int *errp);
+extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode,
+			ext3_fsblk_t goal, unsigned long *count, int *errp);
+extern void ext3_free_blocks (handle_t *handle, struct inode *inode,
+			ext3_fsblk_t block, unsigned long count);
+extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb,
+				 ext3_fsblk_t block, unsigned long count,
+				unsigned long *pdquot_freed_blocks);
+extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *);
 extern void ext3_check_blocks_bitmap (struct super_block *);
 extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
 						    unsigned int block_group,
@@ -773,7 +783,8 @@
 
 
 /* inode.c */
-int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
+int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
+		struct buffer_head *bh, ext3_fsblk_t blocknr);
 struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
 int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
@@ -808,7 +819,7 @@
 				struct ext3_new_group_data *input);
 extern int ext3_group_extend(struct super_block *sb,
 				struct ext3_super_block *es,
-				unsigned long n_blocks_count);
+				ext3_fsblk_t n_blocks_count);
 
 /* super.c */
 extern void ext3_error (struct super_block *, const char *, const char *, ...)
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
index 7abf901..2f18b95 100644
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -21,9 +21,17 @@
 #include <linux/seqlock.h>
 #include <linux/mutex.h>
 
+/* data type for block offset of block group */
+typedef int ext3_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long ext3_fsblk_t;
+
+#define E3FSBLK "%lu"
+
 struct ext3_reserve_window {
-	__u32			_rsv_start;	/* First byte reserved */
-	__u32			_rsv_end;	/* Last byte reserved or 0 */
+	ext3_fsblk_t	_rsv_start;	/* First byte reserved */
+	ext3_fsblk_t	_rsv_end;	/* Last byte reserved or 0 */
 };
 
 struct ext3_reserve_window_node {
@@ -50,7 +58,7 @@
 	 * allocated to this file.  This give us the goal (target) for the next
 	 * allocation when we detect linearly ascending requests.
 	 */
-	__u32                   last_alloc_physical_block;
+	ext3_fsblk_t		last_alloc_physical_block;
 };
 
 #define rsv_start rsv_window._rsv_start
@@ -67,7 +75,7 @@
 	__u8	i_frag_no;
 	__u8	i_frag_size;
 #endif
-	__u32	i_file_acl;
+	ext3_fsblk_t	i_file_acl;
 	__u32	i_dir_acl;
 	__u32	i_dtime;
 
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 315d897..07a08e9 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_FB_H
 #define _LINUX_FB_H
 
+#include <linux/backlight.h>
 #include <asm/types.h>
 
 /* Definitions of frame buffers						*/
@@ -366,6 +367,12 @@
 	struct fb_image	image;	/* Cursor image */
 };
 
+#ifdef CONFIG_FB_BACKLIGHT
+/* Settings for the generic backlight code */
+#define FB_BACKLIGHT_LEVELS	128
+#define FB_BACKLIGHT_MAX	0xFF
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/fs.h>
@@ -497,23 +504,19 @@
 #define FB_EVENT_MODE_DELETE            0x04
 /*      A driver registered itself */
 #define FB_EVENT_FB_REGISTERED          0x05
+/*      A driver unregistered itself */
+#define FB_EVENT_FB_UNREGISTERED        0x06
 /*      CONSOLE-SPECIFIC: get console to framebuffer mapping */
-#define FB_EVENT_GET_CONSOLE_MAP        0x06
+#define FB_EVENT_GET_CONSOLE_MAP        0x07
 /*      CONSOLE-SPECIFIC: set console to framebuffer mapping */
-#define FB_EVENT_SET_CONSOLE_MAP        0x07
+#define FB_EVENT_SET_CONSOLE_MAP        0x08
 /*      A display blank is requested       */
-#define FB_EVENT_BLANK                  0x08
+#define FB_EVENT_BLANK                  0x09
 /*      Private modelist is to be replaced */
-#define FB_EVENT_NEW_MODELIST           0x09
+#define FB_EVENT_NEW_MODELIST           0x0A
 /*	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
+#define FB_EVENT_MODE_CHANGE_ALL	0x0B
 
 struct fb_event {
 	struct fb_info *info;
@@ -756,6 +759,21 @@
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
 	struct fb_videomode *mode;	/* current mode */
+
+#ifdef CONFIG_FB_BACKLIGHT
+	/* Lock ordering:
+	 * bl_mutex (protects bl_dev and bl_curve)
+	 *   bl_dev->sem (backlight class)
+	 */
+	struct mutex bl_mutex;
+
+	/* assigned backlight device */
+	struct backlight_device *bl_dev;
+
+	/* Backlight level curve */
+	u8 bl_curve[FB_BACKLIGHT_LEVELS];
+#endif
+
 	struct fb_ops *fbops;
 	struct device *device;
 	struct class_device *class_device; /* sysfs per device attrs */
@@ -870,7 +888,6 @@
 			      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;
@@ -895,6 +912,7 @@
 extern void framebuffer_release(struct fb_info *info);
 extern int fb_init_class_device(struct fb_info *fb_info);
 extern void fb_cleanup_class_device(struct fb_info *head);
+extern void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max);
 
 /* drivers/video/fbmon.c */
 #define FB_MAXTIMINGS		0
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index c52a637..996f561 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -29,6 +29,7 @@
 #define AT_SYMLINK_NOFOLLOW	0x100   /* Do not follow symbolic links.  */
 #define AT_REMOVEDIR		0x200   /* Remove directory instead of
                                            unlinking file.  */
+#define AT_SYMLINK_FOLLOW	0x400   /* Follow symbolic links.  */
 
 #ifdef __KERNEL__
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index dba4cbd..2d8b348 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1100,7 +1100,7 @@
 	int (*statfs) (struct dentry *, struct kstatfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
-	void (*umount_begin) (struct super_block *);
+	void (*umount_begin) (struct vfsmount *, int);
 
 	int (*show_options)(struct seq_file *, struct vfsmount *);
 	int (*show_stats)(struct seq_file *, struct vfsmount *);
@@ -1767,7 +1767,7 @@
 struct tree_descr { char *name; const struct file_operations *ops; int mode; };
 struct dentry *d_alloc_name(struct dentry *, const char *);
 extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
-extern int simple_pin_fs(char *name, struct vfsmount **mount, int *count);
+extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count);
 extern void simple_release_fs(struct vfsmount **mount, int *count);
 
 extern ssize_t simple_read_from_buffer(void __user *, size_t, loff_t *, const void *, size_t);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 5425b60..9fc48a6 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -1,6 +1,6 @@
 /*
     FUSE: Filesystem in Userspace
-    Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
+    Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
 
     This program can be distributed under the terms of the GNU GPL.
     See the file COPYING.
@@ -9,18 +9,19 @@
 /* This file defines the kernel interface of FUSE */
 
 #include <asm/types.h>
+#include <linux/major.h>
 
 /** Version number of this interface */
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 6
+#define FUSE_KERNEL_MINOR_VERSION 7
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
 
 /** The major number of the fuse character device */
-#define FUSE_MAJOR 10
+#define FUSE_MAJOR MISC_MAJOR
 
 /** The minor number of the fuse character device */
 #define FUSE_MINOR 229
@@ -58,6 +59,13 @@
 	__u32	spare[6];
 };
 
+struct fuse_file_lock {
+	__u64	start;
+	__u64	end;
+	__u32	type;
+	__u32	pid; /* tgid */
+};
+
 /**
  * Bitmasks for fuse_setattr_in.valid
  */
@@ -82,6 +90,7 @@
  * INIT request/reply flags
  */
 #define FUSE_ASYNC_READ		(1 << 0)
+#define FUSE_POSIX_LOCKS	(1 << 1)
 
 enum fuse_opcode {
 	FUSE_LOOKUP	   = 1,
@@ -112,8 +121,12 @@
 	FUSE_READDIR       = 28,
 	FUSE_RELEASEDIR    = 29,
 	FUSE_FSYNCDIR      = 30,
+	FUSE_GETLK         = 31,
+	FUSE_SETLK         = 32,
+	FUSE_SETLKW        = 33,
 	FUSE_ACCESS        = 34,
-	FUSE_CREATE        = 35
+	FUSE_CREATE        = 35,
+	FUSE_INTERRUPT     = 36,
 };
 
 /* The read buffer is required to be at least 8k, but may be much larger */
@@ -199,6 +212,7 @@
 	__u64	fh;
 	__u32	flush_flags;
 	__u32	padding;
+	__u64	lock_owner;
 };
 
 struct fuse_read_in {
@@ -247,6 +261,16 @@
 	__u32	padding;
 };
 
+struct fuse_lk_in {
+	__u64	fh;
+	__u64	owner;
+	struct fuse_file_lock lk;
+};
+
+struct fuse_lk_out {
+	struct fuse_file_lock lk;
+};
+
 struct fuse_access_in {
 	__u32	mask;
 	__u32	padding;
@@ -268,6 +292,10 @@
 	__u32	max_write;
 };
 
+struct fuse_interrupt_in {
+	__u64	unique;
+};
+
 struct fuse_in_header {
 	__u32	len;
 	__u32	opcode;
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 7d2a1b9..07d7305 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -40,7 +40,6 @@
 
 /**
  * struct hrtimer - the basic hrtimer structure
- *
  * @node:	red black tree node for time ordered insertion
  * @expires:	the absolute expiry time in the hrtimers internal
  *		representation. The time is related to the clock on
@@ -59,7 +58,6 @@
 
 /**
  * struct hrtimer_sleeper - simple sleeper structure
- *
  * @timer:	embedded timer structure
  * @task:	task to wake up
  *
@@ -72,7 +70,6 @@
 
 /**
  * struct hrtimer_base - the timer base for a specific clock
- *
  * @index:		clock type index for per_cpu support when moving a timer
  *			to a base on another cpu.
  * @lock:		lock protecting the base and associated timers
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
new file mode 100644
index 0000000..21ea761
--- /dev/null
+++ b/include/linux/hw_random.h
@@ -0,0 +1,50 @@
+/*
+	Hardware Random Number Generator
+
+	Please read Documentation/hw_random.txt for details on use.
+
+	----------------------------------------------------------
+	This software may be used and distributed according to the terms
+        of the GNU General Public License, incorporated herein by reference.
+
+ */
+
+#ifndef LINUX_HWRANDOM_H_
+#define LINUX_HWRANDOM_H_
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+/**
+ * struct hwrng - Hardware Random Number Generator driver
+ * @name:		Unique RNG name.
+ * @init:		Initialization callback (can be NULL).
+ * @cleanup:		Cleanup callback (can be NULL).
+ * @data_present:	Callback to determine if data is available
+ *			on the RNG. If NULL, it is assumed that
+ *			there is always data available.
+ * @data_read:		Read data from the RNG device.
+ *			Returns the number of lower random bytes in "data".
+ *			Must not be NULL.
+ * @priv:		Private data, for use by the RNG driver.
+ */
+struct hwrng {
+	const char *name;
+	int (*init)(struct hwrng *rng);
+	void (*cleanup)(struct hwrng *rng);
+	int (*data_present)(struct hwrng *rng);
+	int (*data_read)(struct hwrng *rng, u32 *data);
+	unsigned long priv;
+
+	/* internal. */
+	struct list_head list;
+};
+
+/** Register a new Hardware Random Number Generator driver. */
+extern int hwrng_register(struct hwrng *rng);
+/** Unregister a Hardware Random Number Generator driver. */
+extern void hwrng_unregister(struct hwrng *rng);
+
+#endif /* __KERNEL__ */
+#endif /* LINUX_HWRANDOM_H_ */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index c8b81f4..21338bb 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -112,6 +112,9 @@
 #define I2C_DRIVERID_X1205	82	/* Xicor/Intersil X1205 RTC	*/
 #define I2C_DRIVERID_PCF8563	83	/* Philips PCF8563 RTC		*/
 #define I2C_DRIVERID_RS5C372	84	/* Ricoh RS5C372 RTC		*/
+#define I2C_DRIVERID_BT866	85	/* Conexant bt866 video encoder */
+#define I2C_DRIVERID_KS0127	86	/* Samsung ks0127 video decoder */
+#define I2C_DRIVERID_TLV320AIC23B 87	/* TI TLV320AIC23B audio codec  */
 
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 77e66d0..ef7bef2 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -630,6 +630,7 @@
 	unsigned int	usage;		/* current "open()" count for drive */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
+	u64		probed_capacity;/* initial reported media capacity (ide-cd only currently) */
 
 	u64		capacity64;	/* total number of sectors */
 
@@ -1005,6 +1006,8 @@
 extern int noautodma;
 
 extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+			     int uptodate, int nr_sectors);
 
 /*
  * This is used on exit from the driver to designate the next irq handler
diff --git a/include/linux/idr.h b/include/linux/idr.h
index d37c8d8..f559a71 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -78,6 +78,7 @@
 int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
 int idr_get_new(struct idr *idp, void *ptr, int *id);
 int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
+void *idr_replace(struct idr *idp, void *ptr, int id);
 void idr_remove(struct idr *idp, int id);
 void idr_destroy(struct idr *idp);
 void idr_init(struct idr *idp);
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 41ecbb8..e127ef7 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -119,7 +119,6 @@
 		.signal = {{0}}},					\
 	.blocked	= {{0}},					\
 	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
-	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
 	.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
 	.fs_excl	= ATOMIC_INIT(0),				\
diff --git a/include/linux/input.h b/include/linux/input.h
index b32c2b6..56f1e0e 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -232,7 +232,8 @@
 #define KEY_PAUSE		119
 
 #define KEY_KPCOMMA		121
-#define KEY_HANGUEL		122
+#define KEY_HANGEUL		122
+#define KEY_HANGUEL		KEY_HANGEUL
 #define KEY_HANJA		123
 #define KEY_YEN			124
 #define KEY_LEFTMETA		125
@@ -1005,6 +1006,7 @@
 }
 
 struct input_dev *input_allocate_device(void);
+void input_free_device(struct input_dev *dev);
 
 static inline struct input_dev *input_get_device(struct input_dev *dev)
 {
@@ -1016,12 +1018,6 @@
 	class_device_put(&dev->cdev);
 }
 
-static inline void input_free_device(struct input_dev *dev)
-{
-	if (dev)
-		input_put_device(dev);
-}
-
 int input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 8c21aaa..5c1ec1f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -32,6 +32,7 @@
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 
 #define	KERN_EMERG	"<0>"	/* system is unusable			*/
 #define	KERN_ALERT	"<1>"	/* action must be taken immediately	*/
@@ -117,6 +118,8 @@
 	__attribute__ ((format (printf, 3, 4)));
 extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
 	__attribute__ ((format (printf, 3, 0)));
+extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
 
 extern int sscanf(const char *, const char *, ...)
 	__attribute__ ((format (scanf, 2, 3)));
@@ -334,6 +337,12 @@
 /* Force a compilation error if condition is true */
 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
 
+/* Force a compilation error if condition is true, but also produce a
+   result (of value 0 and type size_t), so the expression can be used
+   e.g. in a structure initializer (or where-ever else comma expressions
+   aren't permitted). */
+#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
+
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)
 
diff --git a/include/linux/key.h b/include/linux/key.h
index e81ebf9..e693e72 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -248,7 +248,14 @@
 			     const char *desc,
 			     uid_t uid, gid_t gid,
 			     struct task_struct *ctx,
-			     key_perm_t perm, int not_in_quota);
+			     key_perm_t perm,
+			     unsigned long flags);
+
+
+#define KEY_ALLOC_IN_QUOTA	0x0000	/* add to quota, reject if would overrun */
+#define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
+#define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
+
 extern int key_payload_reserve(struct key *key, size_t datalen);
 extern int key_instantiate_and_link(struct key *key,
 				    const void *data,
@@ -285,7 +292,7 @@
 				      const char *description,
 				      const void *payload,
 				      size_t plen,
-				      int not_in_quota);
+				      unsigned long flags);
 
 extern int key_update(key_ref_t key,
 		      const void *payload,
@@ -299,7 +306,7 @@
 
 extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
 				 struct task_struct *ctx,
-				 int not_in_quota,
+				 unsigned long flags,
 				 struct key *dest);
 
 extern int keyring_clear(struct key *keyring);
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index ebdd41f..7cce5df 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -4,37 +4,19 @@
 #include <linux/err.h>
 #include <linux/sched.h>
 
-/**
- * kthread_create: create a kthread.
- * @threadfn: the function to run until signal_pending(current).
- * @data: data ptr for @threadfn.
- * @namefmt: printf-style name for the thread.
- *
- * Description: This helper function creates and names a kernel
- * thread.  The thread will be stopped: use wake_up_process() to start
- * it.  See also kthread_run(), kthread_create_on_cpu().
- *
- * When woken, the thread will run @threadfn() with @data as its
- * argument. @threadfn can either call do_exit() directly if it is a
- * standalone thread for which noone will call kthread_stop(), or
- * return when 'kthread_should_stop()' is true (which means
- * kthread_stop() has been called).  The return value should be zero
- * or a negative error number: it will be passed to kthread_stop().
- *
- * Returns a task_struct or ERR_PTR(-ENOMEM).
- */
 struct task_struct *kthread_create(int (*threadfn)(void *data),
 				   void *data,
 				   const char namefmt[], ...);
 
 /**
- * kthread_run: create and wake a thread.
+ * kthread_run - create and wake a thread.
  * @threadfn: the function to run until signal_pending(current).
  * @data: data ptr for @threadfn.
  * @namefmt: printf-style name for the thread.
  *
  * Description: Convenient wrapper for kthread_create() followed by
- * wake_up_process().  Returns the kthread, or ERR_PTR(-ENOMEM). */
+ * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
+ */
 #define kthread_run(threadfn, data, namefmt, ...)			   \
 ({									   \
 	struct task_struct *__k						   \
@@ -44,50 +26,9 @@
 	__k;								   \
 })
 
-/**
- * kthread_bind: bind a just-created kthread to a cpu.
- * @k: thread created by kthread_create().
- * @cpu: cpu (might not be online, must be possible) for @k to run on.
- *
- * Description: This function is equivalent to set_cpus_allowed(),
- * except that @cpu doesn't need to be online, and the thread must be
- * stopped (ie. just returned from kthread_create().
- */
 void kthread_bind(struct task_struct *k, unsigned int cpu);
-
-/**
- * kthread_stop: stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- *
- * Sets kthread_should_stop() for @k to return true, wakes it, and
- * waits for it to exit.  Your threadfn() must not call do_exit()
- * itself if you use this function!  This can also be called after
- * kthread_create() instead of calling wake_up_process(): the thread
- * will exit without calling threadfn().
- *
- * Returns the result of threadfn(), or -EINTR if wake_up_process()
- * was never called. */
 int kthread_stop(struct task_struct *k);
-
-/**
- * kthread_stop_sem: stop a thread created by kthread_create().
- * @k: thread created by kthread_create().
- * @s: semaphore that @k waits on while idle.
- *
- * Does essentially the same thing as kthread_stop() above, but wakes
- * @k by calling up(@s).
- *
- * Returns the result of threadfn(), or -EINTR if wake_up_process()
- * was never called. */
 int kthread_stop_sem(struct task_struct *k, struct semaphore *s);
-
-/**
- * kthread_should_stop: should this kthread return now?
- *
- * When someone calls kthread_stop on your kthread, it will be woken
- * and this will return true.  You should then return, and your return
- * value will be passed through to kthread_stop().
- */
 int kthread_should_stop(void);
 
 #endif /* _LINUX_KTHREAD_H */
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 62bc575..ed3396d 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -66,7 +66,6 @@
 
 /**
  * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
- *
  * @secs:	seconds to set
  * @nsecs:	nanoseconds to set
  *
@@ -138,7 +137,6 @@
 
 /**
  * ktime_sub - subtract two ktime_t variables
- *
  * @lhs:	minuend
  * @rhs:	subtrahend
  *
@@ -157,7 +155,6 @@
 
 /**
  * ktime_add - add two ktime_t variables
- *
  * @add1:	addend1
  * @add2:	addend2
  *
@@ -184,7 +181,6 @@
 
 /**
  * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
- *
  * @kt:		addend
  * @nsec:	the scalar nsec value to add
  *
@@ -194,7 +190,6 @@
 
 /**
  * timespec_to_ktime - convert a timespec to ktime_t format
- *
  * @ts:		the timespec variable to convert
  *
  * Returns a ktime_t variable with the converted timespec value
@@ -207,7 +202,6 @@
 
 /**
  * timeval_to_ktime - convert a timeval to ktime_t format
- *
  * @tv:		the timeval variable to convert
  *
  * Returns a ktime_t variable with the converted timeval value
@@ -220,7 +214,6 @@
 
 /**
  * ktime_to_timespec - convert a ktime_t variable to timespec format
- *
  * @kt:		the ktime_t variable to convert
  *
  * Returns the timespec representation of the ktime value
@@ -233,7 +226,6 @@
 
 /**
  * ktime_to_timeval - convert a ktime_t variable to timeval format
- *
  * @kt:		the ktime_t variable to convert
  *
  * Returns the timeval representation of the ktime value
diff --git a/include/linux/license.h b/include/linux/license.h
new file mode 100644
index 0000000..decdbf4
--- /dev/null
+++ b/include/linux/license.h
@@ -0,0 +1,14 @@
+#ifndef __LICENSE_H
+#define __LICENSE_H
+
+static inline int license_is_gpl_compatible(const char *license)
+{
+	return (strcmp(license, "GPL") == 0
+		|| strcmp(license, "GPL v2") == 0
+		|| strcmp(license, "GPL and additional rights") == 0
+		|| strcmp(license, "Dual BSD/GPL") == 0
+		|| strcmp(license, "Dual MIT/GPL") == 0
+		|| strcmp(license, "Dual MPL/GPL") == 0);
+}
+
+#endif
diff --git a/include/linux/list.h b/include/linux/list.h
index a02642e..37ca31b 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -281,16 +281,17 @@
 }
 
 /**
- * list_empty_careful - tests whether a list is
- * empty _and_ checks that no other CPU might be
- * in the process of still modifying either member
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
  *
  * NOTE: using list_empty_careful() without synchronization
  * can only be safe if the only activity that can happen
  * to the list entry is list_del_init(). Eg. it cannot be used
  * if another CPU could re-list_add() it.
- *
- * @head: the list to test.
  */
 static inline int list_empty_careful(const struct list_head *head)
 {
@@ -350,7 +351,7 @@
 
 /**
  * list_for_each	-	iterate over a list
- * @pos:	the &struct list_head to use as a loop counter.
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
  */
 #define list_for_each(pos, head) \
@@ -359,7 +360,7 @@
 
 /**
  * __list_for_each	-	iterate over a list
- * @pos:	the &struct list_head to use as a loop counter.
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
  *
  * This variant differs from list_for_each() in that it's the
@@ -372,7 +373,7 @@
 
 /**
  * list_for_each_prev	-	iterate over a list backwards
- * @pos:	the &struct list_head to use as a loop counter.
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
  */
 #define list_for_each_prev(pos, head) \
@@ -380,8 +381,8 @@
         	pos = pos->prev)
 
 /**
- * list_for_each_safe	-	iterate over a list safe against removal of list entry
- * @pos:	the &struct list_head to use as a loop counter.
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @n:		another &struct list_head to use as temporary storage
  * @head:	the head for your list.
  */
@@ -391,7 +392,7 @@
 
 /**
  * list_for_each_entry	-	iterate over list of given type
- * @pos:	the type * to use as a loop counter.
+ * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
  */
@@ -402,7 +403,7 @@
 
 /**
  * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos:	the type * to use as a loop counter.
+ * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
  */
@@ -412,21 +413,24 @@
 	     pos = list_entry(pos->member.prev, typeof(*pos), member))
 
 /**
- * list_prepare_entry - prepare a pos entry for use as a start point in
- *			list_for_each_entry_continue
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
  * @pos:	the type * to use as a start point
  * @head:	the head of the list
  * @member:	the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
  */
 #define list_prepare_entry(pos, head, member) \
 	((pos) ? : list_entry(head, typeof(*pos), member))
 
 /**
- * list_for_each_entry_continue -	iterate over list of given type
- *			continuing after existing point
- * @pos:	the type * to use as a loop counter.
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
  */
 #define list_for_each_entry_continue(pos, head, member) 		\
 	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
@@ -434,11 +438,12 @@
 	     pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
- * list_for_each_entry_from -	iterate over list of given type
- *			continuing from existing point
- * @pos:	the type * to use as a loop counter.
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
  */
 #define list_for_each_entry_from(pos, head, member) 			\
 	for (; prefetch(pos->member.next), &pos->member != (head);	\
@@ -446,7 +451,7 @@
 
 /**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop counter.
+ * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
@@ -458,12 +463,14 @@
 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
- * list_for_each_entry_safe_continue -	iterate over list of given type
- *			continuing after existing point safe against removal of list entry
- * @pos:	the type * to use as a loop counter.
+ * list_for_each_entry_safe_continue
+ * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
 	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
@@ -472,12 +479,14 @@
 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
- * list_for_each_entry_safe_from - iterate over list of given type
- *			from existing point safe against removal of list entry
- * @pos:	the type * to use as a loop counter.
+ * list_for_each_entry_safe_from
+ * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
 	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
@@ -485,12 +494,14 @@
 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
- * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
- *				      removal of list entry
- * @pos:	the type * to use as a loop counter.
+ * list_for_each_entry_safe_reverse
+ * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
 	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
@@ -500,7 +511,7 @@
 
 /**
  * list_for_each_rcu	-	iterate over an rcu-protected list
- * @pos:	the &struct list_head to use as a loop counter.
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
  *
  * This list-traversal primitive may safely run concurrently with
@@ -518,12 +529,13 @@
         	pos = pos->next)
 
 /**
- * list_for_each_safe_rcu	-	iterate over an rcu-protected list safe
- *					against removal of list entry
- * @pos:	the &struct list_head to use as a loop counter.
+ * list_for_each_safe_rcu
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @n:		another &struct list_head to use as temporary storage
  * @head:	the head for your list.
  *
+ * Iterate over an rcu-protected list, safe against removal of list entry.
+ *
  * This list-traversal primitive may safely run concurrently with
  * the _rcu list-mutation primitives such as list_add_rcu()
  * as long as the traversal is guarded by rcu_read_lock().
@@ -535,7 +547,7 @@
 
 /**
  * list_for_each_entry_rcu	-	iterate over rcu list of given type
- * @pos:	the type * to use as a loop counter.
+ * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the list_struct within the struct.
  *
@@ -551,11 +563,12 @@
 
 
 /**
- * list_for_each_continue_rcu	-	iterate over an rcu-protected list
- *			continuing after existing point.
- * @pos:	the &struct list_head to use as a loop counter.
+ * list_for_each_continue_rcu
+ * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
  *
+ * Iterate over an rcu-protected list, continuing after current point.
+ *
  * This list-traversal primitive may safely run concurrently with
  * the _rcu list-mutation primitives such as list_add_rcu()
  * as long as the traversal is guarded by rcu_read_lock().
@@ -681,11 +694,14 @@
 
 
 /**
- * hlist_add_head_rcu - adds the specified element to the specified hlist,
- * while permitting racing traversals.
+ * hlist_add_head_rcu
  * @n: the element to add to the hash list.
  * @h: the list to add to.
  *
+ * Description:
+ * Adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ *
  * The caller must take whatever precautions are necessary
  * (such as holding appropriate locks) to avoid racing
  * with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -730,11 +746,14 @@
 }
 
 /**
- * hlist_add_before_rcu - adds the specified element to the specified hlist
- * before the specified node while permitting racing traversals.
+ * hlist_add_before_rcu
  * @n: the new element to add to the hash list.
  * @next: the existing element to add the new element before.
  *
+ * Description:
+ * Adds the specified element to the specified hlist
+ * before the specified node while permitting racing traversals.
+ *
  * The caller must take whatever precautions are necessary
  * (such as holding appropriate locks) to avoid racing
  * with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -755,11 +774,14 @@
 }
 
 /**
- * hlist_add_after_rcu - adds the specified element to the specified hlist
- * after the specified node while permitting racing traversals.
+ * hlist_add_after_rcu
  * @prev: the existing element to add the new element after.
  * @n: the new element to add to the hash list.
  *
+ * Description:
+ * Adds the specified element to the specified hlist
+ * after the specified node while permitting racing traversals.
+ *
  * The caller must take whatever precautions are necessary
  * (such as holding appropriate locks) to avoid racing
  * with another list-mutation primitive, such as hlist_add_head_rcu()
@@ -792,8 +814,8 @@
 
 /**
  * hlist_for_each_entry	- iterate over list of given type
- * @tpos:	the type * to use as a loop counter.
- * @pos:	the &struct hlist_node to use as a loop counter.
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the hlist_node within the struct.
  */
@@ -804,9 +826,9 @@
 	     pos = pos->next)
 
 /**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
- * @tpos:	the type * to use as a loop counter.
- * @pos:	the &struct hlist_node to use as a loop counter.
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
  * @member:	the name of the hlist_node within the struct.
  */
 #define hlist_for_each_entry_continue(tpos, pos, member)		 \
@@ -816,9 +838,9 @@
 	     pos = pos->next)
 
 /**
- * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
- * @tpos:	the type * to use as a loop counter.
- * @pos:	the &struct hlist_node to use as a loop counter.
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
  * @member:	the name of the hlist_node within the struct.
  */
 #define hlist_for_each_entry_from(tpos, pos, member)			 \
@@ -828,8 +850,8 @@
 
 /**
  * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @tpos:	the type * to use as a loop counter.
- * @pos:	the &struct hlist_node to use as a loop counter.
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
  * @n:		another &struct hlist_node to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the hlist_node within the struct.
@@ -842,8 +864,8 @@
 
 /**
  * hlist_for_each_entry_rcu - iterate over rcu list of given type
- * @tpos:	the type * to use as a loop counter.
- * @pos:	the &struct hlist_node to use as a loop counter.
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
  * @head:	the head for your list.
  * @member:	the name of the hlist_node within the struct.
  *
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index a8876bc..aa4fe90 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -49,11 +49,12 @@
 				h_killed     : 1,
 				h_monitored  : 1;
 	wait_queue_head_t	h_gracewait;	/* wait while reclaiming */
+	struct rw_semaphore	h_rwsem;	/* Reboot recovery lock */
 	u32			h_state;	/* pseudo-state counter */
 	u32			h_nsmstate;	/* true remote NSM state */
 	u32			h_pidcount;	/* Pseudopids */
 	atomic_t		h_count;	/* reference count */
-	struct semaphore	h_sema;		/* mutex for pmap binding */
+	struct mutex		h_mutex;	/* mutex for pmap binding */
 	unsigned long		h_nextrebind;	/* next portmap call */
 	unsigned long		h_expires;	/* eligible for GC */
 	struct list_head	h_lockowners;	/* Lockowners for the client */
@@ -219,6 +220,7 @@
 nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2)
 {
 	return	fl1->fl_pid   == fl2->fl_pid
+	     && fl1->fl_owner == fl2->fl_owner
 	     && fl1->fl_start == fl2->fl_start
 	     && fl1->fl_end   == fl2->fl_end
 	     &&(fl1->fl_type  == fl2->fl_type || fl2->fl_type == F_UNLCK);
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 5dba23a..48148e0 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -16,7 +16,9 @@
 			struct page *, struct page *);
 
 extern int migrate_prep(void);
-
+extern int migrate_vmas(struct mm_struct *mm,
+		const nodemask_t *from, const nodemask_t *to,
+		unsigned long flags);
 #else
 
 static inline int isolate_lru_page(struct page *p, struct list_head *list)
@@ -30,6 +32,13 @@
 
 static inline int migrate_prep(void) { return -ENOSYS; }
 
+static inline int migrate_vmas(struct mm_struct *mm,
+		const nodemask_t *from, const nodemask_t *to,
+		unsigned long flags)
+{
+	return -ENOSYS;
+}
+
 /* Possible settings for the migrate_page() method in address_operations */
 #define migrate_page NULL
 #define fail_migrate_page NULL
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 3b09444..a929ea1 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -145,7 +145,6 @@
 
 #define VM_GROWSDOWN	0x00000100	/* general info on the segment */
 #define VM_GROWSUP	0x00000200
-#define VM_SHM		0x00000000	/* Means nothing: delete it later */
 #define VM_PFNMAP	0x00000400	/* Page-ranges managed without "struct page", just pure PFN */
 #define VM_DENYWRITE	0x00000800	/* ETXTBSY on write attempts.. */
 
@@ -207,6 +206,8 @@
 	int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
 	struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
 					unsigned long addr);
+	int (*migrate)(struct vm_area_struct *vma, const nodemask_t *from,
+		const nodemask_t *to, unsigned long flags);
 #endif
 };
 
diff --git a/include/linux/module.h b/include/linux/module.h
index 2d36609..9ebbb74 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -285,6 +285,9 @@
 	/* The size of the executable code in each section.  */
 	unsigned long init_text_size, core_text_size;
 
+	/* The handle returned from unwind_add_table. */
+	void *unwind_info;
+
 	/* Arch-specific module values */
 	struct mod_arch_specific arch;
 
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 60718f1..403d1a9 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -28,6 +28,8 @@
 #define MNT_NOATIME	0x08
 #define MNT_NODIRATIME	0x10
 
+#define MNT_SHRINKABLE	0x100
+
 #define MNT_SHARED	0x1000	/* if the vfsmount is a shared mount */
 #define MNT_UNBINDABLE	0x2000	/* if the vfsmount is a unbindable mount */
 #define MNT_PNODE_MASK	0x3000	/* propogation flag mask */
@@ -78,12 +80,18 @@
 extern struct vfsmount *do_kern_mount(const char *fstype, int flags,
 				      const char *name, void *data);
 
+struct file_system_type;
+extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
+				      int flags, const char *name,
+				      void *data);
+
 struct nameidata;
 
 extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
 			int mnt_flags, struct list_head *fslist);
 
 extern void mark_mounts_for_expiry(struct list_head *mounts);
+extern void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts);
 
 extern spinlock_t vfsmount_lock;
 extern dev_t name_to_dev_t(char *name);
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 1d7cdd2..e712e7d 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -77,11 +77,11 @@
  * server. All data are in network byte order.
  */
 struct nbd_request {
-	__u32 magic;
-	__u32 type;	/* == READ || == WRITE 	*/
+	__be32 magic;
+	__be32 type;	/* == READ || == WRITE 	*/
 	char handle[8];
-	__u64 from;
-	__u32 len;
+	__be64 from;
+	__be32 len;
 }
 #ifdef __GNUC__
 	__attribute__ ((packed))
@@ -93,8 +93,8 @@
  * it has completed an I/O request (or an error occurs).
  */
 struct nbd_reply {
-	__u32 magic;
-	__u32 error;		/* 0 = ok, else error	*/
+	__be32 magic;
+	__be32 error;		/* 0 = ok, else error	*/
 	char handle[8];		/* handle you got from request	*/
 };
 #endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index bc747e5..03cd755 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -699,7 +699,6 @@
 
 extern void		dev_init(void);
 
-extern int		netdev_nit;
 extern int		netdev_budget;
 
 /* Called by rtnetlink.c:rtnl_unlock() */
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index ca5a873..1efe60c 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -31,6 +31,7 @@
 	int rx_flags;
 	spinlock_t rx_lock;
 	struct netpoll *rx_np; /* netpoll that registered an rx_hook */
+	struct sk_buff_head arp_tx; /* list of arp requests to reply to */
 };
 
 void netpoll_poll(struct netpoll *np);
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 1059e6d..5f681d5 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -384,6 +384,7 @@
 	NFSPROC4_CLNT_DELEGRETURN,
 	NFSPROC4_CLNT_GETACL,
 	NFSPROC4_CLNT_SETACL,
+	NFSPROC4_CLNT_FS_LOCATIONS,
 };
 
 #endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 7e079f8..0a1740b 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -9,6 +9,27 @@
 #ifndef _LINUX_NFS_FS_H
 #define _LINUX_NFS_FS_H
 
+#include <linux/config.h>
+#include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <linux/wait.h>
+
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
+
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_xdr.h>
+
+#include <linux/nfs_fs_sb.h>
+
+#include <linux/rwsem.h>
+#include <linux/mempool.h>
 
 /*
  * Enable debugging support for nfs client.
@@ -41,27 +62,9 @@
 #define FLUSH_LOWPRI		8	/* low priority background flush */
 #define FLUSH_HIGHPRI		16	/* high priority memory reclaim flush */
 #define FLUSH_NOCOMMIT		32	/* Don't send the NFSv3/v4 COMMIT */
+#define FLUSH_INVALIDATE	64	/* Invalidate the page cache */
 
 #ifdef __KERNEL__
-#include <linux/in.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/rwsem.h>
-#include <linux/wait.h>
-
-#include <linux/nfs_fs_sb.h>
-
-#include <linux/sunrpc/debug.h>
-#include <linux/sunrpc/auth.h>
-#include <linux/sunrpc/clnt.h>
-
-#include <linux/nfs.h>
-#include <linux/nfs2.h>
-#include <linux/nfs3.h>
-#include <linux/nfs4.h>
-#include <linux/nfs_xdr.h>
-#include <linux/rwsem.h>
-#include <linux/mempool.h>
 
 /*
  * NFSv3/v4 Access mode cache entry
@@ -233,8 +236,12 @@
 
 static inline void nfs_mark_for_revalidate(struct inode *inode)
 {
+	struct nfs_inode *nfsi = NFS_I(inode);
+
 	spin_lock(&inode->i_lock);
-	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+	nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+	if (S_ISDIR(inode->i_mode))
+		nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
 	spin_unlock(&inode->i_lock);
 }
 
@@ -296,7 +303,7 @@
 extern int nfs_attribute_timeout(struct inode *inode);
 extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
-extern void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
 extern int nfs_setattr(struct dentry *, struct iattr *);
 extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
 extern void nfs_begin_attr_update(struct inode *);
@@ -306,6 +313,10 @@
 extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
 extern void put_nfs_open_context(struct nfs_open_context *ctx);
 extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
+extern struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+					const struct dentry *dentry,
+					struct nfs_fh *fh,
+					struct nfs_fattr *fattr);
 
 /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
 extern u32 root_nfs_parse_addr(char *name); /*__init*/
@@ -392,6 +403,15 @@
 #endif
 
 /*
+ * linux/fs/nfs/namespace.c
+ */
+extern struct list_head nfs_automount_list;
+extern struct inode_operations nfs_mountpoint_inode_operations;
+extern struct inode_operations nfs_referral_inode_operations;
+extern int nfs_mountpoint_expiry_timeout;
+extern void nfs_release_automount_timer(void);
+
+/*
  * linux/fs/nfs/unlink.c
  */
 extern int  nfs_async_unlink(struct dentry *);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 65dec21..6b4a13c 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -35,6 +35,7 @@
 	char *			hostname;	/* remote hostname */
 	struct nfs_fh		fh;
 	struct sockaddr_in	addr;
+	struct nfs_fsid		fsid;
 	unsigned long		mount_time;	/* when this fs was mounted */
 #ifdef CONFIG_NFS_V4
 	/* Our own IP address, as a null-terminated string.
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 66e2ed6..1f7bd28 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -13,7 +13,6 @@
 #include <linux/list.h>
 #include <linux/pagemap.h>
 #include <linux/wait.h>
-#include <linux/nfs_fs_sb.h>
 #include <linux/sunrpc/auth.h>
 #include <linux/nfs_xdr.h>
 
@@ -63,8 +62,8 @@
 
 extern  int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
 				unsigned long idx_start, unsigned int npages);
-extern	int nfs_scan_list(struct list_head *, struct list_head *,
-			  unsigned long, unsigned int);
+extern	int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
+			  unsigned long idx_start, unsigned int npages);
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
 				  unsigned int);
 extern  int nfs_wait_on_request(struct nfs_page *);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 7fafc4c..7c7320f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -14,11 +14,19 @@
 #define NFS_DEF_FILE_IO_SIZE	(4096U)
 #define NFS_MIN_FILE_IO_SIZE	(1024U)
 
-struct nfs4_fsid {
-	__u64 major;
-	__u64 minor;
+struct nfs_fsid {
+	uint64_t		major;
+	uint64_t		minor;
 };
 
+/*
+ * Helper for checking equality between 2 fsids.
+ */
+static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid *b)
+{
+	return a->major == b->major && a->minor == b->minor;
+}
+
 struct nfs_fattr {
 	unsigned short		valid;		/* which fields are valid */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -40,10 +48,7 @@
 		} nfs3;
 	} du;
 	dev_t			rdev;
-	union {
-		__u64		nfs3;		/* also nfs2 */
-		struct nfs4_fsid nfs4;
-	} fsid_u;
+	struct nfs_fsid		fsid;
 	__u64			fileid;
 	struct timespec		atime;
 	struct timespec		mtime;
@@ -57,8 +62,8 @@
 #define NFS_ATTR_WCC		0x0001		/* pre-op WCC data    */
 #define NFS_ATTR_FATTR		0x0002		/* post-op attributes */
 #define NFS_ATTR_FATTR_V3	0x0004		/* NFSv3 attributes */
-#define NFS_ATTR_FATTR_V4	0x0008
-#define NFS_ATTR_PRE_CHANGE	0x0010
+#define NFS_ATTR_FATTR_V4	0x0008		/* NFSv4 change attribute */
+#define NFS_ATTR_FATTR_V4_REFERRAL	0x0010		/* NFSv4 referral */
 
 /*
  * Info on the file system
@@ -675,6 +680,40 @@
 	u32				has_symlinks;
 };
 
+struct nfs4_string {
+	unsigned int len;
+	char *data;
+};
+
+#define NFS4_PATHNAME_MAXCOMPONENTS 512
+struct nfs4_pathname {
+	unsigned int ncomponents;
+	struct nfs4_string components[NFS4_PATHNAME_MAXCOMPONENTS];
+};
+
+#define NFS4_FS_LOCATION_MAXSERVERS 10
+struct nfs4_fs_location {
+	unsigned int nservers;
+	struct nfs4_string servers[NFS4_FS_LOCATION_MAXSERVERS];
+	struct nfs4_pathname rootpath;
+};
+
+#define NFS4_FS_LOCATIONS_MAXENTRIES 10
+struct nfs4_fs_locations {
+	struct nfs_fattr fattr;
+	const struct nfs_server *server;
+	struct nfs4_pathname fs_path;
+	int nlocations;
+	struct nfs4_fs_location locations[NFS4_FS_LOCATIONS_MAXENTRIES];
+};
+
+struct nfs4_fs_locations_arg {
+	const struct nfs_fh *dir_fh;
+	const struct qstr *name;
+	struct page *page;
+	const u32 *bitmask;
+};
+
 #endif /* CONFIG_NFS_V4 */
 
 struct nfs_page;
@@ -695,7 +734,7 @@
 #ifdef CONFIG_NFS_V4
 	unsigned long		timestamp;	/* For lease renewal */
 #endif
-	struct page		*page_array[NFS_PAGEVEC_SIZE + 1];
+	struct page		*page_array[NFS_PAGEVEC_SIZE];
 };
 
 struct nfs_write_data {
@@ -713,7 +752,7 @@
 #ifdef CONFIG_NFS_V4
 	unsigned long		timestamp;	/* For lease renewal */
 #endif
-	struct page		*page_array[NFS_PAGEVEC_SIZE + 1];
+	struct page		*page_array[NFS_PAGEVEC_SIZE];
 };
 
 struct nfs_access_entry;
diff --git a/include/linux/parport.h b/include/linux/parport.h
index d42737e..5bf321e 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -127,6 +127,10 @@
        unsigned char statusdir;/* ciab.ddrb & 7 */
 };
 
+struct ax88796_parport_state {
+	unsigned char cpr;
+};
+
 struct ip32_parport_state {
 	unsigned int dcr;
 	unsigned int ecr;
@@ -138,6 +142,7 @@
 		/* ARC has no state. */
 		struct ax_parport_state ax;
 		struct amiga_parport_state amiga;
+		struct ax88796_parport_state ax88796;
 		/* Atari has not state. */
 		struct ip32_parport_state ip32;
 		void *misc; 
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index ecce591..2ed807d 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -230,4 +230,8 @@
 extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
 extern unsigned int pmu_power_flags;
 
+/* Backlight */
+extern int disable_kernel_backlight;
+extern void pmu_backlight_init(struct device_node*);
+
 #endif	/* __KERNEL__ */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 5810d28..17e7578 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -99,9 +99,8 @@
 
 struct mm_struct;
 
+void proc_flush_task(struct task_struct *task);
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *);
-struct dentry *proc_pid_unhash(struct task_struct *p);
-void proc_pid_flush(struct dentry *proc_dentry);
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
 unsigned long task_vsize(struct mm_struct *);
 int task_statm(struct mm_struct *, int *, int *, int *, int *);
@@ -211,8 +210,7 @@
 #define proc_net_create(name, mode, info)	({ (void)(mode), NULL; })
 static inline void proc_net_remove(const char *name) {}
 
-static inline struct dentry *proc_pid_unhash(struct task_struct *p) { return NULL; }
-static inline void proc_pid_flush(struct dentry *proc_dentry) { }
+static inline void proc_flush_task(struct task_struct *task) { }
 
 static inline struct proc_dir_entry *create_proc_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *parent) { return NULL; }
@@ -248,8 +246,8 @@
 #endif
 
 struct proc_inode {
-	struct task_struct *task;
-	int type;
+	struct pid *pid;
+	int fd;
 	union {
 		int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
 		int (*proc_read)(struct task_struct *task, char *page);
@@ -268,4 +266,10 @@
 	return PROC_I(inode)->pde;
 }
 
+struct proc_maps_private {
+	struct pid *pid;
+	struct task_struct *task;
+	struct vm_area_struct *tail_vma;
+};
+
 #endif /* _LINUX_PROC_FS_H */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index ee918bc..8b2749a 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -88,7 +88,6 @@
 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
 extern int ptrace_attach(struct task_struct *tsk);
 extern int ptrace_detach(struct task_struct *, unsigned int);
-extern void __ptrace_detach(struct task_struct *, unsigned int);
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index 8994378..63df898 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -140,6 +140,7 @@
 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_WRITE_ERROR = 0x004, /* A write error has occurred */
 	BITMAP_HOSTENDIAN = 0x8000,
 };
 
@@ -244,15 +245,9 @@
 	unsigned long daemon_lastrun; /* jiffies of last run */
 	unsigned long daemon_sleep; /* how many seconds between updates? */
 
-	/*
-	 * bitmap_writeback_daemon waits for file-pages that have been written,
-	 * as there is no way to get a call-back when a page write completes.
-	 */
-	mdk_thread_t *writeback_daemon;
-	spinlock_t write_lock;
+	atomic_t pending_writes; /* pending writes to the bitmap file */
 	wait_queue_head_t write_wait;
-	struct list_head complete_pages;
-	mempool_t *write_pool;
+
 };
 
 /* the bitmap API */
diff --git a/include/linux/raid/linear.h b/include/linux/raid/linear.h
index 7eaf290..ba15469 100644
--- a/include/linux/raid/linear.h
+++ b/include/linux/raid/linear.h
@@ -13,8 +13,10 @@
 
 struct linear_private_data
 {
+	struct linear_private_data *prev;	/* earlier version */
 	dev_info_t		**hash_table;
 	sector_t		hash_spacing;
+	sector_t		array_size;
 	int			preshift; /* shift before dividing by hash_spacing */
 	dev_info_t		disks[0];
 };
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index 66b44e5..eb3e547 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -85,8 +85,6 @@
 extern void md_error (mddev_t *mddev, mdk_rdev_t *rdev);
 extern void md_unplug_mddev(mddev_t *mddev);
 
-extern void md_print_devices (void);
-
 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);
@@ -97,7 +95,5 @@
 
 extern void md_update_sb(mddev_t * mddev);
 
-#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
-
 #endif 
 
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index e2df61f..c1e0ac5 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -40,7 +40,8 @@
  * options passed in raidrun:
  */
 
-#define MAX_CHUNK_SIZE (4096*1024)
+/* Currently this must fix in an 'int' */
+#define MAX_CHUNK_SIZE (1<<30)
 
 /*
  * MD's 'extended' device
@@ -57,6 +58,7 @@
 
 	struct page	*sb_page;
 	int		sb_loaded;
+	__u64		sb_events;
 	sector_t	data_offset;	/* start of data in array */
 	sector_t	sb_offset;
 	int		sb_size;	/* bytes in the superblock */
@@ -87,6 +89,10 @@
 					 * array and could again if we did a partial
 					 * resync from the bitmap
 					 */
+	sector_t	recovery_offset;/* If this device has been partially
+					 * recovered, this is where we were
+					 * up to.
+					 */
 
 	atomic_t	nr_pending;	/* number of pending requests.
 					 * only maintained for arrays that
@@ -182,6 +188,8 @@
 #define	MD_RECOVERY_REQUESTED	6
 #define	MD_RECOVERY_CHECK	7
 #define MD_RECOVERY_RESHAPE	8
+#define	MD_RECOVERY_FROZEN	9
+
 	unsigned long			recovery;
 
 	int				in_sync;	/* know to not need resync */
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index f1fbae7..b6ebc69b 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -265,9 +265,12 @@
 
 /* feature_map bits */
 #define MD_FEATURE_BITMAP_OFFSET	1
+#define	MD_FEATURE_RECOVERY_OFFSET	2 /* recovery_offset is present and
+					   * must be honoured
+					   */
 #define	MD_FEATURE_RESHAPE_ACTIVE	4
 
-#define	MD_FEATURE_ALL			5
+#define	MD_FEATURE_ALL			(1|2|4)
 
 #endif 
 
diff --git a/include/linux/raid/raid10.h b/include/linux/raid/raid10.h
index b110329..c41e56a 100644
--- a/include/linux/raid/raid10.h
+++ b/include/linux/raid/raid10.h
@@ -24,11 +24,16 @@
 	int 			far_copies;   /* number of copies layed out
 					       * at large strides across drives
 					       */
+	int			far_offset;   /* far_copies are offset by 1 stripe
+					       * instead of many
+					       */
 	int			copies;	      /* near_copies * far_copies.
 					       * must be <= raid_disks
 					       */
 	sector_t		stride;	      /* distance between far copies.
-					       * This is size / far_copies
+					       * This is size / far_copies unless
+					       * far_offset, in which case it is
+					       * 1 stripe.
 					       */
 
 	int chunk_shift; /* shift from chunks to sectors */
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index 914af66..20ed4c9 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -212,6 +212,7 @@
 	mddev_t			*mddev;
 	struct disk_info	*spare;
 	int			chunk_size, level, algorithm;
+	int			max_degraded;
 	int			raid_disks, working_disks, failed_disks;
 	int			max_nr_stripes;
 
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 015297f..1dd1c70 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -59,13 +59,13 @@
  * Architecture independent implemenations of sys_reboot commands.
  */
 
-extern void kernel_restart_prepare(char *cmd);
 extern void kernel_shutdown_prepare(enum system_states state);
 
 extern void kernel_restart(char *cmd);
 extern void kernel_halt(void);
 extern void kernel_power_off(void);
-extern void kernel_kexec(void);
+
+void ctrl_alt_del(void);
 
 /*
  * Emergency restart, callable from an interrupt handler.
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 21a86cb..ae13db7 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -3,6 +3,8 @@
 
 #include <linux/time.h>
 
+struct task_struct;
+
 /*
  * Resource control/accounting header file for linux
  */
@@ -67,4 +69,6 @@
  */
 #include <asm/resource.h>
 
+int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
+
 #endif
diff --git a/include/linux/rtc-v3020.h b/include/linux/rtc-v3020.h
new file mode 100644
index 0000000..bf74e63
--- /dev/null
+++ b/include/linux/rtc-v3020.h
@@ -0,0 +1,35 @@
+/*
+ * v3020.h - Registers definition and platform data structure for the v3020 RTC.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006, 8D Technologies inc.
+ */
+#ifndef __LINUX_V3020_H
+#define __LINUX_V3020_H
+
+/* The v3020 has only one data pin but which one
+ * is used depends on the board. */
+struct v3020_platform_data {
+	int leftshift; /* (1<<(leftshift)) & readl() */
+};
+
+#define V3020_STATUS_0	0x00
+#define V3020_STATUS_1	0x01
+#define V3020_SECONDS	0x02
+#define V3020_MINUTES	0x03
+#define V3020_HOURS		0x04
+#define V3020_MONTH_DAY	0x05
+#define V3020_MONTH		0x06
+#define V3020_YEAR		0x07
+#define V3020_WEEK_DAY	0x08
+#define V3020_WEEK		0x09
+
+#define V3020_IS_COMMAND(val) ((val)>=0x0E)
+
+#define V3020_CMD_RAM2CLOCK	0x0E
+#define V3020_CMD_CLOCK2RAM	0x0F
+
+#endif /* __LINUX_V3020_H */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index ab61cd11..36e2bf4 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -102,6 +102,7 @@
 #include <linux/interrupt.h>
 
 extern int rtc_month_days(unsigned int month, unsigned int year);
+extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
 extern int rtc_valid_tm(struct rtc_time *tm);
 extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
 extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
@@ -155,6 +156,17 @@
 	struct rtc_task *irq_task;
 	spinlock_t irq_task_lock;
 	int irq_freq;
+	int max_user_freq;
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+	struct work_struct uie_task;
+	struct timer_list uie_timer;
+	/* Those fields are protected by rtc->irq_lock */
+	unsigned int oldsecs;
+	unsigned int irq_active:1;
+	unsigned int stop_uie_polling:1;
+	unsigned int uie_task_active:1;
+	unsigned int uie_timer_active:1;
+#endif
 };
 #define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 38b4791e..122a25c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -358,6 +358,14 @@
 	spinlock_t		siglock;
 };
 
+struct pacct_struct {
+	int			ac_flag;
+	long			ac_exitcode;
+	unsigned long		ac_mem;
+	cputime_t		ac_utime, ac_stime;
+	unsigned long		ac_minflt, ac_majflt;
+};
+
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
@@ -449,6 +457,9 @@
 	struct key *session_keyring;	/* keyring inherited over fork */
 	struct key *process_keyring;	/* keyring private to this process */
 #endif
+#ifdef CONFIG_BSD_PROCESS_ACCT
+	struct pacct_struct pacct;	/* per-process accounting information */
+#endif
 };
 
 /* Context switch must be unlocked if interrupts are to be enabled */
@@ -831,8 +842,6 @@
    	u32 self_exec_id;
 /* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
 	spinlock_t alloc_lock;
-/* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
-	spinlock_t proc_lock;
 
 #ifdef CONFIG_DEBUG_MUTEXES
 	/* mutex deadlock detection */
@@ -845,7 +854,6 @@
 /* VM state */
 	struct reclaim_state *reclaim_state;
 
-	struct dentry *proc_dentry;
 	struct backing_dev_info *backing_dev_info;
 
 	struct io_context *io_context;
diff --git a/include/linux/security.h b/include/linux/security.h
index d2c17bd..5180580 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -862,6 +862,7 @@
  *	Permit allocation of a key and assign security data. Note that key does
  *	not have a serial number assigned at this point.
  *	@key points to the key.
+ *	@flags is the allocation flags
  *	Return 0 if permission is granted, -ve error otherwise.
  * @key_free:
  *	Notification of destruction; free security data.
@@ -1324,7 +1325,7 @@
 
 	/* key management security hooks */
 #ifdef CONFIG_KEYS
-	int (*key_alloc)(struct key *key, struct task_struct *tsk);
+	int (*key_alloc)(struct key *key, struct task_struct *tsk, unsigned long flags);
 	void (*key_free)(struct key *key);
 	int (*key_permission)(key_ref_t key_ref,
 			      struct task_struct *context,
@@ -3040,9 +3041,10 @@
 #ifdef CONFIG_KEYS
 #ifdef CONFIG_SECURITY
 static inline int security_key_alloc(struct key *key,
-				     struct task_struct *tsk)
+				     struct task_struct *tsk,
+				     unsigned long flags)
 {
-	return security_ops->key_alloc(key, tsk);
+	return security_ops->key_alloc(key, tsk, flags);
 }
 
 static inline void security_key_free(struct key *key)
@@ -3060,7 +3062,8 @@
 #else
 
 static inline int security_key_alloc(struct key *key,
-				     struct task_struct *tsk)
+				     struct task_struct *tsk,
+				     unsigned long flags)
 {
 	return 0;
 }
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index 9b8bcf1..6e112cc 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -126,7 +126,7 @@
 /* Just increments the mechanism's reference count and returns its input: */
 struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
 
-/* For every succesful gss_mech_get or gss_mech_get_by_* call there must be a
+/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
  * corresponding call to gss_mech_put. */
 void gss_mech_put(struct gss_api_mech *);
 
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 84c35d4..e6d3d34 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -194,6 +194,7 @@
 extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
 extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
+extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index e82cb10..96e31aa 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -71,7 +71,6 @@
 void __save_processor_state(struct saved_context *ctxt);
 void __restore_processor_state(struct saved_context *ctxt);
 unsigned long get_safe_page(gfp_t gfp_mask);
-int swsusp_add_arch_pages(unsigned long start, unsigned long end);
 
 /*
  * XXX: We try to keep some more pages free so that I/O operations succeed
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 2993302..0577f52 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -1,7 +1,7 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.11 2006/02/06 21:20:29 paulkf Exp $
+ * $Id: synclink.h,v 3.13 2006/05/23 18:25:06 paulkf Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
  *
@@ -97,6 +97,8 @@
 #define HDLC_TXIDLE_ALT_MARK_SPACE	4
 #define HDLC_TXIDLE_SPACE		5
 #define HDLC_TXIDLE_MARK		6
+#define HDLC_TXIDLE_CUSTOM_8            0x10000000
+#define HDLC_TXIDLE_CUSTOM_16           0x20000000
 
 #define HDLC_ENCODING_NRZ			0
 #define HDLC_ENCODING_NRZB			1
@@ -170,6 +172,7 @@
 #define SYNCLINK_GT_DEVICE_ID 0x0070
 #define SYNCLINK_GT4_DEVICE_ID 0x0080
 #define SYNCLINK_AC_DEVICE_ID  0x0090
+#define SYNCLINK_GT2_DEVICE_ID 0x00A0
 #define MGSL_MAX_SERIAL_NUMBER 30
 
 /*
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index c713202..349ef90 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -55,7 +55,7 @@
 	CTL_KERN=1,		/* General kernel info and control */
 	CTL_VM=2,		/* VM management */
 	CTL_NET=3,		/* Networking */
-	CTL_PROC=4,		/* Process info */
+	/* was CTL_PROC */
 	CTL_FS=5,		/* Filesystems */
 	CTL_DEBUG=6,		/* Debugging */
 	CTL_DEV=7,		/* Devices */
@@ -148,9 +148,11 @@
 	KERN_SPIN_RETRY=70,	/* int: number of spinlock retries */
 	KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */
 	KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
+	KERN_COMPAT_LOG=73,	/* int: print compat layer  messages */
 };
 
 
+
 /* CTL_VM names: */
 enum
 {
@@ -767,8 +769,6 @@
 	NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
 };
 
-/* CTL_PROC names: */
-
 /* CTL_FS names: */
 enum
 {
diff --git a/include/linux/time.h b/include/linux/time.h
index 0cd696c..c05f8bb 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -28,10 +28,13 @@
 #ifdef __KERNEL__
 
 /* Parameters used to convert the timespec values: */
-#define MSEC_PER_SEC		1000L
-#define USEC_PER_SEC		1000000L
-#define NSEC_PER_SEC		1000000000L
-#define NSEC_PER_USEC		1000L
+#define MSEC_PER_SEC	1000L
+#define USEC_PER_MSEC	1000L
+#define NSEC_PER_USEC	1000L
+#define NSEC_PER_MSEC	1000000L
+#define USEC_PER_SEC	1000000L
+#define NSEC_PER_SEC	1000000000L
+#define FSEC_PER_SEC	1000000000000000L
 
 static inline int timespec_equal(struct timespec *a, struct timespec *b)
 {
@@ -77,6 +80,8 @@
 extern struct timespec wall_to_monotonic;
 extern seqlock_t xtime_lock;
 
+void timekeeping_init(void);
+
 static inline unsigned long get_seconds(void)
 {
 	return xtime.tv_sec;
@@ -100,6 +105,7 @@
 extern void getnstimeofday(struct timespec *tv);
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
+extern int timekeeping_is_continuous(void);
 
 /**
  * timespec_to_ns - Convert timespec to nanoseconds
@@ -142,6 +148,20 @@
  */
 extern struct timeval ns_to_timeval(const s64 nsec);
 
+/**
+ * timespec_add_ns - Adds nanoseconds to a timespec
+ * @a:		pointer to timespec to be incremented
+ * @ns:		unsigned nanoseconds value to be added
+ */
+static inline void timespec_add_ns(struct timespec *a, u64 ns)
+{
+	ns += a->tv_nsec;
+	while(unlikely(ns >= NSEC_PER_SEC)) {
+		ns -= NSEC_PER_SEC;
+		a->tv_sec++;
+	}
+	a->tv_nsec = ns;
+}
 #endif /* __KERNEL__ */
 
 #define NFDBITS			__NFDBITS
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 34d3ccf..19bb653 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -303,6 +303,8 @@
 
 #endif /* !CONFIG_TIME_INTERPOLATION */
 
+#define TICK_LENGTH_SHIFT	32
+
 /* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
 extern u64 current_tick_length(void);
 
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 86b5b42..914f911 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -220,6 +220,19 @@
  */
 #define UFS_MINFREE         5
 #define UFS_DEFAULTOPT      UFS_OPTTIME
+
+/*
+ * Debug code
+ */
+#ifdef CONFIG_UFS_DEBUG
+#	define UFSD(f, a...)	{					\
+		printk ("UFSD (%s, %d): %s:",				\
+			__FILE__, __LINE__, __FUNCTION__);		\
+		printk (f, ## a);					\
+	}
+#else
+#	define UFSD(f, a...)	/**/
+#endif
             
 /*
  * Turn file system block numbers into disk block addresses.
@@ -339,7 +352,22 @@
 };
 
 /*
+ * File system flags
+ */
+#define UFS_UNCLEAN      0x01    /* file system not clean at mount (unused) */
+#define UFS_DOSOFTDEP    0x02    /* file system using soft dependencies */
+#define UFS_NEEDSFSCK    0x04    /* needs sync fsck (FreeBSD compat, unused) */
+#define UFS_INDEXDIRS    0x08    /* kernel supports indexed directories */
+#define UFS_ACLS         0x10    /* file system has ACLs enabled */
+#define UFS_MULTILABEL   0x20    /* file system is MAC multi-label */
+#define UFS_FLAGS_UPDATED 0x80   /* flags have been moved to new location */
+
+#if 0
+/*
  * This is the actual superblock, as it is laid out on the disk.
+ * Do NOT use this structure, because of sizeof(ufs_super_block) > 512 and
+ * it may occupy several blocks, use
+ * struct ufs_super_block_(first,second,third) instead.
  */
 struct ufs_super_block {
 	__fs32	fs_link;	/* UNUSED */
@@ -416,7 +444,7 @@
 	__s8	fs_fmod;	/* super block modified flag */
 	__s8	fs_clean;	/* file system is clean flag */
 	__s8	fs_ronly;	/* mounted read-only flag */
-	__s8	fs_flags;	/* currently unused flag */
+	__s8	fs_flags;
 	union {
 		struct {
 			__s8	fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */
@@ -485,6 +513,7 @@
 	__fs32	fs_magic;		/* magic number */
 	__u8	fs_space[1];		/* list of blocks for each rotation */
 };
+#endif/*struct ufs_super_block*/
 
 /*
  * Preference for optimization.
@@ -666,7 +695,7 @@
 };
 
 struct ufs_cg_private_info {
-	struct ufs_cylinder_group ucg;
+	struct ufs_buffer_head c_ubh;
 	__u32	c_cgx;		/* number of cylidner group */
 	__u16	c_ncyl;		/* number of cyl's this cg */
 	__u16	c_niblk;	/* number of inode blocks this cg */
@@ -686,6 +715,7 @@
 
 struct ufs_sb_private_info {
 	struct ufs_buffer_head s_ubh; /* buffer containing super block */
+	struct ufs2_csum_total cs_total;
 	__u32	s_sblkno;	/* offset of super-blocks in filesys */
 	__u32	s_cblkno;	/* offset of cg-block in filesys */
 	__u32	s_iblkno;	/* offset of inode-blocks in filesys */
@@ -824,16 +854,54 @@
 };
 
 struct ufs_super_block_second {
-	__s8	fs_fsmnt[212];
-	__fs32	fs_cgrotor;
-	__fs32	fs_csp[UFS_MAXCSBUFS];
-	__fs32	fs_maxcluster;
-	__fs32	fs_cpc;
-	__fs16	fs_opostbl[82];
-};	
+	union {
+		struct {
+			__s8	fs_fsmnt[212];
+			__fs32	fs_cgrotor;
+			__fs32	fs_csp[UFS_MAXCSBUFS];
+			__fs32	fs_maxcluster;
+			__fs32	fs_cpc;
+			__fs16	fs_opostbl[82];
+		} fs_u1;
+		struct {
+			__s8  fs_fsmnt[UFS2_MAXMNTLEN - UFS_MAXMNTLEN + 212];
+			__u8   fs_volname[UFS2_MAXVOLLEN];
+			__fs64  fs_swuid;
+			__fs32  fs_pad;
+			__fs32   fs_cgrotor;
+			__fs32   fs_ocsp[UFS2_NOCSPTRS];
+			__fs32   fs_contigdirs;
+			__fs32   fs_csp;
+			__fs32   fs_maxcluster;
+			__fs32   fs_active;
+			__fs32   fs_old_cpc;
+			__fs32   fs_maxbsize;
+			__fs64   fs_sparecon64[17];
+			__fs64   fs_sblockloc;
+			__fs64	cs_ndir;
+			__fs64	cs_nbfree;
+		} fs_u2;
+	} fs_un;
+};
 
 struct ufs_super_block_third {
-	__fs16	fs_opostbl[46];
+	union {
+		struct {
+			__fs16	fs_opostbl[46];
+		} fs_u1;
+		struct {
+			__fs64	cs_nifree;	/* number of free inodes */
+			__fs64	cs_nffree;	/* number of free frags */
+			__fs64   cs_numclusters;	/* number of free clusters */
+			__fs64   cs_spare[3];	/* future expansion */
+			struct  ufs_timeval    fs_time;		/* last time written */
+			__fs64    fs_size;		/* number of blocks in fs */
+			__fs64    fs_dsize;	/* number of data blocks in fs */
+			__fs64   fs_csaddr;	/* blk addr of cyl grp summary area */
+			__fs64    fs_pendingblocks;/* blocks in process of being freed */
+			__fs32    fs_pendinginodes;/*inodes in process of being freed */
+		} fs_u2;
+	} fs_un1;
 	union {
 		struct {
 			__fs32	fs_sparecon[53];/* reserved for future constants */
@@ -861,7 +929,7 @@
 			__fs32	fs_qfmask[2];	/* ~usb_fmask */
 			__fs32	fs_state;	/* file system state time stamp */
 		} fs_44;
-	} fs_u2;
+	} fs_un2;
 	__fs32	fs_postblformat;
 	__fs32	fs_nrpos;
 	__fs32	fs_postbloff;
@@ -875,7 +943,8 @@
 /* balloc.c */
 extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
 extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
-extern unsigned ufs_new_fragments (struct inode *, __fs32 *, unsigned, unsigned, unsigned, int *);
+extern unsigned ufs_new_fragments(struct inode *, __fs32 *, unsigned, unsigned,
+				  unsigned, int *, struct page *);
 
 /* cylinder.c */
 extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
@@ -886,11 +955,12 @@
 extern int ufs_add_link (struct dentry *, struct inode *);
 extern ino_t ufs_inode_by_name(struct inode *, struct dentry *);
 extern int ufs_make_empty(struct inode *, struct inode *);
-extern struct ufs_dir_entry * ufs_find_entry (struct dentry *, struct buffer_head **);
-extern int ufs_delete_entry (struct inode *, struct ufs_dir_entry *, struct buffer_head *);
+extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **);
+extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
 extern int ufs_empty_dir (struct inode *);
-extern struct ufs_dir_entry * ufs_dotdot (struct inode *, struct buffer_head **);
-extern void ufs_set_link(struct inode *, struct ufs_dir_entry *, struct buffer_head *, struct inode *);
+extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);
+extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
+			 struct page *page, struct inode *inode);
 
 /* file.c */
 extern struct inode_operations ufs_file_inode_operations;
@@ -903,13 +973,11 @@
 extern struct inode * ufs_new_inode (struct inode *, int);
 
 /* inode.c */
-extern u64  ufs_frag_map (struct inode *, sector_t);
 extern void ufs_read_inode (struct inode *);
 extern void ufs_put_inode (struct inode *);
 extern int ufs_write_inode (struct inode *, int);
 extern int ufs_sync_inode (struct inode *);
 extern void ufs_delete_inode (struct inode *);
-extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
 extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
 extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
 
diff --git a/include/linux/ufs_fs_i.h b/include/linux/ufs_fs_i.h
index 21665a9..f50ce3b 100644
--- a/include/linux/ufs_fs_i.h
+++ b/include/linux/ufs_fs_i.h
@@ -27,6 +27,7 @@
 	__u32	i_oeftflag;
 	__u16	i_osync;
 	__u32	i_lastfrag;
+	__u32   i_dir_start_lookup;
 	struct inode vfs_inode;
 };
 
diff --git a/include/linux/unwind.h b/include/linux/unwind.h
new file mode 100644
index 0000000..ce48e2c
--- /dev/null
+++ b/include/linux/unwind.h
@@ -0,0 +1,127 @@
+#ifndef _LINUX_UNWIND_H
+#define _LINUX_UNWIND_H
+
+/*
+ * Copyright (C) 2002-2006 Novell, Inc.
+ *	Jan Beulich <jbeulich@novell.com>
+ * This code is released under version 2 of the GNU GPL.
+ *
+ * A simple API for unwinding kernel stacks.  This is used for
+ * debugging and error reporting purposes.  The kernel doesn't need
+ * full-blown stack unwinding with all the bells and whistles, so there
+ * is not much point in implementing the full Dwarf2 unwind API.
+ */
+
+#include <linux/config.h>
+
+struct module;
+
+#ifdef CONFIG_STACK_UNWIND
+
+#include <asm/unwind.h>
+
+#ifndef ARCH_UNWIND_SECTION_NAME
+#define ARCH_UNWIND_SECTION_NAME ".eh_frame"
+#endif
+
+/*
+ * Initialize unwind support.
+ */
+extern void unwind_init(void);
+
+#ifdef CONFIG_MODULES
+
+extern void *unwind_add_table(struct module *,
+                              const void *table_start,
+                              unsigned long table_size);
+
+extern void unwind_remove_table(void *handle, int init_only);
+
+#endif
+
+extern int unwind_init_frame_info(struct unwind_frame_info *,
+                                  struct task_struct *,
+                                  /*const*/ struct pt_regs *);
+
+/*
+ * Prepare to unwind a blocked task.
+ */
+extern int unwind_init_blocked(struct unwind_frame_info *,
+                               struct task_struct *);
+
+/*
+ * Prepare to unwind the currently running thread.
+ */
+extern int unwind_init_running(struct unwind_frame_info *,
+                               asmlinkage int (*callback)(struct unwind_frame_info *,
+                                                          void *arg),
+                               void *arg);
+
+/*
+ * Unwind to previous to frame.  Returns 0 if successful, negative
+ * number in case of an error.
+ */
+extern int unwind(struct unwind_frame_info *);
+
+/*
+ * Unwind until the return pointer is in user-land (or until an error
+ * occurs).  Returns 0 if successful, negative number in case of
+ * error.
+ */
+extern int unwind_to_user(struct unwind_frame_info *);
+
+#else
+
+struct unwind_frame_info {};
+
+static inline void unwind_init(void) {}
+
+#ifdef CONFIG_MODULES
+
+static inline void *unwind_add_table(struct module *mod,
+                                     const void *table_start,
+                                     unsigned long table_size)
+{
+	return NULL;
+}
+
+#endif
+
+static inline void unwind_remove_table(void *handle, int init_only)
+{
+}
+
+static inline int unwind_init_frame_info(struct unwind_frame_info *info,
+                                         struct task_struct *tsk,
+                                         const struct pt_regs *regs)
+{
+	return -ENOSYS;
+}
+
+static inline int unwind_init_blocked(struct unwind_frame_info *info,
+                                      struct task_struct *tsk)
+{
+	return -ENOSYS;
+}
+
+static inline int unwind_init_running(struct unwind_frame_info *info,
+                                      asmlinkage int (*cb)(struct unwind_frame_info *,
+                                                           void *arg),
+                                      void *arg)
+{
+	return -ENOSYS;
+}
+
+static inline int unwind(struct unwind_frame_info *info)
+{
+	return -ENOSYS;
+}
+
+static inline int unwind_to_user(struct unwind_frame_info *info)
+{
+	return -ENOSYS;
+}
+
+#endif
+
+#endif /* _LINUX_UNWIND_H */
diff --git a/include/linux/videodev.h b/include/linux/videodev.h
index 9114009..41bc7e9 100644
--- a/include/linux/videodev.h
+++ b/include/linux/videodev.h
@@ -1,49 +1,21 @@
+/*
+ *	Video for Linux version 1 - OBSOLETE
+ *
+ *	Header file for v4l1 drivers and applications, for
+ *	Linux kernels 2.2.x or 2.4.x.
+ *
+ *	Provides header for legacy drivers and applications
+ *
+ *	See http://linuxtv.org for more info
+ *
+ */
 #ifndef __LINUX_VIDEODEV_H
 #define __LINUX_VIDEODEV_H
 
-#include <linux/types.h>
-
 #define HAVE_V4L1 1
 
 #include <linux/videodev2.h>
 
-#ifdef __KERNEL__
-
-#include <linux/mm.h>
-
-extern struct video_device* video_devdata(struct file*);
-
-#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
-static inline void
-video_device_create_file(struct video_device *vfd,
-			 struct class_device_attribute *attr)
-{
-	class_device_create_file(&vfd->class_dev, attr);
-}
-static inline void
-video_device_remove_file(struct video_device *vfd,
-			 struct class_device_attribute *attr)
-{
-	class_device_remove_file(&vfd->class_dev, attr);
-}
-
-#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)
-{
-	return dev->priv;
-}
-
-static inline void video_set_drvdata(struct video_device *dev, void *data)
-{
-	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);
-#endif /* __KERNEL__ */
-
 struct video_capability
 {
 	char name[32];
@@ -363,6 +335,7 @@
 #define VID_HARDWARE_SAA7114H   37
 #define VID_HARDWARE_SN9C102	38
 #define VID_HARDWARE_ARV	39
+
 #endif /* __LINUX_VIDEODEV_H */
 
 /*
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index ad7fa9c..a62673d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1,35 +1,33 @@
-#ifndef __LINUX_VIDEODEV2_H
-#define __LINUX_VIDEODEV2_H
 /*
  *	Video for Linux Two
  *
- *	Header file for v4l or V4L2 drivers and applications, for
- *	Linux kernels 2.2.x or 2.4.x.
+ *	Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
  *
- *	See http://bytesex.org/v4l/ for API specs and other
- *	v4l2 documentation.
+ *	See http://linuxtv.org for more info
  *
  *	Author: Bill Dirks <bdirks@pacbell.net>
  *		Justin Schoeman
  *		et al.
  */
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
 #ifdef __KERNEL__
-#include <linux/time.h> /* need struct timeval */
-#include <linux/poll.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#endif
+#include <linux/time.h>     /* need struct timeval */
 #include <linux/compiler.h> /* need __user */
+#else
+#define __user
+#endif
+#include <linux/types.h>
 
-
-#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.17 */
 #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 */
@@ -47,71 +45,6 @@
 #define VID_TYPE_MJPEG_DECODER	4096	/* Can decode MJPEG streams */
 #define VID_TYPE_MJPEG_ENCODER	8192	/* Can encode MJPEG streams */
 
-#ifdef __KERNEL__
-
-/* Minor device allocation */
-#define MINOR_VFL_TYPE_GRABBER_MIN   0
-#define MINOR_VFL_TYPE_GRABBER_MAX  63
-#define MINOR_VFL_TYPE_RADIO_MIN    64
-#define MINOR_VFL_TYPE_RADIO_MAX   127
-#define MINOR_VFL_TYPE_VTX_MIN     192
-#define MINOR_VFL_TYPE_VTX_MAX     223
-#define MINOR_VFL_TYPE_VBI_MIN     224
-#define MINOR_VFL_TYPE_VBI_MAX     255
-
-#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 */
-	const 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 mutex 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
  */
@@ -172,6 +105,8 @@
 	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
 	V4L2_CTRL_TYPE_MENU	     = 3,
 	V4L2_CTRL_TYPE_BUTTON	     = 4,
+	V4L2_CTRL_TYPE_INTEGER64     = 5,
+	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
 };
 
 enum v4l2_tuner_type {
@@ -270,7 +205,6 @@
 /*
  *	V I D E O   I M A G E   F O R M A T
  */
-
 struct v4l2_pix_format
 {
 	__u32         		width;
@@ -283,7 +217,7 @@
 	__u32			priv;		/* private data, depends on pixelformat */
 };
 
-/*           Pixel format    FOURCC                  depth  Description   */
+/*      Pixel format         FOURCC                        depth  Description  */
 #define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R','G','B','1') /*  8  RGB-3-3-2     */
 #define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R','G','B','O') /* 16  RGB-5-5-5     */
 #define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R','G','B','P') /* 16  RGB-5-6-5     */
@@ -311,6 +245,7 @@
 #define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y','U','1','2') /* 12  YUV 4:2:0     */
 #define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y','Y','U','V') /* 16  YUV 4:2:2     */
 #define V4L2_PIX_FMT_HI240   v4l2_fourcc('H','I','2','4') /*  8  8-bit color   */
+#define V4L2_PIX_FMT_HM12    v4l2_fourcc('H','M','1','2') /*  8  YUV 4:1:1 16x16 macroblocks */
 
 /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /*  8  BGBG.. GRGR.. */
@@ -319,7 +254,7 @@
 #define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M','J','P','G') /* Motion-JPEG   */
 #define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J','P','E','G') /* JFIF JPEG     */
 #define V4L2_PIX_FMT_DV       v4l2_fourcc('d','v','s','d') /* 1394          */
-#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M','P','E','G') /* MPEG          */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M','P','E','G') /* MPEG-1/2/4    */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
@@ -343,7 +278,6 @@
 
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
 
-
 /*
  *	T I M E C O D E
  */
@@ -373,16 +307,15 @@
 #define V4L2_TC_USERBITS_8BITCHARS	0x0008
 /* The above is based on SMPTE timecodes */
 
-
+#ifdef __KERNEL__
 /*
  *	M P E G   C O M P R E S S I O N   P A R A M E T E R S
  *
- *  ### WARNING: this is still work-in-progress right now, most likely
- *  ###          there will be some incompatible changes.
+ *  ### WARNING: This experimental MPEG compression API is obsolete.
+ *  ###          It is replaced by the MPEG controls API.
+ *  ###          This old API will disappear in the near future!
  *
  */
-
-
 enum v4l2_bitrate_mode {
 	V4L2_BITRATE_NONE = 0,	/* not specified */
 	V4L2_BITRATE_CBR,	/* constant bitrate */
@@ -460,6 +393,7 @@
 	/* I don't expect the above being perfect yet ;) */
 	__u32				reserved_5[8];
 };
+#endif
 
 struct v4l2_jpegcompression
 {
@@ -491,7 +425,6 @@
 					* allways use APP0 */
 };
 
-
 /*
  *	M E M O R Y - M A P P I N G   B U F F E R S
  */
@@ -573,7 +506,6 @@
 	void			__user *bitmap;
 };
 
-
 /*
  *	C A P T U R E   P A R A M E T E R S
  */
@@ -586,6 +518,7 @@
 	__u32              readbuffers;   /*  # of buffers for read */
 	__u32		   reserved[4];
 };
+
 /*  Flags for 'capability' and 'capturemode' fields */
 #define V4L2_MODE_HIGHQUALITY	0x0001	/*  High quality imaging mode */
 #define V4L2_CAP_TIMEPERFRAME	0x1000	/*  timeperframe field is supported */
@@ -603,7 +536,6 @@
 /*
  *	I N P U T   I M A G E   C R O P P I N G
  */
-
 struct v4l2_cropcap {
 	enum v4l2_buf_type      type;
 	struct v4l2_rect        bounds;
@@ -710,7 +642,6 @@
 	__u32		     reserved[4];
 };
 
-
 /*
  *	V I D E O   I N P U T S
  */
@@ -725,6 +656,7 @@
 	__u32	     status;
 	__u32	     reserved[4];
 };
+
 /*  Values for the 'type' field */
 #define V4L2_INPUT_TYPE_TUNER		1
 #define V4L2_INPUT_TYPE_CAMERA		2
@@ -775,6 +707,34 @@
 	__s32		     value;
 };
 
+struct v4l2_ext_control
+{
+	__u32 id;
+	__u32 reserved2[2];
+	union {
+		__s32 value;
+		__s64 value64;
+		void *reserved;
+	};
+};
+
+struct v4l2_ext_controls
+{
+	__u32 ctrl_class;
+	__u32 count;
+	__u32 error_idx;
+	__u32 reserved[2];
+	struct v4l2_ext_control *controls;
+};
+
+/*  Values for ctrl_class field */
+#define V4L2_CTRL_CLASS_USER 0x00980000	/* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG 0x00990000	/* MPEG-compression controls */
+
+#define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
+#define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct v4l2_queryctrl
 {
@@ -801,12 +761,21 @@
 /*  Control flags  */
 #define V4L2_CTRL_FLAG_DISABLED		0x0001
 #define V4L2_CTRL_FLAG_GRABBED		0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY 	0x0004
+#define V4L2_CTRL_FLAG_UPDATE 		0x0008
+#define V4L2_CTRL_FLAG_INACTIVE 	0x0010
+#define V4L2_CTRL_FLAG_SLIDER 		0x0020
 
-/*  Control IDs defined by V4L2 */
-#define V4L2_CID_BASE			0x00980900
+/*  Query flag, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL	0x80000000
+
+/*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_BASE			(V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE 		V4L2_CID_BASE
 /*  IDs reserved for driver specific controls */
 #define V4L2_CID_PRIVATE_BASE		0x08000000
 
+#define V4L2_CID_USER_CLASS 		(V4L2_CTRL_CLASS_USER | 1)
 #define V4L2_CID_BRIGHTNESS		(V4L2_CID_BASE+0)
 #define V4L2_CID_CONTRAST		(V4L2_CID_BASE+1)
 #define V4L2_CID_SATURATION		(V4L2_CID_BASE+2)
@@ -833,6 +802,188 @@
 #define V4L2_CID_VCENTER		(V4L2_CID_BASE+23)
 #define V4L2_CID_LASTP1			(V4L2_CID_BASE+24) /* last CID + 1 */
 
+/*  MPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS 			(V4L2_CTRL_CLASS_MPEG | 1)
+
+/*  MPEG streams */
+#define V4L2_CID_MPEG_STREAM_TYPE 		(V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+	V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT 		(V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO 		(V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO 		(V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR 		(V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO 	(V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO 	(V4L2_CID_MPEG_BASE+6)
+#define V4L2_CID_MPEG_STREAM_VBI_FMT 		(V4L2_CID_MPEG_BASE+7)
+enum v4l2_mpeg_stream_vbi_fmt {
+	V4L2_MPEG_STREAM_VBI_FMT_NONE = 0,  /* No VBI in the MPEG stream */
+	V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
+};
+
+/*  MPEG audio */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ 	(V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING 		(V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE 		(V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+	V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
+	V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
+	V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+	V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+	V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+	V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+	V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+	V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+	V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+	V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+	V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+	V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+	V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE 		(V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+	V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
+	V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
+	V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
+	V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
+	V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
+	V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+	V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+	V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+	V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+	V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+	V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+	V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+	V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE 		(V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+	V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
+	V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
+	V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
+	V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
+	V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
+	V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
+	V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+	V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+	V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+	V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+	V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+	V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+	V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE 		(V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+	V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
+	V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+	V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
+	V4L2_MPEG_AUDIO_MODE_MONO         = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION 	(V4L2_CID_MPEG_BASE+106)
+enum v4l2_mpeg_audio_mode_extension {
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS 		(V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+	V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
+	V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+	V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC 		(V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+	V4L2_MPEG_AUDIO_CRC_NONE  = 0,
+	V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+
+/*  MPEG video */
+#define V4L2_CID_MPEG_VIDEO_ENCODING 		(V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT 		(V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+	V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
+	V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
+	V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
+	V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES 		(V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE 		(V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE 	(V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN 		(V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE 	(V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+	V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE 		(V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK 	(V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+
+/*  MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE 				(V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE 	(V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+	V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+	V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER 		(V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE 	(V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE 	(V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
+	V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE 	(V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+	V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+	V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER 		(V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE 		(V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM 	(V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM	(V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+10)
+
 /*
  *	T U N I N G
  */
@@ -904,6 +1055,7 @@
 	__u32	mode;
 	__u32	reserved[2];
 };
+
 /*  Flags for the 'capability' field */
 #define V4L2_AUDCAP_STEREO		0x00001
 #define V4L2_AUDCAP_AVL			0x00002
@@ -927,7 +1079,6 @@
  */
 
 /* Raw VBI */
-
 struct v4l2_vbi_format
 {
 	__u32	sampling_rate;		/* in 1 Hz */
@@ -1034,8 +1185,6 @@
 	} parm;
 };
 
-
-
 /*
  *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -1045,8 +1194,10 @@
 #define VIDIOC_ENUM_FMT         _IOWR ('V',  2, struct v4l2_fmtdesc)
 #define VIDIOC_G_FMT		_IOWR ('V',  4, struct v4l2_format)
 #define VIDIOC_S_FMT		_IOWR ('V',  5, struct v4l2_format)
+#ifdef __KERNEL__
 #define VIDIOC_G_MPEGCOMP       _IOR  ('V',  6, struct v4l2_mpeg_compression)
 #define VIDIOC_S_MPEGCOMP     	_IOW  ('V',  7, struct v4l2_mpeg_compression)
+#endif
 #define VIDIOC_REQBUFS		_IOWR ('V',  8, struct v4l2_requestbuffers)
 #define VIDIOC_QUERYBUF		_IOWR ('V',  9, struct v4l2_buffer)
 #define VIDIOC_G_FBUF		_IOR  ('V', 10, struct v4l2_framebuffer)
@@ -1096,7 +1247,11 @@
 #define VIDIOC_G_SLICED_VBI_CAP _IOR  ('V', 69, struct v4l2_sliced_vbi_cap)
 #endif
 #define VIDIOC_LOG_STATUS       _IO   ('V', 70)
+#define VIDIOC_G_EXT_CTRLS	_IOWR ('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS	_IOWR ('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS	_IOWR ('V', 73, struct v4l2_ext_controls)
 
+#ifdef __OLD_VIDIOC_
 /* for compatibility, will go away some day */
 #define VIDIOC_OVERLAY_OLD     	_IOWR ('V', 14, int)
 #define VIDIOC_S_PARM_OLD      	_IOW  ('V', 22, struct v4l2_streamparm)
@@ -1104,57 +1259,10 @@
 #define VIDIOC_G_AUDIO_OLD     	_IOWR ('V', 33, struct v4l2_audio)
 #define VIDIOC_G_AUDOUT_OLD    	_IOWR ('V', 49, struct v4l2_audioout)
 #define VIDIOC_CROPCAP_OLD     	_IOR  ('V', 58, struct v4l2_cropcap)
+#endif
 
 #define BASE_VIDIOC_PRIVATE	192		/* 192-255 are private */
 
-
-#ifdef __KERNEL__
-/*
- *
- *	V 4 L 2   D R I V E R   H E L P E R   A P I
- *
- *	Some commonly needed functions for drivers (v4l2-common.o module)
- */
-#include <linux/fs.h>
-
-/*  Video standard functions  */
-extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
-extern int v4l2_video_std_construct(struct v4l2_standard *vs,
-				    int id, char *name);
-
-/* prority handling */
-struct v4l2_prio_state {
-	atomic_t prios[4];
-};
-int v4l2_prio_init(struct v4l2_prio_state *global);
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
-		     enum v4l2_priority new);
-int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
-int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
-
-/* names for fancy debug output */
-extern char *v4l2_field_names[];
-extern char *v4l2_type_names[];
-
-/*  Compatibility layer interface  --  v4l1-compat module */
-typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
-			   unsigned int cmd, void *arg);
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
-			       int cmd, void *arg, v4l2_kioctl driver_ioctl);
-#else
-#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
-#endif
-
-/* 32 Bits compatibility layer for 64 bits processors */
-extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
-				unsigned long arg);
-
-
-#endif /* __KERNEL__ */
 #endif /* __LINUX_VIDEODEV2_H */
 
 /*
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
new file mode 100644
index 0000000..074c400
--- /dev/null
+++ b/include/media/cx2341x.h
@@ -0,0 +1,195 @@
+/*
+    cx23415/6 header containing common defines.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef CX2341X_H
+#define CX2341X_H
+
+enum cx2341x_port {
+	CX2341X_PORT_MEMORY    = 0,
+	CX2341X_PORT_STREAMING = 1,
+	CX2341X_PORT_SERIAL    = 2
+};
+
+enum cx2341x_cap {
+	CX2341X_CAP_HAS_SLICED_VBI = 1 << 0,
+};
+
+struct cx2341x_mpeg_params {
+	/* misc */
+	u32 capabilities;
+	enum cx2341x_port port;
+	u16 width;
+	u16 height;
+	u16 is_50hz;
+
+	/* stream */
+	enum v4l2_mpeg_stream_type stream_type;
+	enum v4l2_mpeg_stream_vbi_fmt stream_vbi_fmt;
+
+	/* audio */
+	enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
+	enum v4l2_mpeg_audio_encoding audio_encoding;
+	enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
+	enum v4l2_mpeg_audio_mode audio_mode;
+	enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
+	enum v4l2_mpeg_audio_emphasis audio_emphasis;
+	enum v4l2_mpeg_audio_crc audio_crc;
+	u8 audio_properties;
+
+	/* video */
+	enum v4l2_mpeg_video_encoding video_encoding;
+	enum v4l2_mpeg_video_aspect video_aspect;
+	u16 video_b_frames;
+	u16 video_gop_size;
+	u16 video_gop_closure;
+	u16 video_pulldown;
+	enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode;
+	u32 video_bitrate;
+	u32 video_bitrate_peak;
+	u16 video_temporal_decimation;
+
+	/* encoding filters */
+	enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
+	u16 video_spatial_filter;
+	enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type;
+	enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type;
+	enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode;
+	u16 video_temporal_filter;
+	enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type;
+	u16 video_luma_median_filter_top;
+	u16 video_luma_median_filter_bottom;
+	u16 video_chroma_median_filter_top;
+	u16 video_chroma_median_filter_bottom;
+};
+
+#define CX2341X_MBOX_MAX_DATA 16
+
+extern const u32 cx2341x_mpeg_ctrls[];
+typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out,
+		u32 data[CX2341X_MBOX_MAX_DATA]);
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+		const struct cx2341x_mpeg_params *old,
+		const struct cx2341x_mpeg_params *new);
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+		struct v4l2_queryctrl *qctrl);
+const char **cx2341x_ctrl_get_menu(u32 id);
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+		struct v4l2_ext_controls *ctrls, int cmd);
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int cardid);
+
+/* Firmware names */
+#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
+/* Decoder firmware for the cx23415 only */
+#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw"
+
+/* Firmware API commands */
+
+/* MPEG decoder API, specific to the cx23415 */
+#define CX2341X_DEC_PING_FW 			0x00
+#define CX2341X_DEC_START_PLAYBACK 		0x01
+#define CX2341X_DEC_STOP_PLAYBACK 		0x02
+#define CX2341X_DEC_SET_PLAYBACK_SPEED 		0x03
+#define CX2341X_DEC_STEP_VIDEO 			0x05
+#define CX2341X_DEC_SET_DMA_BLOCK_SIZE 		0x08
+#define CX2341X_DEC_GET_XFER_INFO		0x09
+#define CX2341X_DEC_GET_DMA_STATUS		0x0a
+#define CX2341X_DEC_SCHED_DMA_FROM_HOST		0x0b
+#define CX2341X_DEC_PAUSE_PLAYBACK 		0x0d
+#define CX2341X_DEC_HALT_FW 			0x0e
+#define CX2341X_DEC_SET_STANDARD 		0x10
+#define CX2341X_DEC_GET_VERSION			0x11
+#define CX2341X_DEC_SET_STREAM_INPUT 		0x14
+#define CX2341X_DEC_GET_TIMING_INFO 		0x15
+#define CX2341X_DEC_SET_AUDIO_MODE 		0x16
+#define CX2341X_DEC_SET_EVENT_NOTIFICATION	0x17
+#define CX2341X_DEC_SET_DISPLAY_BUFFERS		0x18
+#define CX2341X_DEC_EXTRACT_VBI 		0x19
+#define CX2341X_DEC_SET_DECODER_SOURCE 		0x1a
+#define CX2341X_DEC_SET_AUDIO_OUTPUT 		0x1b
+#define CX2341X_DEC_SET_AV_DELAY 		0x1c
+#define CX2341X_DEC_SET_PREBUFFERING		0x1e
+
+/* MPEG encoder API */
+#define CX2341X_ENC_PING_FW 			0x80
+#define CX2341X_ENC_START_CAPTURE 		0x81
+#define CX2341X_ENC_STOP_CAPTURE 		0x82
+#define CX2341X_ENC_SET_AUDIO_ID 		0x89
+#define CX2341X_ENC_SET_VIDEO_ID 		0x8b
+#define CX2341X_ENC_SET_PCR_ID 			0x8d
+#define CX2341X_ENC_SET_FRAME_RATE 		0x8f
+#define CX2341X_ENC_SET_FRAME_SIZE 		0x91
+#define CX2341X_ENC_SET_BIT_RATE 		0x95
+#define CX2341X_ENC_SET_GOP_PROPERTIES 		0x97
+#define CX2341X_ENC_SET_ASPECT_RATIO 		0x99
+#define CX2341X_ENC_SET_DNR_FILTER_MODE 	0x9b
+#define CX2341X_ENC_SET_DNR_FILTER_PROPS 	0x9d
+#define CX2341X_ENC_SET_CORING_LEVELS 		0x9f
+#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE 	0xa1
+#define CX2341X_ENC_SET_3_2_PULLDOWN 		0xb1
+#define CX2341X_ENC_SET_VBI_LINE 		0xb7
+#define CX2341X_ENC_SET_STREAM_TYPE 		0xb9
+#define CX2341X_ENC_SET_OUTPUT_PORT 		0xbb
+#define CX2341X_ENC_SET_AUDIO_PROPERTIES 	0xbd
+#define CX2341X_ENC_HALT_FW 			0xc3
+#define CX2341X_ENC_GET_VERSION			0xc4
+#define CX2341X_ENC_SET_GOP_CLOSURE 		0xc5
+#define CX2341X_ENC_GET_SEQ_END 		0xc6
+#define CX2341X_ENC_SET_PGM_INDEX_INFO 		0xc7
+#define CX2341X_ENC_SET_VBI_CONFIG		0xc8
+#define CX2341X_ENC_SET_DMA_BLOCK_SIZE 		0xc9
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10	0xca
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9	0xcb
+#define CX2341X_ENC_SCHED_DMA_TO_HOST 		0xcc
+#define CX2341X_ENC_INITIALIZE_INPUT 		0xcd
+#define CX2341X_ENC_SET_FRAME_DROP_RATE 	0xd0
+#define CX2341X_ENC_PAUSE_ENCODER 		0xd2
+#define CX2341X_ENC_REFRESH_INPUT 		0xd3
+#define CX2341X_ENC_SET_COPYRIGHT		0xd4
+#define CX2341X_ENC_SET_EVENT_NOTIFICATION 	0xd5
+#define CX2341X_ENC_SET_NUM_VSYNC_LINES 	0xd6
+#define CX2341X_ENC_SET_PLACEHOLDER 		0xd7
+#define CX2341X_ENC_MUTE_VIDEO 			0xd9
+#define CX2341X_ENC_MUTE_AUDIO 			0xda
+#define CX2341X_ENC_UNKNOWN			0xdb
+#define CX2341X_ENC_MISC 			0xdc
+
+/* OSD API, specific to the cx23415 */
+#define CX2341X_OSD_GET_FRAMEBUFFER 		0x41
+#define CX2341X_OSD_GET_PIXEL_FORMAT 		0x42
+#define CX2341X_OSD_SET_PIXEL_FORMAT 		0x43
+#define CX2341X_OSD_GET_STATE 			0x44
+#define CX2341X_OSD_SET_STATE 			0x45
+#define CX2341X_OSD_GET_OSD_COORDS 		0x46
+#define CX2341X_OSD_SET_OSD_COORDS 		0x47
+#define CX2341X_OSD_GET_SCREEN_COORDS 		0x48
+#define CX2341X_OSD_SET_SCREEN_COORDS 		0x49
+#define CX2341X_OSD_GET_GLOBAL_ALPHA 		0x4a
+#define CX2341X_OSD_SET_GLOBAL_ALPHA 		0x4b
+#define CX2341X_OSD_SET_BLEND_COORDS 		0x4c
+#define CX2341X_OSD_GET_FLICKER_STATE 		0x4f
+#define CX2341X_OSD_SET_FLICKER_STATE 		0x50
+#define CX2341X_OSD_BLT_COPY 			0x52
+#define CX2341X_OSD_BLT_FILL 			0x53
+#define CX2341X_OSD_BLT_TEXT 			0x54
+#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW 	0x56
+#define CX2341X_OSD_SET_CHROMA_KEY 		0x60
+#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX 	0x61
+#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX 	0x62
+
+#endif /* CX2341X_H */
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 302d5b3..7bab09b 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -73,7 +73,7 @@
 extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
@@ -87,8 +87,9 @@
 extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
 
 #endif
 
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 730f21e..a455f7c 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -20,5 +20,6 @@
 	int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
 
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 #endif
diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h
index 8138983..0f43451 100644
--- a/include/media/ovcamchip.h
+++ b/include/media/ovcamchip.h
@@ -15,6 +15,7 @@
 #define __LINUX_OVCAMCHIP_H
 
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
 #include <linux/i2c.h>
 
 /* --------------------------------- */
diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h
new file mode 100644
index 0000000..adc1254
--- /dev/null
+++ b/include/media/pwc-ioctl.h
@@ -0,0 +1,325 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 10.0.10
+   It contains structures and defines to communicate from user space
+   directly to the driver.
+ */
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added ioctl constants to access methods for
+			  changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
+   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
+	       PWCX easier
+   2006/01/01  Luc Saillard Add raw format definition
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+   They contain functions not found in other webcams, and settings not
+   specified in the Video4Linux API.
+
+   The #define names are built up like follows:
+   VIDIOC		VIDeo IOCtl prefix
+	 PWC		Philps WebCam
+	    G           optional: Get
+	    S           optional: Set
+	     ... 	the function
+ */
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF	0x00
+#define PSZ_QSIF	0x01
+#define PSZ_QCIF	0x02
+#define PSZ_SIF		0x03
+#define PSZ_CIF		0x04
+#define PSZ_VGA		0x05
+#define PSZ_MAX		6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+   the upper 16 bits, since some flags are defined nowadays. The following
+   defines provide a mask and shift to filter out this value.
+   This value can also be passing using the private flag when using v4l2 and
+   VIDIOC_S_FMT ioctl.
+
+   In 'Snapshot' mode the camera freezes its automatic exposure and colour
+   balance controls.
+ */
+#define PWC_FPS_SHIFT		16
+#define PWC_FPS_MASK		0x00FF0000
+#define PWC_FPS_FRMASK		0x003F0000
+#define PWC_FPS_SNAPSHOT	0x00400000
+#define PWC_QLT_MASK		0x03000000
+#define PWC_QLT_SHIFT		24
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+	int x, y;		/* guess what */
+	int size;		/* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+	char name[32];
+	int type;
+};
+
+struct pwc_serial
+{
+	char serial[30];	/* String with serial number. Contains terminating 0 */
+};
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR		0
+#define PWC_WB_OUTDOOR		1
+#define PWC_WB_FL		2
+#define PWC_WB_MANUAL		3
+#define PWC_WB_AUTO		4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+   Set mode to one of the PWC_WB_* values above.
+   *red and *blue are the respective gains of these colour components inside
+   the camera; range 0..65535
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
+   otherwise undefined.
+   'read_red' and 'read_blue' are read-only.
+*/
+struct pwc_whitebalance
+{
+	int mode;
+	int manual_red, manual_blue;	/* R/W */
+	int read_red, read_blue;	/* R/O */
+};
+
+/*
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+	int control_speed;
+	int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+	int led_on;			/* Led on-time; range = 0..25000 */
+	int led_off;			/* Led off-time; range = 0..25000  */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+	int width;
+	int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN		0x01
+#define PWC_MPT_TILT		0x02
+#define PWC_MPT_TIMEOUT		0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the
+   driver calculates the relative offset for you. This can only
+   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+   absolute angles.
+ */
+struct pwc_mpt_angles
+{
+	int absolute;		/* write-only */
+	int pan;		/* degrees * 100 */
+	int tilt;		/* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+	int pan_min, pan_max;		/* degrees * 100 */
+	int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+	int status;
+	int time_pan;
+	int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+   all the necessary information to initialize and use the decompressor
+   routines in standalone applications.
+ */
+struct pwc_video_command
+{
+	int type;		/* camera type (645, 675, 730, etc.) */
+	int release;		/* release number */
+
+	int size;		/* one of PSZ_* */
+	int alternate;
+	int command_len;	/* length of USB video command */
+	unsigned char command_buf[13];	/* Actual USB video command */
+	int bandlength;		/* >0 = compressed */
+	int frame_size;		/* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR	0x0001
+#define PWCX_FLAG_BAYER		0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER		_IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER		_IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY	_IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+    means use uncompressed modes when available; 1 is low compression, 2 is
+    medium and 3 is high compression preferred. Of course, the higher the
+    compression, the lower the bandwidth used but more chance of artefacts
+    in the image. The driver automatically chooses a higher compression when
+    the preferred mode is not available.
+  */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL		_IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL		_IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL	_IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */
+#define VIDIOCPWCPROBE		_IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC		_IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC		_IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER	_IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED	_IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED	_IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR	_IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR	_IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT	_IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT	_IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER	_IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER	_IOR('v', 208, int)
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE	_IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */
+#define VIDIOCPWCMPTRESET	_IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE	_IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE	_IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE	_IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS	_IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD	_IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+   int len;
+   char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE	_IOR('v', 216, struct pwc_table_init_buffer)
+
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+   __le16 type;		/* type of the webcam */
+   __le16 vbandlength;	/* Size of 4lines compressed (used by the decompressor) */
+   __u8   cmd[4];	/* the four byte of the command (in case of nala,
+			   only the first 3 bytes is filled) */
+   __u8   rawframe[0];	/* frame_size = H/4*vbandlength */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/include/media/saa7115.h b/include/media/saa7115.h
index 6b4836f..9f0e228 100644
--- a/include/media/saa7115.h
+++ b/include/media/saa7115.h
@@ -1,5 +1,5 @@
 /*
-    saa7115.h - definition for saa7113/4/5 inputs
+    saa7115.h - definition for saa7113/4/5 inputs and frequency flags
 
     Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
 
@@ -33,5 +33,14 @@
 #define SAA7115_SVIDEO2    8
 #define SAA7115_SVIDEO3    9
 
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ  32110000   /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000   /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC   (1 << 0)	   /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV (1 << 1)	   /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL   (1 << 2)	   /* SA 3A[3], APLL, SAA7114/5 only */
+
 #endif
 
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index 4507cb6..83fe2e3 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -2,7 +2,7 @@
 #define __SAA7146_VV__
 
 #include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
 #include <media/saa7146.h>
 #include <media/video-buf.h>
 
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 017fed7..2f7b00b 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -25,6 +25,8 @@
 #include <linux/videodev2.h>
 #include <media/tuner-types.h>
 
+extern int tuner_debug;
+
 #define ADDR_UNSET (255)
 
 #define TUNER_TEMIC_PAL			0        /* 4002 FH5 (3X 7756, 9483) */
@@ -108,7 +110,7 @@
 #define TUNER_TEA5767			62	/* Only FM Radio Tuner */
 #define TUNER_PHILIPS_FMD1216ME_MK3	63
 
-#define TUNER_LG_TDVS_H062F		64	/* DViCO FusionHDTV 5 */
+#define TUNER_LG_TDVS_H06XF		64	/* TDVS H061F, H062F, H064F */
 #define TUNER_YMEC_TVF66T5_B_DFF	65	/* Acorp Y878F */
 #define TUNER_LG_TALN			66
 #define TUNER_PHILIPS_TD1316		67
@@ -119,6 +121,8 @@
 #define TUNER_XCEIVE_XC3028		71
 
 #define TUNER_THOMSON_FE6600		72	/* DViCO FusionHDTV DVB-T Hybrid */
+#define TUNER_SAMSUNG_TCPG_6121P30A     73 	/* Hauppauge PVR-500 PAL */
+#define TUNER_TDA9887                   74      /* This tuner should be used only internally */
 
 /* tv card specific */
 #define TDA9887_PRESENT 		(1<<0)
@@ -190,6 +194,10 @@
 
 	int          using_v4l2;
 
+	/* used by tda9887 */
+	unsigned int       tda9887_config;
+	unsigned char 	   tda9887_data[4];
+
 	/* used by MT2032 */
 	unsigned int xogc;
 	unsigned int radio_if2;
@@ -206,6 +214,8 @@
 	void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
 	int  (*has_signal)(struct i2c_client *c);
 	int  (*is_stereo)(struct i2c_client *c);
+	int  (*get_afc)(struct i2c_client *c);
+	void (*tuner_status)(struct i2c_client *c);
 	void (*standby)(struct i2c_client *c);
 };
 
@@ -218,6 +228,7 @@
 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);
+extern int tda9887_tuner_init(struct i2c_client *c);
 
 #define tuner_warn(fmt, arg...) do {\
 	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
diff --git a/include/media/tvp5150.h b/include/media/tvp5150.h
new file mode 100644
index 0000000..72bd2a2
--- /dev/null
+++ b/include/media/tvp5150.h
@@ -0,0 +1,34 @@
+/*
+    tvp5150.h - definition for tvp5150 inputs
+
+    Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _TVP5150_H_
+#define _TVP5150_H_
+
+/* TVP5150 HW inputs */
+#define TVP5150_COMPOSITE0 0
+#define TVP5150_COMPOSITE1 1
+#define TVP5150_SVIDEO     2
+
+/* TVP5150 HW outputs */
+#define TVP5150_NORMAL       0
+#define TVP5150_BLACK_SCREEN 1
+
+#endif
+
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 642520a..5564db1 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -26,8 +26,14 @@
 #ifndef V4L2_COMMON_H_
 #define V4L2_COMMON_H_
 
+#include <media/v4l2-dev.h>
+
 /* v4l debugging and diagnostics */
 
+/* Debug bitmask flags to be used on V4L2 */
+#define V4L2_DEBUG_IOCTL     0x01
+#define V4L2_DEBUG_IOCTL_ARG 0x02
+
 /* Common printk constucts for v4l-i2c drivers. These macros create a unique
    prefix consisting of the driver name, the adapter number and the i2c
    address. */
@@ -78,6 +84,19 @@
 
 /* ------------------------------------------------------------------------- */
 
+/* Control helper functions */
+
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+		const char **menu_items);
+const char **v4l2_ctrl_get_menu(u32 id);
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
+		struct v4l2_queryctrl *qctrl, const char **menu_items);
+u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
+
+/* ------------------------------------------------------------------------- */
+
 /* Internal ioctls */
 
 /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
@@ -112,6 +131,8 @@
 	V4L2_IDENT_SAA7129 = 159,
 
 	/* module cx25840: reserved range 200-249 */
+	V4L2_IDENT_CX25836 = 236,
+	V4L2_IDENT_CX25837 = 237,
 	V4L2_IDENT_CX25840 = 240,
 	V4L2_IDENT_CX25841 = 241,
 	V4L2_IDENT_CX25842 = 242,
@@ -211,4 +232,15 @@
 #define	VIDIOC_INT_S_VIDEO_ROUTING	_IOW ('d', 111, struct v4l2_routing)
 #define	VIDIOC_INT_G_VIDEO_ROUTING	_IOR ('d', 112, struct v4l2_routing)
 
+struct v4l2_crystal_freq {
+	u32 freq;	/* frequency in Hz of the crystal */
+	u32 flags; 	/* device specific flags */
+};
+
+/* Sets the frequency of the crystal used to generate the clocks.
+   An extra flags field allows device specific configuration regarding
+   clock frequency dividers, etc. If not used, then set flags to 0.
+   If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_S_CRYSTAL_FREQ 	_IOW ('d', 113, struct v4l2_crystal_freq)
+
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
new file mode 100644
index 0000000..a1b4731
--- /dev/null
+++ b/include/media/v4l2-dev.h
@@ -0,0 +1,375 @@
+/*
+ *
+ *	V 4 L 2   D R I V E R   H E L P E R   A P I
+ *
+ * Moved from videodev2.h
+ *
+ *	Some commonly needed functions for drivers (v4l2-common.o module)
+ */
+#ifndef _V4L2_DEV_H
+#define _V4L2_DEV_H
+
+#define OBSOLETE_OWNER 1 /* to be removed soon */
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/compiler.h> /* need __user */
+#ifdef CONFIG_VIDEO_V4L1
+#include <linux/videodev.h>
+#else
+#include <linux/videodev2.h>
+#endif
+
+#include <linux/fs.h>
+
+#define VIDEO_MAJOR	81
+/* Minor device allocation */
+#define MINOR_VFL_TYPE_GRABBER_MIN   0
+#define MINOR_VFL_TYPE_GRABBER_MAX  63
+#define MINOR_VFL_TYPE_RADIO_MIN    64
+#define MINOR_VFL_TYPE_RADIO_MAX   127
+#define MINOR_VFL_TYPE_VTX_MIN     192
+#define MINOR_VFL_TYPE_VTX_MAX     223
+#define MINOR_VFL_TYPE_VBI_MIN     224
+#define MINOR_VFL_TYPE_VBI_MAX     255
+
+#define VFL_TYPE_GRABBER	0
+#define VFL_TYPE_VBI		1
+#define VFL_TYPE_RADIO		2
+#define VFL_TYPE_VTX		3
+
+/*  Video standard functions  */
+extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern int v4l2_video_std_construct(struct v4l2_standard *vs,
+				    int id, char *name);
+
+/* prority handling */
+struct v4l2_prio_state {
+	atomic_t prios[4];
+};
+int v4l2_prio_init(struct v4l2_prio_state *global);
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+		     enum v4l2_priority new);
+int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
+
+/* names for fancy debug output */
+extern char *v4l2_field_names[];
+extern char *v4l2_type_names[];
+
+/*  Compatibility layer interface  --  v4l1-compat module */
+typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
+			   unsigned int cmd, void *arg);
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
+			       int cmd, void *arg, v4l2_kioctl driver_ioctl);
+#else
+#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
+#endif
+
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+				unsigned long arg);
+
+/*
+ * Newer version of video_device, handled by videodev2.c
+ * 	This version moves redundant code from video device code to
+ *	the common handler
+ */
+struct v4l2_tvnorm {
+	char          *name;
+	v4l2_std_id   id;
+
+	void          *priv_data;
+};
+
+struct video_device
+{
+	/* device ops */
+	const struct file_operations *fops;
+
+	/* device info */
+	struct device *dev;
+	char name[32];
+	int type;       /* v4l1 */
+	int type2;      /* v4l2 */
+	int hardware;
+	int minor;
+
+	int debug;	/* Activates debug level*/
+
+	/* Video standard vars */
+	int tvnormsize;	/* Size of tvnorm array */
+	v4l2_std_id current_norm; /* Current tvnorm */
+	struct v4l2_tvnorm *tvnorms;
+
+	/* callbacks */
+	void (*release)(struct video_device *vfd);
+
+	/* ioctl callbacks */
+
+	/* VIDIOC_QUERYCAP handler */
+	int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
+
+	/* Priority handling */
+	int (*vidioc_g_priority)   (struct file *file, void *fh,
+				    enum v4l2_priority *p);
+	int (*vidioc_s_priority)   (struct file *file, void *fh,
+				    enum v4l2_priority p);
+
+	/* VIDIOC_ENUM_FMT handlers */
+	int (*vidioc_enum_fmt_cap)         (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_overlay)     (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_vbi)         (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_vbi_capture) (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_vbi_output)  (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
+
+	/* VIDIOC_G_FMT handlers */
+	int (*vidioc_g_fmt_cap)        (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_overlay)    (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_vbi)        (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_vbi_output) (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_vbi_capture)(struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_video_output)(struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
+					struct v4l2_format *f);
+
+	/* VIDIOC_S_FMT handlers */
+	int (*vidioc_s_fmt_cap)        (struct file *file, void *fh,
+					struct v4l2_format *f);
+
+	int (*vidioc_s_fmt_overlay)    (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_s_fmt_vbi)        (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_s_fmt_vbi_output) (struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_s_fmt_vbi_capture)(struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_s_fmt_video_output)(struct file *file, void *fh,
+					struct v4l2_format *f);
+	int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
+					struct v4l2_format *f);
+
+	/* VIDIOC_TRY_FMT handlers */
+	int (*vidioc_try_fmt_cap)        (struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_overlay)    (struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_vbi)        (struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_vbi_output) (struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_vbi_capture)(struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_video_output)(struct file *file, void *fh,
+					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
+					  struct v4l2_format *f);
+
+	/* Buffer handlers */
+	int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
+	int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
+	int (*vidioc_qbuf)    (struct file *file, void *fh, struct v4l2_buffer *b);
+	int (*vidioc_dqbuf)   (struct file *file, void *fh, struct v4l2_buffer *b);
+
+
+	int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
+#ifdef HAVE_V4L1
+			/* buffer type is struct vidio_mbuf * */
+	int (*vidiocgmbuf)  (struct file *file, void *fh, struct video_mbuf *p);
+#endif
+	int (*vidioc_g_fbuf)   (struct file *file, void *fh,
+				struct v4l2_framebuffer *a);
+	int (*vidioc_s_fbuf)   (struct file *file, void *fh,
+				struct v4l2_framebuffer *a);
+
+		/* Stream on/off */
+	int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i);
+	int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
+
+		/* Standard handling
+			G_STD and ENUMSTD are handled by videodev.c
+		 */
+	int (*vidioc_s_std)    (struct file *file, void *fh, v4l2_std_id a);
+	int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
+
+		/* Input handling */
+	int (*vidioc_enum_input)(struct file *file, void *fh,
+				 struct v4l2_input *inp);
+	int (*vidioc_g_input)   (struct file *file, void *fh, unsigned int *i);
+	int (*vidioc_s_input)   (struct file *file, void *fh, unsigned int i);
+
+		/* Output handling */
+	int (*vidioc_enumoutput) (struct file *file, void *fh,
+				  struct v4l2_output *a);
+	int (*vidioc_g_output)   (struct file *file, void *fh, unsigned int *i);
+	int (*vidioc_s_output)   (struct file *file, void *fh, unsigned int i);
+
+		/* Control handling */
+	int (*vidioc_queryctrl)        (struct file *file, void *fh,
+					struct v4l2_queryctrl *a);
+	int (*vidioc_g_ctrl)           (struct file *file, void *fh,
+					struct v4l2_control *a);
+	int (*vidioc_s_ctrl)           (struct file *file, void *fh,
+					struct v4l2_control *a);
+	int (*vidioc_g_ext_ctrls)      (struct file *file, void *fh,
+					struct v4l2_ext_controls *a);
+	int (*vidioc_s_ext_ctrls)      (struct file *file, void *fh,
+					struct v4l2_ext_controls *a);
+	int (*vidioc_try_ext_ctrls)    (struct file *file, void *fh,
+					struct v4l2_ext_controls *a);
+	int (*vidioc_querymenu)        (struct file *file, void *fh,
+					struct v4l2_querymenu *a);
+
+	/* Audio ioctls */
+	int (*vidioc_enumaudio)        (struct file *file, void *fh,
+					struct v4l2_audio *a);
+	int (*vidioc_g_audio)          (struct file *file, void *fh,
+					struct v4l2_audio *a);
+	int (*vidioc_s_audio)          (struct file *file, void *fh,
+					struct v4l2_audio *a);
+
+	/* Audio out ioctls */
+	int (*vidioc_enumaudout)       (struct file *file, void *fh,
+					struct v4l2_audioout *a);
+	int (*vidioc_g_audout)         (struct file *file, void *fh,
+					struct v4l2_audioout *a);
+	int (*vidioc_s_audout)         (struct file *file, void *fh,
+					struct v4l2_audioout *a);
+	int (*vidioc_g_modulator)      (struct file *file, void *fh,
+					struct v4l2_modulator *a);
+	int (*vidioc_s_modulator)      (struct file *file, void *fh,
+					struct v4l2_modulator *a);
+	/* Crop ioctls */
+	int (*vidioc_cropcap)          (struct file *file, void *fh,
+					struct v4l2_cropcap *a);
+	int (*vidioc_g_crop)           (struct file *file, void *fh,
+					struct v4l2_crop *a);
+	int (*vidioc_s_crop)           (struct file *file, void *fh,
+					struct v4l2_crop *a);
+	/* Compression ioctls */
+	int (*vidioc_g_mpegcomp)       (struct file *file, void *fh,
+					struct v4l2_mpeg_compression *a);
+	int (*vidioc_s_mpegcomp)       (struct file *file, void *fh,
+					struct v4l2_mpeg_compression *a);
+	int (*vidioc_g_jpegcomp)       (struct file *file, void *fh,
+					struct v4l2_jpegcompression *a);
+	int (*vidioc_s_jpegcomp)       (struct file *file, void *fh,
+					struct v4l2_jpegcompression *a);
+
+	/* Stream type-dependent parameter ioctls */
+	int (*vidioc_g_parm)           (struct file *file, void *fh,
+					struct v4l2_streamparm *a);
+	int (*vidioc_s_parm)           (struct file *file, void *fh,
+					struct v4l2_streamparm *a);
+
+	/* Tuner ioctls */
+	int (*vidioc_g_tuner)          (struct file *file, void *fh,
+					struct v4l2_tuner *a);
+	int (*vidioc_s_tuner)          (struct file *file, void *fh,
+					struct v4l2_tuner *a);
+	int (*vidioc_g_frequency)      (struct file *file, void *fh,
+					struct v4l2_frequency *a);
+	int (*vidioc_s_frequency)      (struct file *file, void *fh,
+					struct v4l2_frequency *a);
+
+	/* Sliced VBI cap */
+	int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh,
+					struct v4l2_sliced_vbi_cap *a);
+
+	/* Log status ioctl */
+	int (*vidioc_log_status)       (struct file *file, void *fh);
+
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* 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 mutex lock;             /* ... helper function uses these   */
+	char devfs_name[64];           /* devfs */
+	struct class_device class_dev; /* sysfs */
+};
+
+/* Version 2 functions */
+extern int video_register_device(struct video_device *vfd, int type, int nr);
+void video_unregister_device(struct video_device *);
+extern int video_ioctl2(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long 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);
+
+/* Include support for obsoleted stuff */
+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));
+
+
+#ifdef HAVE_V4L1
+#include <linux/mm.h>
+
+extern struct video_device* video_devdata(struct file*);
+
+#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+static inline void
+video_device_create_file(struct video_device *vfd,
+			 struct class_device_attribute *attr)
+{
+	class_device_create_file(&vfd->class_dev, attr);
+}
+static inline void
+video_device_remove_file(struct video_device *vfd,
+			 struct class_device_attribute *attr)
+{
+	class_device_remove_file(&vfd->class_dev, attr);
+}
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* helper functions to access driver private data. */
+static inline void *video_get_drvdata(struct video_device *dev)
+{
+	return dev->priv;
+}
+
+static inline void video_set_drvdata(struct video_device *dev, void *data)
+{
+	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);
+#endif /* HAVE_V4L1 */
+
+#endif /* _V4L2_DEV_H */
diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h
index b78d90f..8233caf 100644
--- a/include/media/video-buf-dvb.h
+++ b/include/media/video-buf-dvb.h
@@ -26,7 +26,8 @@
 
 int videobuf_dvb_register(struct videobuf_dvb *dvb,
 			  struct module *module,
-			  void *adapter_priv);
+			  void *adapter_priv,
+			  struct device *device);
 void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
 
 /*
diff --git a/include/media/video-buf.h b/include/media/video-buf.h
index fff3fd0..1115a25 100644
--- a/include/media/video-buf.h
+++ b/include/media/video-buf.h
@@ -23,6 +23,7 @@
  */
 
 #include <linux/videodev2.h>
+#include <linux/poll.h>
 
 #define UNSET (-1U)
 
diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h
index 098607c..e07136d 100644
--- a/include/net/tipc/tipc_bearer.h
+++ b/include/net/tipc/tipc_bearer.h
@@ -49,10 +49,18 @@
 
 #define TIPC_MEDIA_TYPE_ETH	1
 
+/* 
+ * Destination address structure used by TIPC bearers when sending messages
+ * 
+ * IMPORTANT: The fields of this structure MUST be stored using the specified
+ * byte order indicated below, as the structure is exchanged between nodes
+ * as part of a link setup process.
+ */
+
 struct tipc_media_addr {
-	__u32  type;
+	__u32  type;			/* bearer type (network byte order) */
 	union {
-		__u8   eth_addr[6];	/* Ethernet bearer */ 
+		__u8   eth_addr[6];	/* 48 bit Ethernet addr (byte array) */ 
 #if 0
 		/* Prototypes for other possible bearer types */
 
diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h
index a4f55452..b5067d3 100644
--- a/include/sound/tea575x-tuner.h
+++ b/include/sound/tea575x-tuner.h
@@ -20,9 +20,10 @@
  *   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/videodev.h>
+#include <media/v4l2-dev.h>
 
 struct snd_tea575x;
 
diff --git a/init/Kconfig b/init/Kconfig
index df864a3..df55b36 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1,3 +1,11 @@
+config DEFCONFIG_LIST
+	string
+	option defconfig_list
+	default "/lib/modules/$UNAME_RELEASE/.config"
+	default "/etc/kernel-config"
+	default "/boot/config-$UNAME_RELEASE"
+	default "arch/$ARCH/defconfig"
+
 menu "Code maturity level options"
 
 config EXPERIMENTAL
@@ -151,7 +159,8 @@
 	  at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.
 
 config SYSCTL
-	bool "Sysctl support"
+	bool "Sysctl support" if EMBEDDED
+	default y
 	---help---
 	  The sysctl interface provides a means of dynamically changing
 	  certain kernel parameters and variables on the fly without requiring
@@ -235,16 +244,6 @@
 	help
 	  This enables the legacy 16-bit UID syscall wrappers.
 
-config VM86
-	depends X86
-	default y
-	bool "Enable VM86 support" if EMBEDDED
-	help
-          This option is required by programs like DOSEMU to run 16-bit legacy
-	  code on X86 processors. It also may be needed by software like
-          XFree86 to initialize some video cards via BIOS. Disabling this
-          option saves about 6k.
-
 config CC_OPTIMIZE_FOR_SIZE
 	bool "Optimize for size (Look out for broken compilers!)"
 	default y
diff --git a/init/initramfs.c b/init/initramfs.c
index f81cfa4..d28c109 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -30,6 +30,7 @@
 
 static __initdata struct hash {
 	int ino, minor, major;
+	mode_t mode;
 	struct hash *next;
 	char name[N_ALIGN(PATH_MAX)];
 } *head[32];
@@ -41,7 +42,8 @@
 	return tmp & 31;
 }
 
-static char __init *find_link(int major, int minor, int ino, char *name)
+static char __init *find_link(int major, int minor, int ino,
+			      mode_t mode, char *name)
 {
 	struct hash **p, *q;
 	for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
@@ -51,14 +53,17 @@
 			continue;
 		if ((*p)->major != major)
 			continue;
+		if (((*p)->mode ^ mode) & S_IFMT)
+			continue;
 		return (*p)->name;
 	}
 	q = (struct hash *)malloc(sizeof(struct hash));
 	if (!q)
 		panic("can't allocate link hash entry");
-	q->ino = ino;
-	q->minor = minor;
 	q->major = major;
+	q->minor = minor;
+	q->ino = ino;
+	q->mode = mode;
 	strcpy(q->name, name);
 	q->next = NULL;
 	*p = q;
@@ -229,13 +234,25 @@
 static int __init maybe_link(void)
 {
 	if (nlink >= 2) {
-		char *old = find_link(major, minor, ino, collected);
+		char *old = find_link(major, minor, ino, mode, collected);
 		if (old)
 			return (sys_link(old, collected) < 0) ? -1 : 1;
 	}
 	return 0;
 }
 
+static void __init clean_path(char *path, mode_t mode)
+{
+	struct stat st;
+
+	if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) {
+		if (S_ISDIR(st.st_mode))
+			sys_rmdir(path);
+		else
+			sys_unlink(path);
+	}
+}
+
 static __initdata int wfd;
 
 static int __init do_name(void)
@@ -248,9 +265,15 @@
 	}
 	if (dry_run)
 		return 0;
+	clean_path(collected, mode);
 	if (S_ISREG(mode)) {
-		if (maybe_link() >= 0) {
-			wfd = sys_open(collected, O_WRONLY|O_CREAT, mode);
+		int ml = maybe_link();
+		if (ml >= 0) {
+			int openflags = O_WRONLY|O_CREAT;
+			if (ml != 1)
+				openflags |= O_TRUNC;
+			wfd = sys_open(collected, openflags, mode);
+
 			if (wfd >= 0) {
 				sys_fchown(wfd, uid, gid);
 				sys_fchmod(wfd, mode);
@@ -291,6 +314,7 @@
 static int __init do_symlink(void)
 {
 	collected[N_ALIGN(name_len) + body_len] = '\0';
+	clean_path(collected, 0);
 	sys_symlink(collected + N_ALIGN(name_len), collected);
 	sys_lchown(collected, uid, gid);
 	state = SkipIt;
diff --git a/init/main.c b/init/main.c
index f715b9b..80af1a5 100644
--- a/init/main.c
+++ b/init/main.c
@@ -47,6 +47,7 @@
 #include <linux/rmap.h>
 #include <linux/mempolicy.h>
 #include <linux/key.h>
+#include <linux/unwind.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -482,6 +483,7 @@
 		   __stop___param - __start___param,
 		   &unknown_bootoption);
 	sort_main_extable();
+	unwind_init();
 	trap_init();
 	rcu_init();
 	init_IRQ();
@@ -490,6 +492,7 @@
 	hrtimers_init();
 	softirq_init();
 	time_init();
+	timekeeping_init();
 
 	/*
 	 * HACK ALERT! This is early. We're enabling the console before
diff --git a/kernel/Makefile b/kernel/Makefile
index f6ef00f..752bd7d 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -10,6 +10,7 @@
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
 	    hrtimer.o
 
+obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
 obj-$(CONFIG_FUTEX) += futex.o
 ifeq ($(CONFIG_COMPAT),y)
@@ -21,6 +22,7 @@
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
+obj-$(CONFIG_STACK_UNWIND) += unwind.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
diff --git a/kernel/acct.c b/kernel/acct.c
index 6802020..368c4f0 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -75,7 +75,7 @@
 /*
  * External references and all of the globals.
  */
-static void do_acct_process(long, struct file *);
+static void do_acct_process(struct file *);
 
 /*
  * This structure is used so that all the data protected by lock
@@ -196,7 +196,7 @@
 	if (old_acct) {
 		mnt_unpin(old_acct->f_vfsmnt);
 		spin_unlock(&acct_globals.lock);
-		do_acct_process(0, old_acct);
+		do_acct_process(old_acct);
 		filp_close(old_acct, NULL);
 		spin_lock(&acct_globals.lock);
 	}
@@ -419,16 +419,15 @@
 /*
  *  do_acct_process does all actual work. Caller holds the reference to file.
  */
-static void do_acct_process(long exitcode, struct file *file)
+static void do_acct_process(struct file *file)
 {
+	struct pacct_struct *pacct = &current->signal->pacct;
 	acct_t ac;
 	mm_segment_t fs;
-	unsigned long vsize;
 	unsigned long flim;
 	u64 elapsed;
 	u64 run_time;
 	struct timespec uptime;
-	unsigned long jiffies;
 
 	/*
 	 * First check to see if there is enough free_space to continue
@@ -469,12 +468,6 @@
 #endif
 	do_div(elapsed, AHZ);
 	ac.ac_btime = xtime.tv_sec - elapsed;
-	jiffies = cputime_to_jiffies(cputime_add(current->utime,
-						 current->signal->utime));
-	ac.ac_utime = encode_comp_t(jiffies_to_AHZ(jiffies));
-	jiffies = cputime_to_jiffies(cputime_add(current->stime,
-						 current->signal->stime));
-	ac.ac_stime = encode_comp_t(jiffies_to_AHZ(jiffies));
 	/* we really need to bite the bullet and change layout */
 	ac.ac_uid = current->uid;
 	ac.ac_gid = current->gid;
@@ -496,37 +489,18 @@
 		old_encode_dev(tty_devnum(current->signal->tty)) : 0;
 	read_unlock(&tasklist_lock);
 
-	ac.ac_flag = 0;
-	if (current->flags & PF_FORKNOEXEC)
-		ac.ac_flag |= AFORK;
-	if (current->flags & PF_SUPERPRIV)
-		ac.ac_flag |= ASU;
-	if (current->flags & PF_DUMPCORE)
-		ac.ac_flag |= ACORE;
-	if (current->flags & PF_SIGNALED)
-		ac.ac_flag |= AXSIG;
-
-	vsize = 0;
-	if (current->mm) {
-		struct vm_area_struct *vma;
-		down_read(&current->mm->mmap_sem);
-		vma = current->mm->mmap;
-		while (vma) {
-			vsize += vma->vm_end - vma->vm_start;
-			vma = vma->vm_next;
-		}
-		up_read(&current->mm->mmap_sem);
-	}
-	vsize = vsize / 1024;
-	ac.ac_mem = encode_comp_t(vsize);
+	spin_lock(&current->sighand->siglock);
+	ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
+	ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
+	ac.ac_flag = pacct->ac_flag;
+	ac.ac_mem = encode_comp_t(pacct->ac_mem);
+	ac.ac_minflt = encode_comp_t(pacct->ac_minflt);
+	ac.ac_majflt = encode_comp_t(pacct->ac_majflt);
+	ac.ac_exitcode = pacct->ac_exitcode;
+	spin_unlock(&current->sighand->siglock);
 	ac.ac_io = encode_comp_t(0 /* current->io_usage */);	/* %% */
 	ac.ac_rw = encode_comp_t(ac.ac_io / 1024);
-	ac.ac_minflt = encode_comp_t(current->signal->min_flt +
-				     current->min_flt);
-	ac.ac_majflt = encode_comp_t(current->signal->maj_flt +
-				     current->maj_flt);
 	ac.ac_swaps = encode_comp_t(0);
-	ac.ac_exitcode = exitcode;
 
 	/*
          * Kernel segment override to datasegment and write it
@@ -546,12 +520,63 @@
 }
 
 /**
+ * acct_init_pacct - initialize a new pacct_struct
+ */
+void acct_init_pacct(struct pacct_struct *pacct)
+{
+	memset(pacct, 0, sizeof(struct pacct_struct));
+	pacct->ac_utime = pacct->ac_stime = cputime_zero;
+}
+
+/**
+ * acct_collect - collect accounting information into pacct_struct
+ * @exitcode: task exit code
+ * @group_dead: not 0, if this thread is the last one in the process.
+ */
+void acct_collect(long exitcode, int group_dead)
+{
+	struct pacct_struct *pacct = &current->signal->pacct;
+	unsigned long vsize = 0;
+
+	if (group_dead && current->mm) {
+		struct vm_area_struct *vma;
+		down_read(&current->mm->mmap_sem);
+		vma = current->mm->mmap;
+		while (vma) {
+			vsize += vma->vm_end - vma->vm_start;
+			vma = vma->vm_next;
+		}
+		up_read(&current->mm->mmap_sem);
+	}
+
+	spin_lock_irq(&current->sighand->siglock);
+	if (group_dead)
+		pacct->ac_mem = vsize / 1024;
+	if (thread_group_leader(current)) {
+		pacct->ac_exitcode = exitcode;
+		if (current->flags & PF_FORKNOEXEC)
+			pacct->ac_flag |= AFORK;
+	}
+	if (current->flags & PF_SUPERPRIV)
+		pacct->ac_flag |= ASU;
+	if (current->flags & PF_DUMPCORE)
+		pacct->ac_flag |= ACORE;
+	if (current->flags & PF_SIGNALED)
+		pacct->ac_flag |= AXSIG;
+	pacct->ac_utime = cputime_add(pacct->ac_utime, current->utime);
+	pacct->ac_stime = cputime_add(pacct->ac_stime, current->stime);
+	pacct->ac_minflt += current->min_flt;
+	pacct->ac_majflt += current->maj_flt;
+	spin_unlock_irq(&current->sighand->siglock);
+}
+
+/**
  * acct_process - now just a wrapper around do_acct_process
  * @exitcode: task exit code
  *
  * handles process accounting for an exiting task
  */
-void acct_process(long exitcode)
+void acct_process()
 {
 	struct file *file = NULL;
 
@@ -570,7 +595,7 @@
 	get_file(file);
 	spin_unlock(&acct_globals.lock);
 
-	do_acct_process(exitcode, file);
+	do_acct_process(file);
 	fput(file);
 }
 
@@ -599,9 +624,7 @@
  */
 void acct_clear_integrals(struct task_struct *tsk)
 {
-	if (tsk) {
-		tsk->acct_stimexpd = 0;
-		tsk->acct_rss_mem1 = 0;
-		tsk->acct_vm_mem1 = 0;
-	}
+	tsk->acct_stimexpd = 0;
+	tsk->acct_rss_mem1 = 0;
+	tsk->acct_vm_mem1 = 0;
 }
diff --git a/kernel/compat.c b/kernel/compat.c
index 2f67233..126dee9 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -730,17 +730,10 @@
 sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
 {
 	switch (_NSIG_WORDS) {
-#if defined (__COMPAT_ENDIAN_SWAP__)
-	case 4: set->sig[3] = compat->sig[7] | (((long)compat->sig[6]) << 32 );
-	case 3: set->sig[2] = compat->sig[5] | (((long)compat->sig[4]) << 32 );
-	case 2: set->sig[1] = compat->sig[3] | (((long)compat->sig[2]) << 32 );
-	case 1: set->sig[0] = compat->sig[1] | (((long)compat->sig[0]) << 32 );
-#else
 	case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
 	case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
 	case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
 	case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
-#endif
 	}
 }
 
diff --git a/kernel/cpu.c b/kernel/cpu.c
index fe2b8d0..03dcd98 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -13,10 +13,10 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/stop_machine.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* This protects CPUs going up and down... */
-static DECLARE_MUTEX(cpucontrol);
+static DEFINE_MUTEX(cpucontrol);
 
 static BLOCKING_NOTIFIER_HEAD(cpu_chain);
 
@@ -30,9 +30,9 @@
 
 	if (lock_cpu_hotplug_owner != current) {
 		if (interruptible)
-			ret = down_interruptible(&cpucontrol);
+			ret = mutex_lock_interruptible(&cpucontrol);
 		else
-			down(&cpucontrol);
+			mutex_lock(&cpucontrol);
 	}
 
 	/*
@@ -56,7 +56,7 @@
 {
 	if (--lock_cpu_hotplug_depth == 0) {
 		lock_cpu_hotplug_owner = NULL;
-		up(&cpucontrol);
+		mutex_unlock(&cpucontrol);
 	}
 }
 EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index b602f73..1535af3 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -2442,31 +2442,43 @@
  */
 static int proc_cpuset_show(struct seq_file *m, void *v)
 {
+	struct pid *pid;
 	struct task_struct *tsk;
 	char *buf;
-	int retval = 0;
+	int retval;
 
+	retval = -ENOMEM;
 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!buf)
-		return -ENOMEM;
+		goto out;
 
-	tsk = m->private;
+	retval = -ESRCH;
+	pid = m->private;
+	tsk = get_pid_task(pid, PIDTYPE_PID);
+	if (!tsk)
+		goto out_free;
+
+	retval = -EINVAL;
 	mutex_lock(&manage_mutex);
+
 	retval = cpuset_path(tsk->cpuset, buf, PAGE_SIZE);
 	if (retval < 0)
-		goto out;
+		goto out_unlock;
 	seq_puts(m, buf);
 	seq_putc(m, '\n');
-out:
+out_unlock:
 	mutex_unlock(&manage_mutex);
+	put_task_struct(tsk);
+out_free:
 	kfree(buf);
+out:
 	return retval;
 }
 
 static int cpuset_open(struct inode *inode, struct file *file)
 {
-	struct task_struct *tsk = PROC_I(inode)->task;
-	return single_open(file, proc_cpuset_show, tsk);
+	struct pid *pid = PROC_I(inode)->pid;
+	return single_open(file, proc_cpuset_show, pid);
 }
 
 struct file_operations proc_cpuset_operations = {
diff --git a/kernel/exit.c b/kernel/exit.c
index a3baf92..304ef63 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -36,6 +36,7 @@
 #include <linux/compat.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/audit.h> /* for audit_free() */
+#include <linux/resource.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -45,8 +46,6 @@
 extern void sem_exit (void);
 extern struct task_struct *child_reaper;
 
-int getrusage(struct task_struct *, int, struct rusage __user *);
-
 static void exit_mm(struct task_struct * tsk);
 
 static void __unhash_process(struct task_struct *p)
@@ -138,12 +137,8 @@
 {
 	int zap_leader;
 	task_t *leader;
-	struct dentry *proc_dentry;
-
 repeat:
 	atomic_dec(&p->user->processes);
-	spin_lock(&p->proc_lock);
-	proc_dentry = proc_pid_unhash(p);
 	write_lock_irq(&tasklist_lock);
 	ptrace_unlink(p);
 	BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
@@ -172,8 +167,7 @@
 
 	sched_exit(p);
 	write_unlock_irq(&tasklist_lock);
-	spin_unlock(&p->proc_lock);
-	proc_pid_flush(proc_dentry);
+	proc_flush_task(p);
 	release_thread(p);
 	call_rcu(&p->rcu, delayed_put_task_struct);
 
@@ -895,11 +889,11 @@
 	if (group_dead) {
  		hrtimer_cancel(&tsk->signal->real_timer);
 		exit_itimers(tsk->signal);
-		acct_process(code);
 	}
+	acct_collect(code, group_dead);
 	if (unlikely(tsk->robust_list))
 		exit_robust_list(tsk);
-#ifdef CONFIG_COMPAT
+#if defined(CONFIG_FUTEX) && defined(CONFIG_COMPAT)
 	if (unlikely(tsk->compat_robust_list))
 		compat_exit_robust_list(tsk);
 #endif
@@ -907,6 +901,8 @@
 		audit_free(tsk);
 	exit_mm(tsk);
 
+	if (group_dead)
+		acct_process();
 	exit_sem(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index 49adc0e..9b4e54e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -874,6 +874,7 @@
 		tsk->it_prof_expires =
 			secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
 	}
+	acct_init_pacct(&sig->pacct);
 
 	return 0;
 }
@@ -992,13 +993,10 @@
 		if (put_user(p->pid, parent_tidptr))
 			goto bad_fork_cleanup;
 
-	p->proc_dentry = NULL;
-
 	INIT_LIST_HEAD(&p->children);
 	INIT_LIST_HEAD(&p->sibling);
 	p->vfork_done = NULL;
 	spin_lock_init(&p->alloc_lock);
-	spin_lock_init(&p->proc_lock);
 
 	clear_tsk_thread_flag(p, TIF_SIGPENDING);
 	init_sigpending(&p->pending);
@@ -1158,18 +1156,6 @@
 	}
 
 	if (clone_flags & CLONE_THREAD) {
-		/*
-		 * Important: if an exit-all has been started then
-		 * do not create this new thread - the whole thread
-		 * group is supposed to exit anyway.
-		 */
-		if (current->signal->flags & SIGNAL_GROUP_EXIT) {
-			spin_unlock(&current->sighand->siglock);
-			write_unlock_irq(&tasklist_lock);
-			retval = -EAGAIN;
-			goto bad_fork_cleanup_namespace;
-		}
-
 		p->group_leader = current->group_leader;
 		list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
 
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 1832430..55601b3 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -98,7 +98,6 @@
 
 /**
  * ktime_get_ts - get the monotonic clock in timespec format
- *
  * @ts:		pointer to timespec variable
  *
  * The function calculates the monotonic clock from the realtime
@@ -238,7 +237,6 @@
 # ifndef CONFIG_KTIME_SCALAR
 /**
  * ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
- *
  * @kt:		addend
  * @nsec:	the scalar nsec value to add
  *
@@ -299,7 +297,6 @@
 
 /**
  * hrtimer_forward - forward the timer expiry
- *
  * @timer:	hrtimer to forward
  * @now:	forward past this time
  * @interval:	the interval to forward
@@ -411,7 +408,6 @@
 
 /**
  * hrtimer_start - (re)start an relative timer on the current CPU
- *
  * @timer:	the timer to be added
  * @tim:	expiry time
  * @mode:	expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
@@ -460,14 +456,13 @@
 
 /**
  * hrtimer_try_to_cancel - try to deactivate a timer
- *
  * @timer:	hrtimer to stop
  *
  * Returns:
  *  0 when the timer was not active
  *  1 when the timer was active
  * -1 when the timer is currently excuting the callback function and
- *    can not be stopped
+ *    cannot be stopped
  */
 int hrtimer_try_to_cancel(struct hrtimer *timer)
 {
@@ -489,7 +484,6 @@
 
 /**
  * hrtimer_cancel - cancel a timer and wait for the handler to finish.
- *
  * @timer:	the timer to be cancelled
  *
  * Returns:
@@ -510,7 +504,6 @@
 
 /**
  * hrtimer_get_remaining - get remaining time for the timer
- *
  * @timer:	the timer to read
  */
 ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
@@ -564,7 +557,6 @@
 
 /**
  * hrtimer_init - initialize a timer to the given clock
- *
  * @timer:	the timer to be initialized
  * @clock_id:	the clock to be used
  * @mode:	timer mode abs/rel
@@ -576,7 +568,7 @@
 
 	memset(timer, 0, sizeof(struct hrtimer));
 
-	bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
+	bases = __raw_get_cpu_var(hrtimer_bases);
 
 	if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS)
 		clock_id = CLOCK_MONOTONIC;
@@ -588,7 +580,6 @@
 
 /**
  * hrtimer_get_res - get the timer resolution for a clock
- *
  * @which_clock: which clock to query
  * @tp:		 pointer to timespec variable to store the resolution
  *
@@ -599,7 +590,7 @@
 {
 	struct hrtimer_base *bases;
 
-	bases = per_cpu(hrtimer_bases, raw_smp_processor_id());
+	bases = __raw_get_cpu_var(hrtimer_bases);
 	*tp = ktime_to_timespec(bases[which_clock].resolution);
 
 	return 0;
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 1fbf466..64aab08 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -47,11 +47,17 @@
 
 static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
 static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
+static atomic_t kprobe_count;
 
 DEFINE_MUTEX(kprobe_mutex);		/* Protects kprobe_table */
 DEFINE_SPINLOCK(kretprobe_lock);	/* Protects kretprobe_inst_table */
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
 
+static struct notifier_block kprobe_page_fault_nb = {
+	.notifier_call = kprobe_exceptions_notify,
+	.priority = 0x7fffffff /* we need to notified first */
+};
+
 #ifdef __ARCH_WANT_KPROBES_INSN_SLOT
 /*
  * kprobe->ainsn.insn points to the copy of the instruction to be
@@ -368,16 +374,15 @@
 */
 static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
 {
-        struct kprobe *kp;
-
 	if (p->break_handler) {
-		list_for_each_entry_rcu(kp, &old_p->list, list) {
-			if (kp->break_handler)
-				return -EEXIST;
-		}
+		if (old_p->break_handler)
+			return -EEXIST;
 		list_add_tail_rcu(&p->list, &old_p->list);
+		old_p->break_handler = aggr_break_handler;
 	} else
 		list_add_rcu(&p->list, &old_p->list);
+	if (p->post_handler && !old_p->post_handler)
+		old_p->post_handler = aggr_post_handler;
 	return 0;
 }
 
@@ -390,9 +395,11 @@
 	copy_kprobe(p, ap);
 	ap->addr = p->addr;
 	ap->pre_handler = aggr_pre_handler;
-	ap->post_handler = aggr_post_handler;
 	ap->fault_handler = aggr_fault_handler;
-	ap->break_handler = aggr_break_handler;
+	if (p->post_handler)
+		ap->post_handler = aggr_post_handler;
+	if (p->break_handler)
+		ap->break_handler = aggr_break_handler;
 
 	INIT_LIST_HEAD(&ap->list);
 	list_add_rcu(&p->list, &ap->list);
@@ -464,6 +471,8 @@
 	old_p = get_kprobe(p->addr);
 	if (old_p) {
 		ret = register_aggr_kprobe(old_p, p);
+		if (!ret)
+			atomic_inc(&kprobe_count);
 		goto out;
 	}
 
@@ -474,6 +483,10 @@
 	hlist_add_head_rcu(&p->hlist,
 		       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
+	if (atomic_add_return(1, &kprobe_count) == \
+				(ARCH_INACTIVE_KPROBE_COUNT + 1))
+		register_page_fault_notifier(&kprobe_page_fault_nb);
+
   	arch_arm_kprobe(p);
 
 out:
@@ -536,14 +549,40 @@
 			kfree(old_p);
 		}
 		arch_remove_kprobe(p);
+	} else {
+		mutex_lock(&kprobe_mutex);
+		if (p->break_handler)
+			old_p->break_handler = NULL;
+		if (p->post_handler){
+			list_for_each_entry_rcu(list_p, &old_p->list, list){
+				if (list_p->post_handler){
+					cleanup_p = 2;
+					break;
+				}
+			}
+			if (cleanup_p == 0)
+				old_p->post_handler = NULL;
+		}
+		mutex_unlock(&kprobe_mutex);
 	}
+
+	/* Call unregister_page_fault_notifier()
+	 * if no probes are active
+	 */
+	mutex_lock(&kprobe_mutex);
+	if (atomic_add_return(-1, &kprobe_count) == \
+				ARCH_INACTIVE_KPROBE_COUNT)
+		unregister_page_fault_notifier(&kprobe_page_fault_nb);
+	mutex_unlock(&kprobe_mutex);
+	return;
 }
 
 static struct notifier_block kprobe_exceptions_nb = {
 	.notifier_call = kprobe_exceptions_notify,
-	.priority = 0x7fffffff /* we need to notified first */
+	.priority = 0x7fffffff /* we need to be notified first */
 };
 
+
 int __kprobes register_jprobe(struct jprobe *jp)
 {
 	/* Todo: Verify probepoint is a function entry point */
@@ -652,6 +691,7 @@
 		INIT_HLIST_HEAD(&kprobe_table[i]);
 		INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
 	}
+	atomic_set(&kprobe_count, 0);
 
 	err = arch_init_kprobes();
 	if (!err)
diff --git a/kernel/kthread.c b/kernel/kthread.c
index c5f3c66..24be714 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -45,6 +45,13 @@
 static DEFINE_MUTEX(kthread_stop_lock);
 static struct kthread_stop_info kthread_stop_info;
 
+/**
+ * kthread_should_stop - should this kthread return now?
+ *
+ * When someone calls kthread_stop on your kthread, it will be woken
+ * and this will return true.  You should then return, and your return
+ * value will be passed through to kthread_stop().
+ */
 int kthread_should_stop(void)
 {
 	return (kthread_stop_info.k == current);
@@ -122,6 +129,25 @@
 	complete(&create->done);
 }
 
+/**
+ * kthread_create - create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread.  The thread will be stopped: use wake_up_process() to start
+ * it.  See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' is true (which means
+ * kthread_stop() has been called).  The return value should be zero
+ * or a negative error number; it will be passed to kthread_stop().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
 struct task_struct *kthread_create(int (*threadfn)(void *data),
 				   void *data,
 				   const char namefmt[],
@@ -156,6 +182,15 @@
 }
 EXPORT_SYMBOL(kthread_create);
 
+/**
+ * kthread_bind - bind a just-created kthread to a cpu.
+ * @k: thread created by kthread_create().
+ * @cpu: cpu (might not be online, must be possible) for @k to run on.
+ *
+ * Description: This function is equivalent to set_cpus_allowed(),
+ * except that @cpu doesn't need to be online, and the thread must be
+ * stopped (i.e., just returned from kthread_create().
+ */
 void kthread_bind(struct task_struct *k, unsigned int cpu)
 {
 	BUG_ON(k->state != TASK_INTERRUPTIBLE);
@@ -166,12 +201,36 @@
 }
 EXPORT_SYMBOL(kthread_bind);
 
+/**
+ * kthread_stop - stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ *
+ * Sets kthread_should_stop() for @k to return true, wakes it, and
+ * waits for it to exit.  Your threadfn() must not call do_exit()
+ * itself if you use this function!  This can also be called after
+ * kthread_create() instead of calling wake_up_process(): the thread
+ * will exit without calling threadfn().
+ *
+ * Returns the result of threadfn(), or %-EINTR if wake_up_process()
+ * was never called.
+ */
 int kthread_stop(struct task_struct *k)
 {
 	return kthread_stop_sem(k, NULL);
 }
 EXPORT_SYMBOL(kthread_stop);
 
+/**
+ * kthread_stop_sem - stop a thread created by kthread_create().
+ * @k: thread created by kthread_create().
+ * @s: semaphore that @k waits on while idle.
+ *
+ * Does essentially the same thing as kthread_stop() above, but wakes
+ * @k by calling up(@s).
+ *
+ * Returns the result of threadfn(), or %-EINTR if wake_up_process()
+ * was never called.
+ */
 int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
 {
 	int ret;
@@ -210,5 +269,5 @@
 
 	return 0;
 }
-core_initcall(helper_init);
 
+core_initcall(helper_init);
diff --git a/kernel/module.c b/kernel/module.c
index bbe0486..10e5b87 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -40,9 +40,11 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/mutex.h>
+#include <linux/unwind.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
+#include <linux/license.h>
 
 #if 0
 #define DEBUGP printk
@@ -1051,6 +1053,8 @@
 	remove_sect_attrs(mod);
 	mod_kobject_remove(mod);
 
+	unwind_remove_table(mod->unwind_info, 0);
+
 	/* Arch-specific cleanup. */
 	module_arch_cleanup(mod);
 
@@ -1248,16 +1252,6 @@
 	}
 }
 
-static inline int license_is_gpl_compatible(const char *license)
-{
-	return (strcmp(license, "GPL") == 0
-		|| strcmp(license, "GPL v2") == 0
-		|| strcmp(license, "GPL and additional rights") == 0
-		|| strcmp(license, "Dual BSD/GPL") == 0
-		|| strcmp(license, "Dual MIT/GPL") == 0
-		|| strcmp(license, "Dual MPL/GPL") == 0);
-}
-
 static void set_license(struct module *mod, const char *license)
 {
 	if (!license)
@@ -1326,7 +1320,7 @@
 	if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
 		return 1;
 	else
-		if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
+		if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
 			return 1;
 		else
 			return 0;
@@ -1412,7 +1406,7 @@
 	unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
 		exportindex, modindex, obsparmindex, infoindex, gplindex,
 		crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
-		gplfuturecrcindex;
+		gplfuturecrcindex, unwindex = 0;
 	struct module *mod;
 	long err = 0;
 	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1502,6 +1496,9 @@
 	versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
 	infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
 	pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
+#ifdef ARCH_UNWIND_SECTION_NAME
+	unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
+#endif
 
 	/* Don't keep modinfo section */
 	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1510,6 +1507,8 @@
 	sechdrs[symindex].sh_flags |= SHF_ALLOC;
 	sechdrs[strindex].sh_flags |= SHF_ALLOC;
 #endif
+	if (unwindex)
+		sechdrs[unwindex].sh_flags |= SHF_ALLOC;
 
 	/* Check module struct version now, before we try to use module. */
 	if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1738,6 +1737,11 @@
 		goto arch_cleanup;
 	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
+	/* Size of section 0 is 0, so this works well if no unwind info. */
+	mod->unwind_info = unwind_add_table(mod,
+	                                    (void *)sechdrs[unwindex].sh_addr,
+	                                    sechdrs[unwindex].sh_size);
+
 	/* Get rid of temporary copy */
 	vfree(hdr);
 
@@ -1836,6 +1840,7 @@
 	mod->state = MODULE_STATE_LIVE;
 	/* Drop initial reference. */
 	module_put(mod);
+	unwind_remove_table(mod->unwind_info, 1);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c
index f4913c3..036b628 100644
--- a/kernel/mutex-debug.c
+++ b/kernel/mutex-debug.c
@@ -153,13 +153,13 @@
 			continue;
 		count++;
 		cursor = curr->next;
-		debug_spin_lock_restore(&debug_mutex_lock, flags);
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);
 
 		printk("\n#%03d:            ", count);
 		printk_lock(lock, filter ? 0 : 1);
 		goto next;
 	}
-	debug_spin_lock_restore(&debug_mutex_lock, flags);
+	debug_spin_unlock_restore(&debug_mutex_lock, flags);
 	printk("\n");
 }
 
@@ -316,7 +316,7 @@
 			continue;
 		list_del_init(curr);
 		DEBUG_OFF();
-		debug_spin_lock_restore(&debug_mutex_lock, flags);
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);
 
 		printk("BUG: %s/%d, lock held at task exit time!\n",
 			task->comm, task->pid);
@@ -325,7 +325,7 @@
 			printk("exiting task is not even the owner??\n");
 		return;
 	}
-	debug_spin_lock_restore(&debug_mutex_lock, flags);
+	debug_spin_unlock_restore(&debug_mutex_lock, flags);
 }
 
 /*
@@ -352,7 +352,7 @@
 			continue;
 		list_del_init(curr);
 		DEBUG_OFF();
-		debug_spin_lock_restore(&debug_mutex_lock, flags);
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);
 
 		printk("BUG: %s/%d, active lock [%p(%p-%p)] freed!\n",
 			current->comm, current->pid, lock, from, to);
@@ -362,7 +362,7 @@
 			printk("freeing task is not even the owner??\n");
 		return;
 	}
-	debug_spin_lock_restore(&debug_mutex_lock, flags);
+	debug_spin_unlock_restore(&debug_mutex_lock, flags);
 }
 
 /*
diff --git a/kernel/mutex-debug.h b/kernel/mutex-debug.h
index fd38405..a5196c3 100644
--- a/kernel/mutex-debug.h
+++ b/kernel/mutex-debug.h
@@ -46,21 +46,6 @@
 extern void debug_mutex_unlock(struct mutex *lock);
 extern void debug_mutex_init(struct mutex *lock, const char *name);
 
-#define debug_spin_lock(lock)				\
-	do {						\
-		local_irq_disable();			\
-		if (debug_mutex_on)			\
-			spin_lock(lock);		\
-	} while (0)
-
-#define debug_spin_unlock(lock)				\
-	do {						\
-		if (debug_mutex_on)			\
-			spin_unlock(lock);		\
-		local_irq_enable();			\
-		preempt_check_resched();		\
-	} while (0)
-
 #define debug_spin_lock_save(lock, flags)		\
 	do {						\
 		local_irq_save(flags);			\
@@ -68,7 +53,7 @@
 			spin_lock(lock);		\
 	} while (0)
 
-#define debug_spin_lock_restore(lock, flags)		\
+#define debug_spin_unlock_restore(lock, flags)		\
 	do {						\
 		if (debug_mutex_on)			\
 			spin_unlock(lock);		\
@@ -76,20 +61,20 @@
 		preempt_check_resched();		\
 	} while (0)
 
-#define spin_lock_mutex(lock)				\
+#define spin_lock_mutex(lock, flags)			\
 	do {						\
 		struct mutex *l = container_of(lock, struct mutex, wait_lock); \
 							\
 		DEBUG_WARN_ON(in_interrupt());		\
-		debug_spin_lock(&debug_mutex_lock);	\
+		debug_spin_lock_save(&debug_mutex_lock, flags); \
 		spin_lock(lock);			\
 		DEBUG_WARN_ON(l->magic != l);		\
 	} while (0)
 
-#define spin_unlock_mutex(lock)				\
+#define spin_unlock_mutex(lock, flags)			\
 	do {						\
 		spin_unlock(lock);			\
-		debug_spin_unlock(&debug_mutex_lock);	\
+		debug_spin_unlock_restore(&debug_mutex_lock, flags);	\
 	} while (0)
 
 #define DEBUG_OFF()					\
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 5449b21..7043db2 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -125,10 +125,11 @@
 	struct task_struct *task = current;
 	struct mutex_waiter waiter;
 	unsigned int old_val;
+	unsigned long flags;
 
 	debug_mutex_init_waiter(&waiter);
 
-	spin_lock_mutex(&lock->wait_lock);
+	spin_lock_mutex(&lock->wait_lock, flags);
 
 	debug_mutex_add_waiter(lock, &waiter, task->thread_info, ip);
 
@@ -157,7 +158,7 @@
 		if (unlikely(state == TASK_INTERRUPTIBLE &&
 						signal_pending(task))) {
 			mutex_remove_waiter(lock, &waiter, task->thread_info);
-			spin_unlock_mutex(&lock->wait_lock);
+			spin_unlock_mutex(&lock->wait_lock, flags);
 
 			debug_mutex_free_waiter(&waiter);
 			return -EINTR;
@@ -165,9 +166,9 @@
 		__set_task_state(task, state);
 
 		/* didnt get the lock, go to sleep: */
-		spin_unlock_mutex(&lock->wait_lock);
+		spin_unlock_mutex(&lock->wait_lock, flags);
 		schedule();
-		spin_lock_mutex(&lock->wait_lock);
+		spin_lock_mutex(&lock->wait_lock, flags);
 	}
 
 	/* got the lock - rejoice! */
@@ -178,7 +179,7 @@
 	if (likely(list_empty(&lock->wait_list)))
 		atomic_set(&lock->count, 0);
 
-	spin_unlock_mutex(&lock->wait_lock);
+	spin_unlock_mutex(&lock->wait_lock, flags);
 
 	debug_mutex_free_waiter(&waiter);
 
@@ -203,10 +204,11 @@
 __mutex_unlock_slowpath(atomic_t *lock_count __IP_DECL__)
 {
 	struct mutex *lock = container_of(lock_count, struct mutex, count);
+	unsigned long flags;
 
 	DEBUG_WARN_ON(lock->owner != current_thread_info());
 
-	spin_lock_mutex(&lock->wait_lock);
+	spin_lock_mutex(&lock->wait_lock, flags);
 
 	/*
 	 * some architectures leave the lock unlocked in the fastpath failure
@@ -231,7 +233,7 @@
 
 	debug_mutex_clear_owner(lock);
 
-	spin_unlock_mutex(&lock->wait_lock);
+	spin_unlock_mutex(&lock->wait_lock, flags);
 }
 
 /*
@@ -276,9 +278,10 @@
 static inline int __mutex_trylock_slowpath(atomic_t *lock_count)
 {
 	struct mutex *lock = container_of(lock_count, struct mutex, count);
+	unsigned long flags;
 	int prev;
 
-	spin_lock_mutex(&lock->wait_lock);
+	spin_lock_mutex(&lock->wait_lock, flags);
 
 	prev = atomic_xchg(&lock->count, -1);
 	if (likely(prev == 1))
@@ -287,7 +290,7 @@
 	if (likely(list_empty(&lock->wait_list)))
 		atomic_set(&lock->count, 0);
 
-	spin_unlock_mutex(&lock->wait_lock);
+	spin_unlock_mutex(&lock->wait_lock, flags);
 
 	return prev == 1;
 }
diff --git a/kernel/mutex.h b/kernel/mutex.h
index 00fe84e..0691899 100644
--- a/kernel/mutex.h
+++ b/kernel/mutex.h
@@ -9,8 +9,10 @@
  * !CONFIG_DEBUG_MUTEXES case. Most of them are NOPs:
  */
 
-#define spin_lock_mutex(lock)			spin_lock(lock)
-#define spin_unlock_mutex(lock)			spin_unlock(lock)
+#define spin_lock_mutex(lock, flags) \
+		do { spin_lock(lock); (void)(flags); } while (0)
+#define spin_unlock_mutex(lock, flags) \
+		do { spin_unlock(lock); (void)(flags); } while (0)
 #define mutex_remove_waiter(lock, waiter, ti) \
 		__list_del((waiter)->list.prev, (waiter)->list.next)
 
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index cdf315e..fc311a4 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -38,7 +38,7 @@
 
 config PM_TRACE
 	bool "Suspend/resume event tracing"
-	depends on PM && PM_DEBUG && X86
+	depends on PM && PM_DEBUG && X86_32
 	default y
 	---help---
 	This enables some cheesy code to save the last PM event point in the
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 81d4d98..e13e740 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -231,7 +231,7 @@
 late_initcall(software_resume);
 
 
-static char * pm_disk_modes[] = {
+static const char * const pm_disk_modes[] = {
 	[PM_DISK_FIRMWARE]	= "firmware",
 	[PM_DISK_PLATFORM]	= "platform",
 	[PM_DISK_SHUTDOWN]	= "shutdown",
diff --git a/kernel/power/main.c b/kernel/power/main.c
index cdf0f07..6d295c7 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -145,7 +145,7 @@
 
 
 
-static char *pm_states[PM_SUSPEND_MAX] = {
+static const char * const pm_states[PM_SUSPEND_MAX] = {
 	[PM_SUSPEND_STANDBY]	= "standby",
 	[PM_SUSPEND_MEM]	= "mem",
 #ifdef CONFIG_SOFTWARE_SUSPEND
@@ -262,7 +262,7 @@
 static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
 {
 	suspend_state_t state = PM_SUSPEND_STANDBY;
-	char ** s;
+	const char * const *s;
 	char *p;
 	int error;
 	int len;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 98c4142..57a7929 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -105,10 +105,6 @@
 extern unsigned long alloc_swap_page(int swap, struct bitmap_page *bitmap);
 extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
 
-extern unsigned int count_special_pages(void);
-extern int save_special_mem(void);
-extern int restore_special_mem(void);
-
 extern int swsusp_check(void);
 extern int swsusp_shrink_memory(void);
 extern void swsusp_free(void);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 3d92841..24c96f3 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -39,90 +39,8 @@
 static unsigned int nr_meta_pages;
 static unsigned long *buffer;
 
-struct arch_saveable_page {
-	unsigned long start;
-	unsigned long end;
-	char *data;
-	struct arch_saveable_page *next;
-};
-static struct arch_saveable_page *arch_pages;
-
-int swsusp_add_arch_pages(unsigned long start, unsigned long end)
-{
-	struct arch_saveable_page *tmp;
-
-	while (start < end) {
-		tmp = kzalloc(sizeof(struct arch_saveable_page), GFP_KERNEL);
-		if (!tmp)
-			return -ENOMEM;
-		tmp->start = start;
-		tmp->end = ((start >> PAGE_SHIFT) + 1) << PAGE_SHIFT;
-		if (tmp->end > end)
-			tmp->end = end;
-		tmp->next = arch_pages;
-		start = tmp->end;
-		arch_pages = tmp;
-	}
-	return 0;
-}
-
-static unsigned int count_arch_pages(void)
-{
-	unsigned int count = 0;
-	struct arch_saveable_page *tmp = arch_pages;
-	while (tmp) {
-		count++;
-		tmp = tmp->next;
-	}
-	return count;
-}
-
-static int save_arch_mem(void)
-{
-	char *kaddr;
-	struct arch_saveable_page *tmp = arch_pages;
-	int offset;
-
-	pr_debug("swsusp: Saving arch specific memory");
-	while (tmp) {
-		tmp->data = (char *)__get_free_page(GFP_ATOMIC);
-		if (!tmp->data)
-			return -ENOMEM;
-		offset = tmp->start - (tmp->start & PAGE_MASK);
-		/* arch pages might haven't a 'struct page' */
-		kaddr = kmap_atomic_pfn(tmp->start >> PAGE_SHIFT, KM_USER0);
-		memcpy(tmp->data + offset, kaddr + offset,
-			tmp->end - tmp->start);
-		kunmap_atomic(kaddr, KM_USER0);
-
-		tmp = tmp->next;
-	}
-	return 0;
-}
-
-static int restore_arch_mem(void)
-{
-	char *kaddr;
-	struct arch_saveable_page *tmp = arch_pages;
-	int offset;
-
-	while (tmp) {
-		if (!tmp->data)
-			continue;
-		offset = tmp->start - (tmp->start & PAGE_MASK);
-		kaddr = kmap_atomic_pfn(tmp->start >> PAGE_SHIFT, KM_USER0);
-		memcpy(kaddr + offset, tmp->data + offset,
-			tmp->end - tmp->start);
-		kunmap_atomic(kaddr, KM_USER0);
-		free_page((long)tmp->data);
-		tmp->data = NULL;
-		tmp = tmp->next;
-	}
-	return 0;
-}
-
 #ifdef CONFIG_HIGHMEM
-static unsigned int count_highmem_pages(void)
+unsigned int count_highmem_pages(void)
 {
 	struct zone *zone;
 	unsigned long zone_pfn;
@@ -199,7 +117,7 @@
 	return 0;
 }
 
-static int save_highmem(void)
+int save_highmem(void)
 {
 	struct zone *zone;
 	int res = 0;
@@ -216,7 +134,7 @@
 	return 0;
 }
 
-static int restore_highmem(void)
+int restore_highmem(void)
 {
 	printk("swsusp: Restoring Highmem\n");
 	while (highmem_copy) {
@@ -238,29 +156,6 @@
 static inline int restore_highmem(void) {return 0;}
 #endif
 
-unsigned int count_special_pages(void)
-{
-	return count_arch_pages() + count_highmem_pages();
-}
-
-int save_special_mem(void)
-{
-	int ret;
-	ret = save_arch_mem();
-	if (!ret)
-		ret = save_highmem();
-	return ret;
-}
-
-int restore_special_mem(void)
-{
-	int ret;
-	ret = restore_arch_mem();
-	if (!ret)
-		ret = restore_highmem();
-	return ret;
-}
-
 static int pfn_is_nosave(unsigned long pfn)
 {
 	unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
@@ -286,6 +181,7 @@
 		return 0;
 
 	page = pfn_to_page(pfn);
+	BUG_ON(PageReserved(page) && PageNosave(page));
 	if (PageNosave(page))
 		return 0;
 	if (PageReserved(page) && pfn_is_nosave(pfn))
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index f0ee4e7..17f669c 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -62,6 +62,16 @@
 
 int in_suspend __nosavedata = 0;
 
+#ifdef CONFIG_HIGHMEM
+unsigned int count_highmem_pages(void);
+int save_highmem(void);
+int restore_highmem(void);
+#else
+static inline int save_highmem(void) { return 0; }
+static inline int restore_highmem(void) { return 0; }
+static inline unsigned int count_highmem_pages(void) { return 0; }
+#endif
+
 /**
  *	The following functions are used for tracing the allocated
  *	swap pages, so that they can be freed in case of an error.
@@ -182,7 +192,7 @@
 
 	printk("Shrinking memory...  ");
 	do {
-		size = 2 * count_special_pages();
+		size = 2 * count_highmem_pages();
 		size += size / 50 + count_data_pages();
 		size += (size + PBES_PER_PAGE - 1) / PBES_PER_PAGE +
 			PAGES_FOR_IO;
@@ -226,7 +236,7 @@
 		goto Enable_irqs;
 	}
 
-	if ((error = save_special_mem())) {
+	if ((error = save_highmem())) {
 		printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
 		goto Restore_highmem;
 	}
@@ -237,7 +247,7 @@
 	/* Restore control flow magically appears here */
 	restore_processor_state();
 Restore_highmem:
-	restore_special_mem();
+	restore_highmem();
 	device_power_up();
 Enable_irqs:
 	local_irq_enable();
@@ -263,7 +273,7 @@
 	 */
 	swsusp_free();
 	restore_processor_state();
-	restore_special_mem();
+	restore_highmem();
 	touch_softlockup_watchdog();
 	device_power_up();
 	local_irq_enable();
diff --git a/kernel/printk.c b/kernel/printk.c
index 19a9556..95b7fe1 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -24,6 +24,7 @@
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/interrupt.h>			/* For in_interrupt() */
 #include <linux/config.h>
 #include <linux/delay.h>
@@ -327,7 +328,9 @@
 	struct console *con;
 
 	for (con = console_drivers; con; con = con->next) {
-		if ((con->flags & CON_ENABLED) && con->write)
+		if ((con->flags & CON_ENABLED) && con->write &&
+				(cpu_online(smp_processor_id()) ||
+				(con->flags & CON_ANYTIME)))
 			con->write(con, &LOG_BUF(start), end - start);
 	}
 }
@@ -437,6 +440,7 @@
 #else
 static int printk_time = 0;
 #endif
+module_param(printk_time, int, S_IRUGO | S_IWUSR);
 
 static int __init printk_time_setup(char *str)
 {
@@ -453,6 +457,18 @@
 	return sched_clock();
 }
 
+/* Check if we have any console registered that can be called early in boot. */
+static int have_callable_console(void)
+{
+	struct console *con;
+
+	for (con = console_drivers; con; con = con->next)
+		if (con->flags & CON_ANYTIME)
+			return 1;
+
+	return 0;
+}
+
 /**
  * printk - print a kernel message
  * @fmt: format string
@@ -566,27 +582,29 @@
 			log_level_unknown = 1;
 	}
 
-	if (!cpu_online(smp_processor_id())) {
-		/*
-		 * Some console drivers may assume that per-cpu resources have
-		 * been allocated.  So don't allow them to be called by this
-		 * CPU until it is officially up.  We shouldn't be calling into
-		 * random console drivers on a CPU which doesn't exist yet..
-		 */
-		printk_cpu = UINT_MAX;
-		spin_unlock_irqrestore(&logbuf_lock, flags);
-		goto out;
-	}
 	if (!down_trylock(&console_sem)) {
-		console_locked = 1;
 		/*
-		 * We own the drivers.  We can drop the spinlock and let
-		 * release_console_sem() print the text
+		 * We own the drivers.  We can drop the spinlock and
+		 * let release_console_sem() print the text, maybe ...
 		 */
+		console_locked = 1;
 		printk_cpu = UINT_MAX;
 		spin_unlock_irqrestore(&logbuf_lock, flags);
-		console_may_schedule = 0;
-		release_console_sem();
+
+		/*
+		 * Console drivers may assume that per-cpu resources have
+		 * been allocated. So unless they're explicitly marked as
+		 * being able to cope (CON_ANYTIME) don't call them until
+		 * this CPU is officially up.
+		 */
+		if (cpu_online(smp_processor_id()) || have_callable_console()) {
+			console_may_schedule = 0;
+			release_console_sem();
+		} else {
+			/* Release by hand to avoid flushing the buffer. */
+			console_locked = 0;
+			up(&console_sem);
+		}
 	} else {
 		/*
 		 * Someone else owns the drivers.  We drop the spinlock, which
@@ -596,7 +614,7 @@
 		printk_cpu = UINT_MAX;
 		spin_unlock_irqrestore(&logbuf_lock, flags);
 	}
-out:
+
 	preempt_enable();
 	return printed_len;
 }
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 921c22a..335c5b9 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -120,8 +120,18 @@
 
 static int may_attach(struct task_struct *task)
 {
-	if (!task->mm)
-		return -EPERM;
+	/* May we inspect the given task?
+	 * This check is used both for attaching with ptrace
+	 * and for allowing access to sensitive information in /proc.
+	 *
+	 * ptrace_attach denies several cases that /proc allows
+	 * because setting up the necessary parent/child relationship
+	 * or halting the specified task is impossible.
+	 */
+	int dumpable = 0;
+	/* Don't let security modules deny introspection */
+	if (task == current)
+		return 0;
 	if (((current->uid != task->euid) ||
 	     (current->uid != task->suid) ||
 	     (current->uid != task->uid) ||
@@ -130,7 +140,9 @@
 	     (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
 		return -EPERM;
 	smp_rmb();
-	if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+	if (task->mm)
+		dumpable = task->mm->dumpable;
+	if (!dumpable && !capable(CAP_SYS_PTRACE))
 		return -EPERM;
 
 	return security_ptrace(current, task);
@@ -176,6 +188,8 @@
 		goto repeat;
 	}
 
+	if (!task->mm)
+		goto bad;
 	/* the same process cannot be attached many times */
 	if (task->ptrace & PT_PTRACED)
 		goto bad;
@@ -200,7 +214,7 @@
 	return retval;
 }
 
-void __ptrace_detach(struct task_struct *child, unsigned int data)
+static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
 {
 	child->exit_code = data;
 	/* .. re-parent .. */
@@ -219,6 +233,7 @@
 	ptrace_disable(child);
 
 	write_lock_irq(&tasklist_lock);
+	/* protect against de_thread()->release_task() */
 	if (child->ptrace)
 		__ptrace_detach(child, data);
 	write_unlock_irq(&tasklist_lock);
diff --git a/kernel/sched.c b/kernel/sched.c
index 5dbc426..a856040 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -818,6 +818,11 @@
  * the target CPU.
  */
 #ifdef CONFIG_SMP
+
+#ifndef tsk_is_polling
+#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
+#endif
+
 static void resched_task(task_t *p)
 {
 	int cpu;
@@ -833,9 +838,9 @@
 	if (cpu == smp_processor_id())
 		return;
 
-	/* NEED_RESCHED must be visible before we test POLLING_NRFLAG */
+	/* NEED_RESCHED must be visible before we test polling */
 	smp_mb();
-	if (!test_tsk_thread_flag(p, TIF_POLLING_NRFLAG))
+	if (!tsk_is_polling(p))
 		smp_send_reschedule(cpu);
 }
 #else
@@ -4152,7 +4157,7 @@
  */
 void __sched io_schedule(void)
 {
-	struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
+	struct runqueue *rq = &__raw_get_cpu_var(runqueues);
 
 	atomic_inc(&rq->nr_iowait);
 	schedule();
@@ -4163,7 +4168,7 @@
 
 long __sched io_schedule_timeout(long timeout)
 {
-	struct runqueue *rq = &per_cpu(runqueues, raw_smp_processor_id());
+	struct runqueue *rq = &__raw_get_cpu_var(runqueues);
 	long ret;
 
 	atomic_inc(&rq->nr_iowait);
@@ -4247,7 +4252,7 @@
 	if (retval)
 		goto out_unlock;
 
-	jiffies_to_timespec(p->policy & SCHED_FIFO ?
+	jiffies_to_timespec(p->policy == SCHED_FIFO ?
 				0 : task_timeslice(p), &t);
 	read_unlock(&tasklist_lock);
 	retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -4756,6 +4761,8 @@
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_UP_CANCELED:
+		if (!cpu_rq(cpu)->migration_thread)
+			break;
 		/* Unbind it from offline cpu so it can run.  Fall thru. */
 		kthread_bind(cpu_rq(cpu)->migration_thread,
 			     any_online_cpu(cpu_online_map));
diff --git a/kernel/signal.c b/kernel/signal.c
index 1b3c921..52adf53 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1531,6 +1531,35 @@
 	spin_unlock_irqrestore(&sighand->siglock, flags);
 }
 
+static inline int may_ptrace_stop(void)
+{
+	if (!likely(current->ptrace & PT_PTRACED))
+		return 0;
+
+	if (unlikely(current->parent == current->real_parent &&
+		    (current->ptrace & PT_ATTACHED)))
+		return 0;
+
+	if (unlikely(current->signal == current->parent->signal) &&
+	    unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))
+		return 0;
+
+	/*
+	 * Are we in the middle of do_coredump?
+	 * If so and our tracer is also part of the coredump stopping
+	 * is a deadlock situation, and pointless because our tracer
+	 * is dead so don't allow us to stop.
+	 * If SIGKILL was already sent before the caller unlocked
+	 * ->siglock we must see ->core_waiters != 0. Otherwise it
+	 * is safe to enter schedule().
+	 */
+	if (unlikely(current->mm->core_waiters) &&
+	    unlikely(current->mm == current->parent->mm))
+		return 0;
+
+	return 1;
+}
+
 /*
  * This must be called with current->sighand->siglock held.
  *
@@ -1559,11 +1588,7 @@
 	spin_unlock_irq(&current->sighand->siglock);
 	try_to_freeze();
 	read_lock(&tasklist_lock);
-	if (likely(current->ptrace & PT_PTRACED) &&
-	    likely(current->parent != current->real_parent ||
-		   !(current->ptrace & PT_ATTACHED)) &&
-	    (likely(current->parent->signal != current->signal) ||
-	     !unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) {
+	if (may_ptrace_stop()) {
 		do_notify_parent_cldstop(current, CLD_TRAPPED);
 		read_unlock(&tasklist_lock);
 		schedule();
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 336f92d..9e2f1c6 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -470,6 +470,8 @@
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_UP_CANCELED:
+		if (!per_cpu(ksoftirqd, hotcpu))
+			break;
 		/* Unbind so it can run.  Fall thru. */
 		kthread_bind(per_cpu(ksoftirqd, hotcpu),
 			     any_online_cpu(cpu_online_map));
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 14c7faf..b5c3b94 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -36,7 +36,7 @@
 
 void touch_softlockup_watchdog(void)
 {
-	per_cpu(touch_timestamp, raw_smp_processor_id()) = jiffies;
+	__raw_get_cpu_var(touch_timestamp) = jiffies;
 }
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
@@ -127,6 +127,8 @@
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_UP_CANCELED:
+		if (!per_cpu(watchdog_task, hotcpu))
+			break;
 		/* Unbind so it can run.  Fall thru. */
 		kthread_bind(per_cpu(watchdog_task, hotcpu),
 			     any_online_cpu(cpu_online_map));
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index dcfb5d7..2c0aacc 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -4,6 +4,7 @@
 #include <linux/cpu.h>
 #include <linux/err.h>
 #include <linux/syscalls.h>
+#include <linux/kthread.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -25,13 +26,11 @@
 static atomic_t stopmachine_thread_ack;
 static DECLARE_MUTEX(stopmachine_mutex);
 
-static int stopmachine(void *cpu)
+static int stopmachine(void *unused)
 {
 	int irqs_disabled = 0;
 	int prepared = 0;
 
-	set_cpus_allowed(current, cpumask_of_cpu((int)(long)cpu));
-
 	/* Ack: we are alive */
 	smp_mb(); /* Theoretically the ack = 0 might not be on this CPU yet. */
 	atomic_inc(&stopmachine_thread_ack);
@@ -85,7 +84,8 @@
 
 static int stop_machine(void)
 {
-	int i, ret = 0;
+	int ret = 0;
+	unsigned int i;
 	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
 	/* One high-prio thread per cpu.  We'll do this one. */
@@ -96,11 +96,16 @@
 	stopmachine_state = STOPMACHINE_WAIT;
 
 	for_each_online_cpu(i) {
+		struct task_struct *tsk;
 		if (i == raw_smp_processor_id())
 			continue;
-		ret = kernel_thread(stopmachine, (void *)(long)i,CLONE_KERNEL);
-		if (ret < 0)
+		tsk = kthread_create(stopmachine, NULL, "stopmachine");
+		if (IS_ERR(tsk)) {
+			ret = PTR_ERR(tsk);
 			break;
+		}
+		kthread_bind(tsk, i);
+		wake_up_process(tsk);
 		stopmachine_num_threads++;
 	}
 
diff --git a/kernel/sys.c b/kernel/sys.c
index 90930b2..2d5179c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -137,14 +137,15 @@
 		unsigned long val, void *v)
 {
 	int ret = NOTIFY_DONE;
-	struct notifier_block *nb;
+	struct notifier_block *nb, *next_nb;
 
 	nb = rcu_dereference(*nl);
 	while (nb) {
+		next_nb = rcu_dereference(nb->next);
 		ret = nb->notifier_call(nb, val, v);
 		if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
 			break;
-		nb = rcu_dereference(nb->next);
+		nb = next_nb;
 	}
 	return ret;
 }
@@ -588,7 +589,7 @@
 }
 EXPORT_SYMBOL_GPL(emergency_restart);
 
-void kernel_restart_prepare(char *cmd)
+static void kernel_restart_prepare(char *cmd)
 {
 	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
 	system_state = SYSTEM_RESTART;
@@ -622,7 +623,7 @@
  *	Move into place and start executing a preloaded standalone
  *	executable.  If nothing was preloaded return an error.
  */
-void kernel_kexec(void)
+static void kernel_kexec(void)
 {
 #ifdef CONFIG_KEXEC
 	struct kimage *image;
@@ -636,7 +637,6 @@
 	machine_kexec(image);
 #endif
 }
-EXPORT_SYMBOL_GPL(kernel_kexec);
 
 void kernel_shutdown_prepare(enum system_states state)
 {
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index eb8bd21..f1a4eb1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -73,6 +73,7 @@
 extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
+extern int compat_log;
 
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
 int unknown_nmi_panic;
@@ -143,7 +144,6 @@
 
 static ctl_table kern_table[];
 static ctl_table vm_table[];
-static ctl_table proc_table[];
 static ctl_table fs_table[];
 static ctl_table debug_table[];
 static ctl_table dev_table[];
@@ -203,12 +203,6 @@
 	},
 #endif
 	{
-		.ctl_name	= CTL_PROC,
-		.procname	= "proc",
-		.mode		= 0555,
-		.child		= proc_table,
-	},
-	{
 		.ctl_name	= CTL_FS,
 		.procname	= "fs",
 		.mode		= 0555,
@@ -684,6 +678,16 @@
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+#ifdef CONFIG_COMPAT
+	{
+		.ctl_name	= KERN_COMPAT_LOG,
+		.procname	= "compat-log",
+		.data		= &compat_log,
+		.maxlen		= sizeof (int),
+	 	.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
 	{ .ctl_name = 0 }
 };
 
@@ -927,10 +931,6 @@
 	{ .ctl_name = 0 }
 };
 
-static ctl_table proc_table[] = {
-	{ .ctl_name = 0 }
-};
-
 static ctl_table fs_table[] = {
 	{
 		.ctl_name	= FS_NRINODE,
diff --git a/kernel/time.c b/kernel/time.c
index b00ddc7..5bd4897 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -523,6 +523,7 @@
 
 
 #else
+#ifndef CONFIG_GENERIC_TIME
 /*
  * Simulate gettimeofday using do_gettimeofday which only allows a timeval
  * and therefore only yields usec accuracy
@@ -537,6 +538,7 @@
 }
 EXPORT_SYMBOL_GPL(getnstimeofday);
 #endif
+#endif
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
new file mode 100644
index 0000000..e1dfd8e
--- /dev/null
+++ b/kernel/time/Makefile
@@ -0,0 +1 @@
+obj-y += clocksource.o jiffies.o
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
new file mode 100644
index 0000000..74eca59
--- /dev/null
+++ b/kernel/time/clocksource.c
@@ -0,0 +1,349 @@
+/*
+ * linux/kernel/time/clocksource.c
+ *
+ * This file contains the functions which manage clocksource drivers.
+ *
+ * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * TODO WishList:
+ *   o Allow clocksource drivers to be unregistered
+ *   o get rid of clocksource_jiffies extern
+ */
+
+#include <linux/clocksource.h>
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+/* XXX - Would like a better way for initializing curr_clocksource */
+extern struct clocksource clocksource_jiffies;
+
+/*[Clocksource internal variables]---------
+ * curr_clocksource:
+ *	currently selected clocksource. Initialized to clocksource_jiffies.
+ * next_clocksource:
+ *	pending next selected clocksource.
+ * clocksource_list:
+ *	linked list with the registered clocksources
+ * clocksource_lock:
+ *	protects manipulations to curr_clocksource and next_clocksource
+ *	and the clocksource_list
+ * override_name:
+ *	Name of the user-specified clocksource.
+ */
+static struct clocksource *curr_clocksource = &clocksource_jiffies;
+static struct clocksource *next_clocksource;
+static LIST_HEAD(clocksource_list);
+static DEFINE_SPINLOCK(clocksource_lock);
+static char override_name[32];
+static int finished_booting;
+
+/* clocksource_done_booting - Called near the end of bootup
+ *
+ * Hack to avoid lots of clocksource churn at boot time
+ */
+static int __init clocksource_done_booting(void)
+{
+	finished_booting = 1;
+	return 0;
+}
+
+late_initcall(clocksource_done_booting);
+
+/**
+ * clocksource_get_next - Returns the selected clocksource
+ *
+ */
+struct clocksource *clocksource_get_next(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocksource_lock, flags);
+	if (next_clocksource && finished_booting) {
+		curr_clocksource = next_clocksource;
+		next_clocksource = NULL;
+	}
+	spin_unlock_irqrestore(&clocksource_lock, flags);
+
+	return curr_clocksource;
+}
+
+/**
+ * select_clocksource - Finds the best registered clocksource.
+ *
+ * Private function. Must hold clocksource_lock when called.
+ *
+ * Looks through the list of registered clocksources, returning
+ * the one with the highest rating value. If there is a clocksource
+ * name that matches the override string, it returns that clocksource.
+ */
+static struct clocksource *select_clocksource(void)
+{
+	struct clocksource *best = NULL;
+	struct list_head *tmp;
+
+	list_for_each(tmp, &clocksource_list) {
+		struct clocksource *src;
+
+		src = list_entry(tmp, struct clocksource, list);
+		if (!best)
+			best = src;
+
+		/* check for override: */
+		if (strlen(src->name) == strlen(override_name) &&
+		    !strcmp(src->name, override_name)) {
+			best = src;
+			break;
+		}
+		/* pick the highest rating: */
+		if (src->rating > best->rating)
+		 	best = src;
+	}
+
+	return best;
+}
+
+/**
+ * is_registered_source - Checks if clocksource is registered
+ * @c:		pointer to a clocksource
+ *
+ * Private helper function. Must hold clocksource_lock when called.
+ *
+ * Returns one if the clocksource is already registered, zero otherwise.
+ */
+static int is_registered_source(struct clocksource *c)
+{
+	int len = strlen(c->name);
+	struct list_head *tmp;
+
+	list_for_each(tmp, &clocksource_list) {
+		struct clocksource *src;
+
+		src = list_entry(tmp, struct clocksource, list);
+		if (strlen(src->name) == len &&	!strcmp(src->name, c->name))
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * clocksource_register - Used to install new clocksources
+ * @t:		clocksource to be registered
+ *
+ * Returns -EBUSY if registration fails, zero otherwise.
+ */
+int clocksource_register(struct clocksource *c)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocksource_lock, flags);
+	/* check if clocksource is already registered */
+	if (is_registered_source(c)) {
+		printk("register_clocksource: Cannot register %s. "
+			"Already registered!", c->name);
+		ret = -EBUSY;
+	} else {
+		/* register it */
+ 		list_add(&c->list, &clocksource_list);
+		/* scan the registered clocksources, and pick the best one */
+		next_clocksource = select_clocksource();
+	}
+	spin_unlock_irqrestore(&clocksource_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(clocksource_register);
+
+/**
+ * clocksource_reselect - Rescan list for next clocksource
+ *
+ * A quick helper function to be used if a clocksource changes its
+ * rating. Forces the clocksource list to be re-scanned for the best
+ * clocksource.
+ */
+void clocksource_reselect(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocksource_lock, flags);
+	next_clocksource = select_clocksource();
+	spin_unlock_irqrestore(&clocksource_lock, flags);
+}
+EXPORT_SYMBOL(clocksource_reselect);
+
+/**
+ * sysfs_show_current_clocksources - sysfs interface for current clocksource
+ * @dev:	unused
+ * @buf:	char buffer to be filled with clocksource list
+ *
+ * Provides sysfs interface for listing current clocksource.
+ */
+static ssize_t
+sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
+{
+	char *curr = buf;
+
+	spin_lock_irq(&clocksource_lock);
+	curr += sprintf(curr, "%s ", curr_clocksource->name);
+	spin_unlock_irq(&clocksource_lock);
+
+	curr += sprintf(curr, "\n");
+
+	return curr - buf;
+}
+
+/**
+ * sysfs_override_clocksource - interface for manually overriding clocksource
+ * @dev:	unused
+ * @buf:	name of override clocksource
+ * @count:	length of buffer
+ *
+ * Takes input from sysfs interface for manually overriding the default
+ * clocksource selction.
+ */
+static ssize_t sysfs_override_clocksource(struct sys_device *dev,
+					  const char *buf, size_t count)
+{
+	size_t ret = count;
+	/* strings from sysfs write are not 0 terminated! */
+	if (count >= sizeof(override_name))
+		return -EINVAL;
+
+	/* strip of \n: */
+	if (buf[count-1] == '\n')
+		count--;
+	if (count < 1)
+		return -EINVAL;
+
+	spin_lock_irq(&clocksource_lock);
+
+	/* copy the name given: */
+	memcpy(override_name, buf, count);
+	override_name[count] = 0;
+
+	/* try to select it: */
+	next_clocksource = select_clocksource();
+
+	spin_unlock_irq(&clocksource_lock);
+
+	return ret;
+}
+
+/**
+ * sysfs_show_available_clocksources - sysfs interface for listing clocksource
+ * @dev:	unused
+ * @buf:	char buffer to be filled with clocksource list
+ *
+ * Provides sysfs interface for listing registered clocksources
+ */
+static ssize_t
+sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
+{
+	struct list_head *tmp;
+	char *curr = buf;
+
+	spin_lock_irq(&clocksource_lock);
+	list_for_each(tmp, &clocksource_list) {
+		struct clocksource *src;
+
+		src = list_entry(tmp, struct clocksource, list);
+		curr += sprintf(curr, "%s ", src->name);
+	}
+	spin_unlock_irq(&clocksource_lock);
+
+	curr += sprintf(curr, "\n");
+
+	return curr - buf;
+}
+
+/*
+ * Sysfs setup bits:
+ */
+static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,
+			sysfs_override_clocksource);
+
+static SYSDEV_ATTR(available_clocksource, 0600,
+			sysfs_show_available_clocksources, NULL);
+
+static struct sysdev_class clocksource_sysclass = {
+	set_kset_name("clocksource"),
+};
+
+static struct sys_device device_clocksource = {
+	.id	= 0,
+	.cls	= &clocksource_sysclass,
+};
+
+static int __init init_clocksource_sysfs(void)
+{
+	int error = sysdev_class_register(&clocksource_sysclass);
+
+	if (!error)
+		error = sysdev_register(&device_clocksource);
+	if (!error)
+		error = sysdev_create_file(
+				&device_clocksource,
+				&attr_current_clocksource);
+	if (!error)
+		error = sysdev_create_file(
+				&device_clocksource,
+				&attr_available_clocksource);
+	return error;
+}
+
+device_initcall(init_clocksource_sysfs);
+
+/**
+ * boot_override_clocksource - boot clock override
+ * @str:	override name
+ *
+ * Takes a clocksource= boot argument and uses it
+ * as the clocksource override name.
+ */
+static int __init boot_override_clocksource(char* str)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&clocksource_lock, flags);
+	if (str)
+		strlcpy(override_name, str, sizeof(override_name));
+	spin_unlock_irqrestore(&clocksource_lock, flags);
+	return 1;
+}
+
+__setup("clocksource=", boot_override_clocksource);
+
+/**
+ * boot_override_clock - Compatibility layer for deprecated boot option
+ * @str:	override name
+ *
+ * DEPRECATED! Takes a clock= boot argument and uses it
+ * as the clocksource override name
+ */
+static int __init boot_override_clock(char* str)
+{
+	if (!strcmp(str, "pmtmr")) {
+		printk("Warning: clock=pmtmr is deprecated. "
+			"Use clocksource=acpi_pm.\n");
+		return boot_override_clocksource("acpi_pm");
+	}
+	printk("Warning! clock= boot option is deprecated. "
+		"Use clocksource=xyz\n");
+	return boot_override_clocksource(str);
+}
+
+__setup("clock=", boot_override_clock);
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
new file mode 100644
index 0000000..126bb30
--- /dev/null
+++ b/kernel/time/jiffies.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+* linux/kernel/time/jiffies.c
+*
+* This file contains the jiffies based clocksource.
+*
+* Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* 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/clocksource.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+
+/* The Jiffies based clocksource is the lowest common
+ * denominator clock source which should function on
+ * all systems. It has the same coarse resolution as
+ * the timer interrupt frequency HZ and it suffers
+ * inaccuracies caused by missed or lost timer
+ * interrupts and the inability for the timer
+ * interrupt hardware to accuratly tick at the
+ * requested HZ value. It is also not reccomended
+ * for "tick-less" systems.
+ */
+#define NSEC_PER_JIFFY	((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ))
+
+/* Since jiffies uses a simple NSEC_PER_JIFFY multiplier
+ * conversion, the .shift value could be zero. However
+ * this would make NTP adjustments impossible as they are
+ * in units of 1/2^.shift. Thus we use JIFFIES_SHIFT to
+ * shift both the nominator and denominator the same
+ * amount, and give ntp adjustments in units of 1/2^8
+ *
+ * The value 8 is somewhat carefully chosen, as anything
+ * larger can result in overflows. NSEC_PER_JIFFY grows as
+ * HZ shrinks, so values greater then 8 overflow 32bits when
+ * HZ=100.
+ */
+#define JIFFIES_SHIFT	8
+
+static cycle_t jiffies_read(void)
+{
+	return (cycle_t) jiffies;
+}
+
+struct clocksource clocksource_jiffies = {
+	.name		= "jiffies",
+	.rating		= 0, /* lowest rating*/
+	.read		= jiffies_read,
+	.mask		= 0xffffffff, /*32bits*/
+	.mult		= NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
+	.shift		= JIFFIES_SHIFT,
+	.is_continuous	= 0, /* tick based, not free running */
+};
+
+static int __init init_jiffies_clocksource(void)
+{
+	return clocksource_register(&clocksource_jiffies);
+}
+
+module_init(init_jiffies_clocksource);
diff --git a/kernel/timer.c b/kernel/timer.c
index f35b393..5bb6b79 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -146,7 +146,7 @@
 void fastcall init_timer(struct timer_list *timer)
 {
 	timer->entry.next = NULL;
-	timer->base = per_cpu(tvec_bases, raw_smp_processor_id());
+	timer->base = __raw_get_cpu_var(tvec_bases);
 }
 EXPORT_SYMBOL(init_timer);
 
@@ -597,7 +597,6 @@
 long time_precision = 1;		/* clock precision (us)		*/
 long time_maxerror = NTP_PHASE_LIMIT;	/* maximum error (us)		*/
 long time_esterror = NTP_PHASE_LIMIT;	/* estimated error (us)		*/
-static long time_phase;			/* phase offset (scaled us)	*/
 long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC;
 					/* frequency offset (scaled ppm)*/
 static long time_adj;			/* tick adjust (scaled 1 / HZ)	*/
@@ -747,27 +746,14 @@
 }
 
 /* in the NTP reference this is called "hardclock()" */
-static void update_wall_time_one_tick(void)
+static void update_ntp_one_tick(void)
 {
-	long time_adjust_step, delta_nsec;
+	long time_adjust_step;
 
 	time_adjust_step = adjtime_adjustment();
 	if (time_adjust_step)
 		/* Reduce by this step the amount of time left  */
 		time_adjust -= time_adjust_step;
-	delta_nsec = tick_nsec + time_adjust_step * 1000;
-	/*
-	 * Advance the phase, once it gets to one microsecond, then
-	 * advance the tick more.
-	 */
-	time_phase += time_adj;
-	if ((time_phase >= FINENSEC) || (time_phase <= -FINENSEC)) {
-		long ltemp = shift_right(time_phase, (SHIFT_SCALE - 10));
-		time_phase -= ltemp << (SHIFT_SCALE - 10);
-		delta_nsec += ltemp;
-	}
-	xtime.tv_nsec += delta_nsec;
-	time_interpolator_update(delta_nsec);
 
 	/* Changes by adjtime() do not take effect till next tick. */
 	if (time_next_adjust != 0) {
@@ -780,36 +766,378 @@
  * Return how long ticks are at the moment, that is, how much time
  * update_wall_time_one_tick will add to xtime next time we call it
  * (assuming no calls to do_adjtimex in the meantime).
- * The return value is in fixed-point nanoseconds with SHIFT_SCALE-10
- * bits to the right of the binary point.
+ * The return value is in fixed-point nanoseconds shifted by the
+ * specified number of bits to the right of the binary point.
  * This function has no side-effects.
  */
 u64 current_tick_length(void)
 {
 	long delta_nsec;
+	u64 ret;
 
+	/* calculate the finest interval NTP will allow.
+	 *    ie: nanosecond value shifted by (SHIFT_SCALE - 10)
+	 */
 	delta_nsec = tick_nsec + adjtime_adjustment() * 1000;
-	return ((u64) delta_nsec << (SHIFT_SCALE - 10)) + time_adj;
+	ret = (u64)delta_nsec << TICK_LENGTH_SHIFT;
+	ret += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10));
+
+	return ret;
+}
+
+/* XXX - all of this timekeeping code should be later moved to time.c */
+#include <linux/clocksource.h>
+static struct clocksource *clock; /* pointer to current clocksource */
+
+#ifdef CONFIG_GENERIC_TIME
+/**
+ * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook
+ *
+ * private function, must hold xtime_lock lock when being
+ * called. Returns the number of nanoseconds since the
+ * last call to update_wall_time() (adjusted by NTP scaling)
+ */
+static inline s64 __get_nsec_offset(void)
+{
+	cycle_t cycle_now, cycle_delta;
+	s64 ns_offset;
+
+	/* read clocksource: */
+	cycle_now = clocksource_read(clock);
+
+	/* calculate the delta since the last update_wall_time: */
+	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+	/* convert to nanoseconds: */
+	ns_offset = cyc2ns(clock, cycle_delta);
+
+	return ns_offset;
+}
+
+/**
+ * __get_realtime_clock_ts - Returns the time of day in a timespec
+ * @ts:		pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec. Used by
+ * do_gettimeofday() and get_realtime_clock_ts().
+ */
+static inline void __get_realtime_clock_ts(struct timespec *ts)
+{
+	unsigned long seq;
+	s64 nsecs;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+
+		*ts = xtime;
+		nsecs = __get_nsec_offset();
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	timespec_add_ns(ts, nsecs);
+}
+
+/**
+ * getnstimeofday - Returns the time of day in a timespec
+ * @ts:		pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec.
+ */
+void getnstimeofday(struct timespec *ts)
+{
+	__get_realtime_clock_ts(ts);
+}
+
+EXPORT_SYMBOL(getnstimeofday);
+
+/**
+ * do_gettimeofday - Returns the time of day in a timeval
+ * @tv:		pointer to the timeval to be set
+ *
+ * NOTE: Users should be converted to using get_realtime_clock_ts()
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	struct timespec now;
+
+	__get_realtime_clock_ts(&now);
+	tv->tv_sec = now.tv_sec;
+	tv->tv_usec = now.tv_nsec/1000;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+/**
+ * do_settimeofday - Sets the time of day
+ * @tv:		pointer to the timespec variable containing the new time
+ *
+ * Sets the time of day to the new time and update NTP and notify hrtimers
+ */
+int do_settimeofday(struct timespec *tv)
+{
+	unsigned long flags;
+	time_t wtm_sec, sec = tv->tv_sec;
+	long wtm_nsec, nsec = tv->tv_nsec;
+
+	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+		return -EINVAL;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+
+	nsec -= __get_nsec_offset();
+
+	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+	set_normalized_timespec(&xtime, sec, nsec);
+	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+	ntp_clear();
+
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	/* signal hrtimers about time change */
+	clock_was_set();
+
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+/**
+ * change_clocksource - Swaps clocksources if a new one is available
+ *
+ * Accumulates current time interval and initializes new clocksource
+ */
+static int change_clocksource(void)
+{
+	struct clocksource *new;
+	cycle_t now;
+	u64 nsec;
+	new = clocksource_get_next();
+	if (clock != new) {
+		now = clocksource_read(new);
+		nsec =  __get_nsec_offset();
+		timespec_add_ns(&xtime, nsec);
+
+		clock = new;
+		clock->cycle_last = now;
+		printk(KERN_INFO "Time: %s clocksource has been installed.\n",
+					clock->name);
+		return 1;
+	} else if (clock->update_callback) {
+		return clock->update_callback();
+	}
+	return 0;
+}
+#else
+#define change_clocksource() (0)
+#endif
+
+/**
+ * timeofday_is_continuous - check to see if timekeeping is free running
+ */
+int timekeeping_is_continuous(void)
+{
+	unsigned long seq;
+	int ret;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+
+		ret = clock->is_continuous;
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	return ret;
 }
 
 /*
- * Using a loop looks inefficient, but "ticks" is
- * usually just one (we shouldn't be losing ticks,
- * we're doing this this way mainly for interrupt
- * latency reasons, not because we think we'll
- * have lots of lost timer ticks
+ * timekeeping_init - Initializes the clocksource and common timekeeping values
  */
-static void update_wall_time(unsigned long ticks)
+void __init timekeeping_init(void)
 {
-	do {
-		ticks--;
-		update_wall_time_one_tick();
-		if (xtime.tv_nsec >= 1000000000) {
-			xtime.tv_nsec -= 1000000000;
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	clock = clocksource_get_next();
+	clocksource_calculate_interval(clock, tick_nsec);
+	clock->cycle_last = clocksource_read(clock);
+	ntp_clear();
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
+
+/*
+ * timekeeping_resume - Resumes the generic timekeeping subsystem.
+ * @dev:	unused
+ *
+ * This is for the generic clocksource timekeeping.
+ * xtime/wall_to_monotonic/jiffies/wall_jiffies/etc are
+ * still managed by arch specific suspend/resume code.
+ */
+static int timekeeping_resume(struct sys_device *dev)
+{
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	/* restart the last cycle value */
+	clock->cycle_last = clocksource_read(clock);
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+	return 0;
+}
+
+/* sysfs resume/suspend bits for timekeeping */
+static struct sysdev_class timekeeping_sysclass = {
+	.resume		= timekeeping_resume,
+	set_kset_name("timekeeping"),
+};
+
+static struct sys_device device_timer = {
+	.id		= 0,
+	.cls		= &timekeeping_sysclass,
+};
+
+static int __init timekeeping_init_device(void)
+{
+	int error = sysdev_class_register(&timekeeping_sysclass);
+	if (!error)
+		error = sysdev_register(&device_timer);
+	return error;
+}
+
+device_initcall(timekeeping_init_device);
+
+/*
+ * If the error is already larger, we look ahead another tick,
+ * to compensate for late or lost adjustments.
+ */
+static __always_inline int clocksource_bigadjust(int sign, s64 error, s64 *interval, s64 *offset)
+{
+	int adj;
+
+	/*
+	 * As soon as the machine is synchronized to the external time
+	 * source this should be the common case.
+	 */
+	error >>= 2;
+	if (likely(sign > 0 ? error <= *interval : error >= *interval))
+		return sign;
+
+	/*
+	 * An extra look ahead dampens the effect of the current error,
+	 * which can grow quite large with continously late updates, as
+	 * it would dominate the adjustment value and can lead to
+	 * oscillation.
+	 */
+	error += current_tick_length() >> (TICK_LENGTH_SHIFT - clock->shift + 1);
+	error -= clock->xtime_interval >> 1;
+
+	adj = 0;
+	while (1) {
+		error >>= 1;
+		if (sign > 0 ? error <= *interval : error >= *interval)
+			break;
+		adj++;
+	}
+
+	/*
+	 * Add the current adjustments to the error and take the offset
+	 * into account, the latter can cause the error to be hardly
+	 * reduced at the next tick. Check the error again if there's
+	 * room for another adjustment, thus further reducing the error
+	 * which otherwise had to be corrected at the next update.
+	 */
+	error = (error << 1) - *interval + *offset;
+	if (sign > 0 ? error > *interval : error < *interval)
+		adj++;
+
+	*interval <<= adj;
+	*offset <<= adj;
+	return sign << adj;
+}
+
+/*
+ * Adjust the multiplier to reduce the error value,
+ * this is optimized for the most common adjustments of -1,0,1,
+ * for other values we can do a bit more work.
+ */
+static void clocksource_adjust(struct clocksource *clock, s64 offset)
+{
+	s64 error, interval = clock->cycle_interval;
+	int adj;
+
+	error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
+	if (error > interval) {
+		adj = clocksource_bigadjust(1, error, &interval, &offset);
+	} else if (error < -interval) {
+		interval = -interval;
+		offset = -offset;
+		adj = clocksource_bigadjust(-1, error, &interval, &offset);
+	} else
+		return;
+
+	clock->mult += adj;
+	clock->xtime_interval += interval;
+	clock->xtime_nsec -= offset;
+	clock->error -= (interval - offset) << (TICK_LENGTH_SHIFT - clock->shift);
+}
+
+/*
+ * update_wall_time - Uses the current clocksource to increment the wall time
+ *
+ * Called from the timer interrupt, must hold a write on xtime_lock.
+ */
+static void update_wall_time(void)
+{
+	cycle_t offset;
+
+	clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
+
+#ifdef CONFIG_GENERIC_TIME
+	offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
+#else
+	offset = clock->cycle_interval;
+#endif
+
+	/* normally this loop will run just once, however in the
+	 * case of lost or late ticks, it will accumulate correctly.
+	 */
+	while (offset >= clock->cycle_interval) {
+		/* accumulate one interval */
+		clock->xtime_nsec += clock->xtime_interval;
+		clock->cycle_last += clock->cycle_interval;
+		offset -= clock->cycle_interval;
+
+		if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {
+			clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;
 			xtime.tv_sec++;
 			second_overflow();
 		}
-	} while (ticks);
+
+		/* interpolator bits */
+		time_interpolator_update(clock->xtime_interval
+						>> clock->shift);
+		/* increment the NTP state machine */
+		update_ntp_one_tick();
+
+		/* accumulate error between NTP and clock interval */
+		clock->error += current_tick_length();
+		clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
+	}
+
+	/* correct the clock when NTP error is too big */
+	clocksource_adjust(clock, offset);
+
+	/* store full nanoseconds into xtime */
+	xtime.tv_nsec = clock->xtime_nsec >> clock->shift;
+	clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
+
+	/* check to see if there is a new clocksource to use */
+	if (change_clocksource()) {
+		clock->error = 0;
+		clock->xtime_nsec = 0;
+		clocksource_calculate_interval(clock, tick_nsec);
+	}
 }
 
 /*
@@ -915,10 +1243,8 @@
 	unsigned long ticks;
 
 	ticks = jiffies - wall_jiffies;
-	if (ticks) {
-		wall_jiffies += ticks;
-		update_wall_time(ticks);
-	}
+	wall_jiffies += ticks;
+	update_wall_time();
 	calc_load(ticks);
 }
   
diff --git a/kernel/unwind.c b/kernel/unwind.c
new file mode 100644
index 0000000..f69c804
--- /dev/null
+++ b/kernel/unwind.c
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2002-2006 Novell, Inc.
+ *	Jan Beulich <jbeulich@novell.com>
+ * This code is released under version 2 of the GNU GPL.
+ *
+ * A simple API for unwinding kernel stacks.  This is used for
+ * debugging and error reporting purposes.  The kernel doesn't need
+ * full-blown stack unwinding with all the bells and whistles, so there
+ * is not much point in implementing the full Dwarf2 unwind API.
+ */
+
+#include <linux/unwind.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/stop_machine.h>
+#include <asm/sections.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+extern char __start_unwind[], __end_unwind[];
+
+#define MAX_STACK_DEPTH 8
+
+#define EXTRA_INFO(f) { \
+		BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
+		                  % FIELD_SIZEOF(struct unwind_frame_info, f)) \
+		+ offsetof(struct unwind_frame_info, f) \
+		  / FIELD_SIZEOF(struct unwind_frame_info, f), \
+		FIELD_SIZEOF(struct unwind_frame_info, f) \
+	}
+#define PTREGS_INFO(f) EXTRA_INFO(regs.f)
+
+static const struct {
+	unsigned offs:BITS_PER_LONG / 2;
+	unsigned width:BITS_PER_LONG / 2;
+} reg_info[] = {
+	UNW_REGISTER_INFO
+};
+
+#undef PTREGS_INFO
+#undef EXTRA_INFO
+
+#ifndef REG_INVALID
+#define REG_INVALID(r) (reg_info[r].width == 0)
+#endif
+
+#define DW_CFA_nop                          0x00
+#define DW_CFA_set_loc                      0x01
+#define DW_CFA_advance_loc1                 0x02
+#define DW_CFA_advance_loc2                 0x03
+#define DW_CFA_advance_loc4                 0x04
+#define DW_CFA_offset_extended              0x05
+#define DW_CFA_restore_extended             0x06
+#define DW_CFA_undefined                    0x07
+#define DW_CFA_same_value                   0x08
+#define DW_CFA_register                     0x09
+#define DW_CFA_remember_state               0x0a
+#define DW_CFA_restore_state                0x0b
+#define DW_CFA_def_cfa                      0x0c
+#define DW_CFA_def_cfa_register             0x0d
+#define DW_CFA_def_cfa_offset               0x0e
+#define DW_CFA_def_cfa_expression           0x0f
+#define DW_CFA_expression                   0x10
+#define DW_CFA_offset_extended_sf           0x11
+#define DW_CFA_def_cfa_sf                   0x12
+#define DW_CFA_def_cfa_offset_sf            0x13
+#define DW_CFA_val_offset                   0x14
+#define DW_CFA_val_offset_sf                0x15
+#define DW_CFA_val_expression               0x16
+#define DW_CFA_lo_user                      0x1c
+#define DW_CFA_GNU_window_save              0x2d
+#define DW_CFA_GNU_args_size                0x2e
+#define DW_CFA_GNU_negative_offset_extended 0x2f
+#define DW_CFA_hi_user                      0x3f
+
+#define DW_EH_PE_FORM     0x07
+#define DW_EH_PE_native   0x00
+#define DW_EH_PE_leb128   0x01
+#define DW_EH_PE_data2    0x02
+#define DW_EH_PE_data4    0x03
+#define DW_EH_PE_data8    0x04
+#define DW_EH_PE_signed   0x08
+#define DW_EH_PE_ADJUST   0x70
+#define DW_EH_PE_abs      0x00
+#define DW_EH_PE_pcrel    0x10
+#define DW_EH_PE_textrel  0x20
+#define DW_EH_PE_datarel  0x30
+#define DW_EH_PE_funcrel  0x40
+#define DW_EH_PE_aligned  0x50
+#define DW_EH_PE_indirect 0x80
+#define DW_EH_PE_omit     0xff
+
+typedef unsigned long uleb128_t;
+typedef   signed long sleb128_t;
+
+static struct unwind_table {
+	struct {
+		unsigned long pc;
+		unsigned long range;
+	} core, init;
+	const void *address;
+	unsigned long size;
+	struct unwind_table *link;
+	const char *name;
+} root_table, *last_table;
+
+struct unwind_item {
+	enum item_location {
+		Nowhere,
+		Memory,
+		Register,
+		Value
+	} where;
+	uleb128_t value;
+};
+
+struct unwind_state {
+	uleb128_t loc, org;
+	const u8 *cieStart, *cieEnd;
+	uleb128_t codeAlign;
+	sleb128_t dataAlign;
+	struct cfa {
+		uleb128_t reg, offs;
+	} cfa;
+	struct unwind_item regs[ARRAY_SIZE(reg_info)];
+	unsigned stackDepth:8;
+	unsigned version:8;
+	const u8 *label;
+	const u8 *stack[MAX_STACK_DEPTH];
+};
+
+static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
+
+static struct unwind_table *find_table(unsigned long pc)
+{
+	struct unwind_table *table;
+
+	for (table = &root_table; table; table = table->link)
+		if ((pc >= table->core.pc
+		     && pc < table->core.pc + table->core.range)
+		    || (pc >= table->init.pc
+		        && pc < table->init.pc + table->init.range))
+			break;
+
+	return table;
+}
+
+static void init_unwind_table(struct unwind_table *table,
+                              const char *name,
+                              const void *core_start,
+                              unsigned long core_size,
+                              const void *init_start,
+                              unsigned long init_size,
+                              const void *table_start,
+                              unsigned long table_size)
+{
+	table->core.pc = (unsigned long)core_start;
+	table->core.range = core_size;
+	table->init.pc = (unsigned long)init_start;
+	table->init.range = init_size;
+	table->address = table_start;
+	table->size = table_size;
+	table->link = NULL;
+	table->name = name;
+}
+
+void __init unwind_init(void)
+{
+	init_unwind_table(&root_table, "kernel",
+	                  _text, _end - _text,
+	                  NULL, 0,
+	                  __start_unwind, __end_unwind - __start_unwind);
+}
+
+#ifdef CONFIG_MODULES
+
+/* Must be called with module_mutex held. */
+void *unwind_add_table(struct module *module,
+                       const void *table_start,
+                       unsigned long table_size)
+{
+	struct unwind_table *table;
+
+	if (table_size <= 0)
+		return NULL;
+
+	table = kmalloc(sizeof(*table), GFP_KERNEL);
+	if (!table)
+		return NULL;
+
+	init_unwind_table(table, module->name,
+	                  module->module_core, module->core_size,
+	                  module->module_init, module->init_size,
+	                  table_start, table_size);
+
+	if (last_table)
+		last_table->link = table;
+	else
+		root_table.link = table;
+	last_table = table;
+
+	return table;
+}
+
+struct unlink_table_info
+{
+	struct unwind_table *table;
+	int init_only;
+};
+
+static int unlink_table(void *arg)
+{
+	struct unlink_table_info *info = arg;
+	struct unwind_table *table = info->table, *prev;
+
+	for (prev = &root_table; prev->link && prev->link != table; prev = prev->link)
+		;
+
+	if (prev->link) {
+		if (info->init_only) {
+			table->init.pc = 0;
+			table->init.range = 0;
+			info->table = NULL;
+		} else {
+			prev->link = table->link;
+			if (!prev->link)
+				last_table = prev;
+		}
+	} else
+		info->table = NULL;
+
+	return 0;
+}
+
+/* Must be called with module_mutex held. */
+void unwind_remove_table(void *handle, int init_only)
+{
+	struct unwind_table *table = handle;
+	struct unlink_table_info info;
+
+	if (!table || table == &root_table)
+		return;
+
+	if (init_only && table == last_table) {
+		table->init.pc = 0;
+		table->init.range = 0;
+		return;
+	}
+
+	info.table = table;
+	info.init_only = init_only;
+	stop_machine_run(unlink_table, &info, NR_CPUS);
+
+	if (info.table)
+		kfree(table);
+}
+
+#endif /* CONFIG_MODULES */
+
+static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
+{
+	const u8 *cur = *pcur;
+	uleb128_t value;
+	unsigned shift;
+
+	for (shift = 0, value = 0; cur < end; shift += 7) {
+		if (shift + 7 > 8 * sizeof(value)
+		    && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
+			cur = end + 1;
+			break;
+		}
+		value |= (uleb128_t)(*cur & 0x7f) << shift;
+		if (!(*cur++ & 0x80))
+			break;
+	}
+	*pcur = cur;
+
+	return value;
+}
+
+static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
+{
+	const u8 *cur = *pcur;
+	sleb128_t value;
+	unsigned shift;
+
+	for (shift = 0, value = 0; cur < end; shift += 7) {
+		if (shift + 7 > 8 * sizeof(value)
+		    && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
+			cur = end + 1;
+			break;
+		}
+		value |= (sleb128_t)(*cur & 0x7f) << shift;
+		if (!(*cur & 0x80)) {
+			value |= -(*cur++ & 0x40) << shift;
+			break;
+		}
+	}
+	*pcur = cur;
+
+	return value;
+}
+
+static unsigned long read_pointer(const u8 **pLoc,
+                                  const void *end,
+                                  signed ptrType)
+{
+	unsigned long value = 0;
+	union {
+		const u8 *p8;
+		const u16 *p16u;
+		const s16 *p16s;
+		const u32 *p32u;
+		const s32 *p32s;
+		const unsigned long *pul;
+	} ptr;
+
+	if (ptrType < 0 || ptrType == DW_EH_PE_omit)
+		return 0;
+	ptr.p8 = *pLoc;
+	switch(ptrType & DW_EH_PE_FORM) {
+	case DW_EH_PE_data2:
+		if (end < (const void *)(ptr.p16u + 1))
+			return 0;
+		if(ptrType & DW_EH_PE_signed)
+			value = get_unaligned(ptr.p16s++);
+		else
+			value = get_unaligned(ptr.p16u++);
+		break;
+	case DW_EH_PE_data4:
+#ifdef CONFIG_64BIT
+		if (end < (const void *)(ptr.p32u + 1))
+			return 0;
+		if(ptrType & DW_EH_PE_signed)
+			value = get_unaligned(ptr.p32s++);
+		else
+			value = get_unaligned(ptr.p32u++);
+		break;
+	case DW_EH_PE_data8:
+		BUILD_BUG_ON(sizeof(u64) != sizeof(value));
+#else
+		BUILD_BUG_ON(sizeof(u32) != sizeof(value));
+#endif
+	case DW_EH_PE_native:
+		if (end < (const void *)(ptr.pul + 1))
+			return 0;
+		value = get_unaligned(ptr.pul++);
+		break;
+	case DW_EH_PE_leb128:
+		BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
+		value = ptrType & DW_EH_PE_signed
+		        ? get_sleb128(&ptr.p8, end)
+		        : get_uleb128(&ptr.p8, end);
+		if ((const void *)ptr.p8 > end)
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+	switch(ptrType & DW_EH_PE_ADJUST) {
+	case DW_EH_PE_abs:
+		break;
+	case DW_EH_PE_pcrel:
+		value += (unsigned long)*pLoc;
+		break;
+	default:
+		return 0;
+	}
+	if ((ptrType & DW_EH_PE_indirect)
+	    && __get_user(value, (unsigned long *)value))
+		return 0;
+	*pLoc = ptr.p8;
+
+	return value;
+}
+
+static signed fde_pointer_type(const u32 *cie)
+{
+	const u8 *ptr = (const u8 *)(cie + 2);
+	unsigned version = *ptr;
+
+	if (version != 1)
+		return -1; /* unsupported */
+	if (*++ptr) {
+		const char *aug;
+		const u8 *end = (const u8 *)(cie + 1) + *cie;
+		uleb128_t len;
+
+		/* check if augmentation size is first (and thus present) */
+		if (*ptr != 'z')
+			return -1;
+		/* check if augmentation string is nul-terminated */
+		if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
+			return -1;
+		++ptr; /* skip terminator */
+		get_uleb128(&ptr, end); /* skip code alignment */
+		get_sleb128(&ptr, end); /* skip data alignment */
+		/* skip return address column */
+		version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end);
+		len = get_uleb128(&ptr, end); /* augmentation length */
+		if (ptr + len < ptr || ptr + len > end)
+			return -1;
+		end = ptr + len;
+		while (*++aug) {
+			if (ptr >= end)
+				return -1;
+			switch(*aug) {
+			case 'L':
+				++ptr;
+				break;
+			case 'P': {
+					signed ptrType = *ptr++;
+
+					if (!read_pointer(&ptr, end, ptrType) || ptr > end)
+						return -1;
+				}
+				break;
+			case 'R':
+				return *ptr;
+			default:
+				return -1;
+			}
+		}
+	}
+	return DW_EH_PE_native|DW_EH_PE_abs;
+}
+
+static int advance_loc(unsigned long delta, struct unwind_state *state)
+{
+	state->loc += delta * state->codeAlign;
+
+	return delta > 0;
+}
+
+static void set_rule(uleb128_t reg,
+                     enum item_location where,
+                     uleb128_t value,
+                     struct unwind_state *state)
+{
+	if (reg < ARRAY_SIZE(state->regs)) {
+		state->regs[reg].where = where;
+		state->regs[reg].value = value;
+	}
+}
+
+static int processCFI(const u8 *start,
+                      const u8 *end,
+                      unsigned long targetLoc,
+                      signed ptrType,
+                      struct unwind_state *state)
+{
+	union {
+		const u8 *p8;
+		const u16 *p16;
+		const u32 *p32;
+	} ptr;
+	int result = 1;
+
+	if (start != state->cieStart) {
+		state->loc = state->org;
+		result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state);
+		if (targetLoc == 0 && state->label == NULL)
+			return result;
+	}
+	for (ptr.p8 = start; result && ptr.p8 < end; ) {
+		switch(*ptr.p8 >> 6) {
+			uleb128_t value;
+
+		case 0:
+			switch(*ptr.p8++) {
+			case DW_CFA_nop:
+				break;
+			case DW_CFA_set_loc:
+				if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0)
+					result = 0;
+				break;
+			case DW_CFA_advance_loc1:
+				result = ptr.p8 < end && advance_loc(*ptr.p8++, state);
+				break;
+			case DW_CFA_advance_loc2:
+				result = ptr.p8 <= end + 2
+				         && advance_loc(*ptr.p16++, state);
+				break;
+			case DW_CFA_advance_loc4:
+				result = ptr.p8 <= end + 4
+				         && advance_loc(*ptr.p32++, state);
+				break;
+			case DW_CFA_offset_extended:
+				value = get_uleb128(&ptr.p8, end);
+				set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
+				break;
+			case DW_CFA_val_offset:
+				value = get_uleb128(&ptr.p8, end);
+				set_rule(value, Value, get_uleb128(&ptr.p8, end), state);
+				break;
+			case DW_CFA_offset_extended_sf:
+				value = get_uleb128(&ptr.p8, end);
+				set_rule(value, Memory, get_sleb128(&ptr.p8, end), state);
+				break;
+			case DW_CFA_val_offset_sf:
+				value = get_uleb128(&ptr.p8, end);
+				set_rule(value, Value, get_sleb128(&ptr.p8, end), state);
+				break;
+			case DW_CFA_restore_extended:
+			case DW_CFA_undefined:
+			case DW_CFA_same_value:
+				set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state);
+				break;
+			case DW_CFA_register:
+				value = get_uleb128(&ptr.p8, end);
+				set_rule(value,
+				         Register,
+				         get_uleb128(&ptr.p8, end), state);
+				break;
+			case DW_CFA_remember_state:
+				if (ptr.p8 == state->label) {
+					state->label = NULL;
+					return 1;
+				}
+				if (state->stackDepth >= MAX_STACK_DEPTH)
+					return 0;
+				state->stack[state->stackDepth++] = ptr.p8;
+				break;
+			case DW_CFA_restore_state:
+				if (state->stackDepth) {
+					const uleb128_t loc = state->loc;
+					const u8 *label = state->label;
+
+					state->label = state->stack[state->stackDepth - 1];
+					memcpy(&state->cfa, &badCFA, sizeof(state->cfa));
+					memset(state->regs, 0, sizeof(state->regs));
+					state->stackDepth = 0;
+					result = processCFI(start, end, 0, ptrType, state);
+					state->loc = loc;
+					state->label = label;
+				} else
+					return 0;
+				break;
+			case DW_CFA_def_cfa:
+				state->cfa.reg = get_uleb128(&ptr.p8, end);
+				/*nobreak*/
+			case DW_CFA_def_cfa_offset:
+				state->cfa.offs = get_uleb128(&ptr.p8, end);
+				break;
+			case DW_CFA_def_cfa_sf:
+				state->cfa.reg = get_uleb128(&ptr.p8, end);
+				/*nobreak*/
+			case DW_CFA_def_cfa_offset_sf:
+				state->cfa.offs = get_sleb128(&ptr.p8, end)
+				                  * state->dataAlign;
+				break;
+			case DW_CFA_def_cfa_register:
+				state->cfa.reg = get_uleb128(&ptr.p8, end);
+				break;
+			/*todo case DW_CFA_def_cfa_expression: */
+			/*todo case DW_CFA_expression: */
+			/*todo case DW_CFA_val_expression: */
+			case DW_CFA_GNU_args_size:
+				get_uleb128(&ptr.p8, end);
+				break;
+			case DW_CFA_GNU_negative_offset_extended:
+				value = get_uleb128(&ptr.p8, end);
+				set_rule(value,
+				         Memory,
+				         (uleb128_t)0 - get_uleb128(&ptr.p8, end), state);
+				break;
+			case DW_CFA_GNU_window_save:
+			default:
+				result = 0;
+				break;
+			}
+			break;
+		case 1:
+			result = advance_loc(*ptr.p8++ & 0x3f, state);
+			break;
+		case 2:
+			value = *ptr.p8++ & 0x3f;
+			set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
+			break;
+		case 3:
+			set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
+			break;
+		}
+		if (ptr.p8 > end)
+			result = 0;
+		if (result && targetLoc != 0 && targetLoc < state->loc)
+			return 1;
+	}
+
+	return result
+	   && ptr.p8 == end
+	   && (targetLoc == 0
+	    || (/*todo While in theory this should apply, gcc in practice omits
+	          everything past the function prolog, and hence the location
+	          never reaches the end of the function.
+	        targetLoc < state->loc &&*/ state->label == NULL));
+}
+
+/* Unwind to previous to frame.  Returns 0 if successful, negative
+ * number in case of an error. */
+int unwind(struct unwind_frame_info *frame)
+{
+#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
+	const u32 *fde = NULL, *cie = NULL;
+	const u8 *ptr = NULL, *end = NULL;
+	unsigned long startLoc = 0, endLoc = 0, cfa;
+	unsigned i;
+	signed ptrType = -1;
+	uleb128_t retAddrReg = 0;
+	struct unwind_table *table;
+	struct unwind_state state;
+
+	if (UNW_PC(frame) == 0)
+		return -EINVAL;
+	if ((table = find_table(UNW_PC(frame))) != NULL
+	    && !(table->size & (sizeof(*fde) - 1))) {
+		unsigned long tableSize = table->size;
+
+		for (fde = table->address;
+		     tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
+		     tableSize -= sizeof(*fde) + *fde,
+		     fde += 1 + *fde / sizeof(*fde)) {
+			if (!*fde || (*fde & (sizeof(*fde) - 1)))
+				break;
+			if (!fde[1])
+				continue; /* this is a CIE */
+			if ((fde[1] & (sizeof(*fde) - 1))
+			    || fde[1] > (unsigned long)(fde + 1)
+			                - (unsigned long)table->address)
+				continue; /* this is not a valid FDE */
+			cie = fde + 1 - fde[1] / sizeof(*fde);
+			if (*cie <= sizeof(*cie) + 4
+			    || *cie >= fde[1] - sizeof(*fde)
+			    || (*cie & (sizeof(*cie) - 1))
+			    || cie[1]
+			    || (ptrType = fde_pointer_type(cie)) < 0) {
+				cie = NULL; /* this is not a (valid) CIE */
+				continue;
+			}
+			ptr = (const u8 *)(fde + 2);
+			startLoc = read_pointer(&ptr,
+			                        (const u8 *)(fde + 1) + *fde,
+			                        ptrType);
+			endLoc = startLoc
+			         + read_pointer(&ptr,
+			                        (const u8 *)(fde + 1) + *fde,
+			                        ptrType & DW_EH_PE_indirect
+			                        ? ptrType
+			                        : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed));
+			if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc)
+				break;
+			cie = NULL;
+		}
+	}
+	if (cie != NULL) {
+		memset(&state, 0, sizeof(state));
+		state.cieEnd = ptr; /* keep here temporarily */
+		ptr = (const u8 *)(cie + 2);
+		end = (const u8 *)(cie + 1) + *cie;
+		if ((state.version = *ptr) != 1)
+			cie = NULL; /* unsupported version */
+		else if (*++ptr) {
+			/* check if augmentation size is first (and thus present) */
+			if (*ptr == 'z') {
+				/* check for ignorable (or already handled)
+				 * nul-terminated augmentation string */
+				while (++ptr < end && *ptr)
+					if (strchr("LPR", *ptr) == NULL)
+						break;
+			}
+			if (ptr >= end || *ptr)
+				cie = NULL;
+		}
+		++ptr;
+	}
+	if (cie != NULL) {
+		/* get code aligment factor */
+		state.codeAlign = get_uleb128(&ptr, end);
+		/* get data aligment factor */
+		state.dataAlign = get_sleb128(&ptr, end);
+		if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
+			cie = NULL;
+		else {
+			retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
+			/* skip augmentation */
+			if (((const char *)(cie + 2))[1] == 'z')
+				ptr += get_uleb128(&ptr, end);
+			if (ptr > end
+			   || retAddrReg >= ARRAY_SIZE(reg_info)
+			   || REG_INVALID(retAddrReg)
+			   || reg_info[retAddrReg].width != sizeof(unsigned long))
+				cie = NULL;
+		}
+	}
+	if (cie != NULL) {
+		state.cieStart = ptr;
+		ptr = state.cieEnd;
+		state.cieEnd = end;
+		end = (const u8 *)(fde + 1) + *fde;
+		/* skip augmentation */
+		if (((const char *)(cie + 2))[1] == 'z') {
+			uleb128_t augSize = get_uleb128(&ptr, end);
+
+			if ((ptr += augSize) > end)
+				fde = NULL;
+		}
+	}
+	if (cie == NULL || fde == NULL) {
+#ifdef CONFIG_FRAME_POINTER
+		unsigned long top, bottom;
+#endif
+
+#ifdef CONFIG_FRAME_POINTER
+		top = STACK_TOP(frame->task);
+		bottom = STACK_BOTTOM(frame->task);
+# if FRAME_RETADDR_OFFSET < 0
+		if (UNW_SP(frame) < top
+		    && UNW_FP(frame) <= UNW_SP(frame)
+		    && bottom < UNW_FP(frame)
+# else
+		if (UNW_SP(frame) > top
+		    && UNW_FP(frame) >= UNW_SP(frame)
+		    && bottom > UNW_FP(frame)
+# endif
+		   && !((UNW_SP(frame) | UNW_FP(frame))
+		        & (sizeof(unsigned long) - 1))) {
+			unsigned long link;
+
+			if (!__get_user(link,
+			                (unsigned long *)(UNW_FP(frame)
+			                                  + FRAME_LINK_OFFSET))
+# if FRAME_RETADDR_OFFSET < 0
+			   && link > bottom && link < UNW_FP(frame)
+# else
+			   && link > UNW_FP(frame) && link < bottom
+# endif
+			   && !(link & (sizeof(link) - 1))
+			   && !__get_user(UNW_PC(frame),
+			                  (unsigned long *)(UNW_FP(frame)
+			                                    + FRAME_RETADDR_OFFSET))) {
+				UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET
+# if FRAME_RETADDR_OFFSET < 0
+					-
+# else
+					+
+# endif
+					  sizeof(UNW_PC(frame));
+				UNW_FP(frame) = link;
+				return 0;
+			}
+		}
+#endif
+		return -ENXIO;
+	}
+	state.org = startLoc;
+	memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
+	/* process instructions */
+	if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state)
+	   || state.loc > endLoc
+	   || state.regs[retAddrReg].where == Nowhere
+	   || state.cfa.reg >= ARRAY_SIZE(reg_info)
+	   || reg_info[state.cfa.reg].width != sizeof(unsigned long)
+	   || state.cfa.offs % sizeof(unsigned long))
+		return -EIO;
+	/* update frame */
+	cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
+	startLoc = min((unsigned long)UNW_SP(frame), cfa);
+	endLoc = max((unsigned long)UNW_SP(frame), cfa);
+	if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
+		startLoc = min(STACK_LIMIT(cfa), cfa);
+		endLoc = max(STACK_LIMIT(cfa), cfa);
+	}
+#ifndef CONFIG_64BIT
+# define CASES CASE(8); CASE(16); CASE(32)
+#else
+# define CASES CASE(8); CASE(16); CASE(32); CASE(64)
+#endif
+	for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
+		if (REG_INVALID(i)) {
+			if (state.regs[i].where == Nowhere)
+				continue;
+			return -EIO;
+		}
+		switch(state.regs[i].where) {
+		default:
+			break;
+		case Register:
+			if (state.regs[i].value >= ARRAY_SIZE(reg_info)
+			   || REG_INVALID(state.regs[i].value)
+			   || reg_info[i].width > reg_info[state.regs[i].value].width)
+				return -EIO;
+			switch(reg_info[state.regs[i].value].width) {
+#define CASE(n) \
+			case sizeof(u##n): \
+				state.regs[i].value = FRAME_REG(state.regs[i].value, \
+				                                const u##n); \
+				break
+			CASES;
+#undef CASE
+			default:
+				return -EIO;
+			}
+			break;
+		}
+	}
+	for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
+		if (REG_INVALID(i))
+			continue;
+		switch(state.regs[i].where) {
+		case Nowhere:
+			if (reg_info[i].width != sizeof(UNW_SP(frame))
+			   || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
+			      != &UNW_SP(frame))
+				continue;
+			UNW_SP(frame) = cfa;
+			break;
+		case Register:
+			switch(reg_info[i].width) {
+#define CASE(n) case sizeof(u##n): \
+				FRAME_REG(i, u##n) = state.regs[i].value; \
+				break
+			CASES;
+#undef CASE
+			default:
+				return -EIO;
+			}
+			break;
+		case Value:
+			if (reg_info[i].width != sizeof(unsigned long))
+				return -EIO;
+			FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
+			                                    * state.dataAlign;
+			break;
+		case Memory: {
+				unsigned long addr = cfa + state.regs[i].value
+				                           * state.dataAlign;
+
+				if ((state.regs[i].value * state.dataAlign)
+				    % sizeof(unsigned long)
+				    || addr < startLoc
+				    || addr + sizeof(unsigned long) < addr
+				    || addr + sizeof(unsigned long) > endLoc)
+					return -EIO;
+				switch(reg_info[i].width) {
+#define CASE(n)     case sizeof(u##n): \
+					__get_user(FRAME_REG(i, u##n), (u##n *)addr); \
+					break
+				CASES;
+#undef CASE
+				default:
+					return -EIO;
+				}
+			}
+			break;
+		}
+	}
+
+	return 0;
+#undef CASES
+#undef FRAME_REG
+}
+EXPORT_SYMBOL(unwind);
+
+int unwind_init_frame_info(struct unwind_frame_info *info,
+                           struct task_struct *tsk,
+                           /*const*/ struct pt_regs *regs)
+{
+	info->task = tsk;
+	arch_unw_init_frame_info(info, regs);
+
+	return 0;
+}
+EXPORT_SYMBOL(unwind_init_frame_info);
+
+/*
+ * Prepare to unwind a blocked task.
+ */
+int unwind_init_blocked(struct unwind_frame_info *info,
+                        struct task_struct *tsk)
+{
+	info->task = tsk;
+	arch_unw_init_blocked(info);
+
+	return 0;
+}
+EXPORT_SYMBOL(unwind_init_blocked);
+
+/*
+ * Prepare to unwind the currently running thread.
+ */
+int unwind_init_running(struct unwind_frame_info *info,
+                        asmlinkage int (*callback)(struct unwind_frame_info *,
+                                                   void *arg),
+                        void *arg)
+{
+	info->task = current;
+
+	return arch_unwind_init_running(info, callback, arg);
+}
+EXPORT_SYMBOL(unwind_init_running);
+
+/*
+ * Unwind until the return pointer is in user-land (or until an error
+ * occurs).  Returns 0 if successful, negative number in case of
+ * error.
+ */
+int unwind_to_user(struct unwind_frame_info *info)
+{
+	while (!arch_unw_user_mode(info)) {
+		int err = unwind(info);
+
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(unwind_to_user);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 740c5ab..565cf7a 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -428,22 +428,34 @@
 	return ret;
 }
 
-int schedule_on_each_cpu(void (*func) (void *info), void *info)
+/**
+ * schedule_on_each_cpu - call a function on each online CPU from keventd
+ * @func: the function to call
+ * @info: a pointer to pass to func()
+ *
+ * Returns zero on success.
+ * Returns -ve errno on failure.
+ *
+ * Appears to be racy against CPU hotplug.
+ *
+ * schedule_on_each_cpu() is very slow.
+ */
+int schedule_on_each_cpu(void (*func)(void *info), void *info)
 {
 	int cpu;
-	struct work_struct *work;
+	struct work_struct *works;
 
-	work = kmalloc(NR_CPUS * sizeof(struct work_struct), GFP_KERNEL);
-
-	if (!work)
+	works = alloc_percpu(struct work_struct);
+	if (!works)
 		return -ENOMEM;
+
 	for_each_online_cpu(cpu) {
-		INIT_WORK(work + cpu, func, info);
+		INIT_WORK(per_cpu_ptr(works, cpu), func, info);
 		__queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu),
-				work + cpu);
+				per_cpu_ptr(works, cpu));
 	}
 	flush_workqueue(keventd_wq);
-	kfree(work);
+	free_percpu(works);
 	return 0;
 }
 
@@ -578,6 +590,8 @@
 
 	case CPU_UP_CANCELED:
 		list_for_each_entry(wq, &workqueues, list) {
+			if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)
+				continue;
 			/* Unbind so it can run. */
 			kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,
 				     any_online_cpu(cpu_online_map));
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ccb0c1f..8bab010 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -188,14 +188,22 @@
 
 config UNWIND_INFO
 	bool "Compile the kernel with frame unwind information"
-	depends on !IA64
-	depends on !MODULES || !(MIPS || PARISC || PPC || SUPERH || V850)
+	depends on !IA64 && !PARISC
+	depends on !MODULES || !(MIPS || PPC || SUPERH || V850)
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
 	  but not slower, and it will give very useful debugging information.
 	  If you don't debug the kernel, you can say N, but we may not be able
 	  to solve problems without frame unwind information or frame pointers.
 
+config STACK_UNWIND
+	bool "Stack unwind support"
+	depends on UNWIND_INFO
+	depends on X86
+	help
+	  This enables more precise stack traces, omitting all unrelated
+	  occurrences of pointers into kernel code from the dump.
+
 config FORCED_INLINING
 	bool "Force gcc to inline functions marked 'inline'"
 	depends on DEBUG_KERNEL
diff --git a/lib/bitmap.c b/lib/bitmap.c
index ed2ae3b..d71e38c 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -317,16 +317,16 @@
 
 /**
  * bitmap_parse - convert an ASCII hex string into a bitmap.
- * @buf: pointer to buffer in user space containing string.
- * @buflen: buffer size in bytes.  If string is smaller than this
+ * @ubuf: pointer to buffer in user space containing string.
+ * @ubuflen: buffer size in bytes.  If string is smaller than this
  *    then it must be terminated with a \0.
  * @maskp: pointer to bitmap array that will contain result.
  * @nmaskbits: size of bitmap, in bits.
  *
  * Commas group hex digits into chunks.  Each chunk defines exactly 32
  * bits of the resultant bitmask.  No chunk may specify a value larger
- * than 32 bits (-EOVERFLOW), and if a chunk specifies a smaller value
- * then leading 0-bits are prepended.  -EINVAL is returned for illegal
+ * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value
+ * then leading 0-bits are prepended.  %-EINVAL is returned for illegal
  * characters and for grouping errors such as "1,,5", ",44", "," and "".
  * Leading and trailing whitespace accepted, but not embedded whitespace.
  */
@@ -452,8 +452,8 @@
 
 /**
  * bitmap_parselist - convert list format ASCII string to bitmap
- * @buf: read nul-terminated user string from this buffer
- * @mask: write resulting mask here
+ * @bp: read nul-terminated user string from this buffer
+ * @maskp: write resulting mask here
  * @nmaskbits: number of bits in mask to be written
  *
  * Input format is a comma-separated list of decimal numbers and
@@ -461,10 +461,11 @@
  * decimal numbers, the smallest and largest bit numbers set in
  * the range.
  *
- * Returns 0 on success, -errno on invalid input strings:
- *    -EINVAL:   second number in range smaller than first
- *    -EINVAL:   invalid character in string
- *    -ERANGE:   bit number specified too large for mask
+ * Returns 0 on success, -errno on invalid input strings.
+ * Error values:
+ *    %-EINVAL: second number in range smaller than first
+ *    %-EINVAL: invalid character in string
+ *    %-ERANGE: bit number specified too large for mask
  */
 int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
 {
@@ -625,10 +626,10 @@
 
 /**
  * bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit
- *	@oldbit - bit position to be mapped
- *      @old: defines domain of map
- *      @new: defines range of map
- *      @bits: number of bits in each of these bitmaps
+ *	@oldbit: bit position to be mapped
+ *	@old: defines domain of map
+ *	@new: defines range of map
+ *	@bits: number of bits in each of these bitmaps
  *
  * Let @old and @new define a mapping of bit positions, such that
  * whatever position is held by the n-th set bit in @old is mapped
@@ -790,7 +791,7 @@
  *
  * Allocate (set bits in) a specified region of a bitmap.
  *
- * Return 0 on success, or -EBUSY if specified region wasn't
+ * Return 0 on success, or %-EBUSY if specified region wasn't
  * free (not all bits were zero).
  */
 int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
diff --git a/lib/crc-ccitt.c b/lib/crc-ccitt.c
index 115d149..7f6dd68 100644
--- a/lib/crc-ccitt.c
+++ b/lib/crc-ccitt.c
@@ -53,9 +53,9 @@
 
 /**
  *	crc_ccitt - recompute the CRC for the data buffer
- *	@crc - previous CRC value
- *	@buffer - data pointer
- *	@len - number of bytes in the buffer
+ *	@crc: previous CRC value
+ *	@buffer: data pointer
+ *	@len: number of bytes in the buffer
  */
 u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)
 {
diff --git a/lib/crc16.c b/lib/crc16.c
index 011fe57..8737b08 100644
--- a/lib/crc16.c
+++ b/lib/crc16.c
@@ -47,12 +47,12 @@
 EXPORT_SYMBOL(crc16_table);
 
 /**
- * Compute the CRC-16 for the data buffer
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc:	previous CRC value
+ * @buffer:	data pointer
+ * @len:	number of bytes in the buffer
  *
- * @param crc     previous CRC value
- * @param buffer  data pointer
- * @param len     number of bytes in the buffer
- * @return        the updated CRC value
+ * Returns the updated CRC value.
  */
 u16 crc16(u16 crc, u8 const *buffer, size_t len)
 {
diff --git a/lib/crc32.c b/lib/crc32.c
index 065198f..285fd9b 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -42,20 +42,21 @@
 MODULE_DESCRIPTION("Ethernet CRC32 calculations");
 MODULE_LICENSE("GPL");
 
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *	other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len);
+
 #if CRC_LE_BITS == 1
 /*
  * In fact, the table-based code will work in this case, but it can be
  * simplified by inlining the table in ?: form.
  */
 
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
 {
 	int i;
@@ -68,14 +69,6 @@
 }
 #else				/* Table-based approach */
 
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_le(u32 crc, unsigned char const *p, size_t len)
 {
 # if CRC_LE_BITS == 8
@@ -145,20 +138,21 @@
 }
 #endif
 
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *	other uses, or the previous crc32 value if computing incrementally.
+ * @p: pointer to buffer over which CRC is run
+ * @len: length of buffer @p
+ */
+u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len);
+
 #if CRC_BE_BITS == 1
 /*
  * In fact, the table-based code will work in this case, but it can be
  * simplified by inlining the table in ?: form.
  */
 
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
 	int i;
@@ -173,14 +167,6 @@
 }
 
 #else				/* Table-based approach */
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *        other uses, or the previous crc32 value if computing incrementally.
- * @p   - pointer to buffer over which CRC is run
- * @len - length of buffer @p
- * 
- */
 u32 __attribute_pure__ crc32_be(u32 crc, unsigned char const *p, size_t len)
 {
 # if CRC_BE_BITS == 8
@@ -249,6 +235,10 @@
 }
 #endif
 
+/**
+ * bitreverse - reverse the order of bits in a u32 value
+ * @x: value to be bit-reversed
+ */
 u32 bitreverse(u32 x)
 {
 	x = (x >> 16) | (x << 16);
diff --git a/lib/idr.c b/lib/idr.c
index d226259..4d09681 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -29,6 +29,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #endif
+#include <linux/err.h>
 #include <linux/string.h>
 #include <linux/idr.h>
 
@@ -48,15 +49,21 @@
 	return(p);
 }
 
+/* only called when idp->lock is held */
+static void __free_layer(struct idr *idp, struct idr_layer *p)
+{
+	p->ary[0] = idp->id_free;
+	idp->id_free = p;
+	idp->id_free_cnt++;
+}
+
 static void free_layer(struct idr *idp, struct idr_layer *p)
 {
 	/*
 	 * Depends on the return element being zeroed.
 	 */
 	spin_lock(&idp->lock);
-	p->ary[0] = idp->id_free;
-	idp->id_free = p;
-	idp->id_free_cnt++;
+	__free_layer(idp, p);
 	spin_unlock(&idp->lock);
 }
 
@@ -184,12 +191,14 @@
 			 * The allocation failed.  If we built part of
 			 * the structure tear it down.
 			 */
+			spin_lock(&idp->lock);
 			for (new = p; p && p != idp->top; new = p) {
 				p = p->ary[0];
 				new->ary[0] = NULL;
 				new->bitmap = new->count = 0;
-				free_layer(idp, new);
+				__free_layer(idp, new);
 			}
+			spin_unlock(&idp->lock);
 			return -1;
 		}
 		new->ary[0] = p;
@@ -390,6 +399,48 @@
 }
 EXPORT_SYMBOL(idr_find);
 
+/**
+ * idr_replace - replace pointer for given id
+ * @idp: idr handle
+ * @ptr: pointer you want associated with the id
+ * @id: lookup key
+ *
+ * Replace the pointer registered with an id and return the old value.
+ * A -ENOENT return indicates that @id was not found.
+ * A -EINVAL return indicates that @id was not within valid constraints.
+ *
+ * The caller must serialize vs idr_find(), idr_get_new(), and idr_remove().
+ */
+void *idr_replace(struct idr *idp, void *ptr, int id)
+{
+	int n;
+	struct idr_layer *p, *old_p;
+
+	n = idp->layers * IDR_BITS;
+	p = idp->top;
+
+	id &= MAX_ID_MASK;
+
+	if (id >= (1 << n))
+		return ERR_PTR(-EINVAL);
+
+	n -= IDR_BITS;
+	while ((n > 0) && p) {
+		p = p->ary[(id >> n) & IDR_MASK];
+		n -= IDR_BITS;
+	}
+
+	n = id & IDR_MASK;
+	if (unlikely(p == NULL || !test_bit(n, &p->bitmap)))
+		return ERR_PTR(-ENOENT);
+
+	old_p = p->ary[n];
+	p->ary[n] = ptr;
+
+	return old_p;
+}
+EXPORT_SYMBOL(idr_replace);
+
 static void idr_cache_ctor(void * idr_layer, kmem_cache_t *idr_layer_cache,
 		unsigned long flags)
 {
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c
index cb5490e..e713e86 100644
--- a/lib/kernel_lock.c
+++ b/lib/kernel_lock.c
@@ -14,7 +14,7 @@
  * The 'big kernel semaphore'
  *
  * This mutex is taken and released recursively by lock_kernel()
- * and unlock_kernel().  It is transparently dropped and reaquired
+ * and unlock_kernel().  It is transparently dropped and reacquired
  * over schedule().  It is used to protect legacy code that hasn't
  * been migrated to a proper locking design yet.
  *
@@ -92,7 +92,7 @@
  * The 'big kernel lock'
  *
  * This spinlock is taken and released recursively by lock_kernel()
- * and unlock_kernel().  It is transparently dropped and reaquired
+ * and unlock_kernel().  It is transparently dropped and reacquired
  * over schedule().  It is used to protect legacy code that hasn't
  * been migrated to a proper locking design yet.
  *
diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c
index 52b6dc1..60f4680 100644
--- a/lib/libcrc32c.c
+++ b/lib/libcrc32c.c
@@ -88,7 +88,7 @@
  * reflect output bytes = true
  */
 
-static u32 crc32c_table[256] = {
+static const u32 crc32c_table[256] = {
 	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
 	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
 	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index b32efae..637d556 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -530,7 +530,7 @@
 			int ret = tag_get(slot, tag, offset);
 
 			BUG_ON(ret && saw_unset_tag);
-			return ret;
+			return !!ret;
 		}
 		slot = slot->slots[offset];
 		shift -= RADIX_TREE_MAP_SHIFT;
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index f8ac9fa..2cc11fa 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -54,7 +54,6 @@
 
 /**
  * rs_init - Initialize a Reed-Solomon codec
- *
  * @symsize:	symbol size, bits (1-8)
  * @gfpoly:	Field generator polynomial coefficients
  * @fcr:	first root of RS code generator polynomial, index form
@@ -62,7 +61,7 @@
  * @nroots:	RS code generator polynomial degree (number of roots)
  *
  * Allocate a control structure and the polynom arrays for faster
- * en/decoding. Fill the arrays according to the given parameters
+ * en/decoding. Fill the arrays according to the given parameters.
  */
 static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
 				   int prim, int nroots)
@@ -155,8 +154,7 @@
 
 
 /**
- *  free_rs - Free the rs control structure, if its not longer used
- *
+ *  free_rs - Free the rs control structure, if it is no longer used
  *  @rs:	the control structure which is not longer used by the
  *		caller
  */
@@ -176,7 +174,6 @@
 
 /**
  * init_rs - Find a matching or allocate a new rs control structure
- *
  *  @symsize:	the symbol size (number of bits)
  *  @gfpoly:	the extended Galois field generator polynomial coefficients,
  *		with the 0th coefficient in the low order bit. The polynomial
@@ -236,7 +233,6 @@
 #ifdef CONFIG_REED_SOLOMON_ENC8
 /**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
- *
  *  @rs:	the rs control structure
  *  @data:	data field of a given type
  *  @len:	data length
@@ -258,7 +254,6 @@
 #ifdef CONFIG_REED_SOLOMON_DEC8
 /**
  *  decode_rs8 - Decode codeword (8bit data width)
- *
  *  @rs:	the rs control structure
  *  @data:	data field of a given type
  *  @par:	received parity data field
@@ -285,7 +280,6 @@
 #ifdef CONFIG_REED_SOLOMON_ENC16
 /**
  *  encode_rs16 - Calculate the parity for data values (16bit data width)
- *
  *  @rs:	the rs control structure
  *  @data:	data field of a given type
  *  @len:	data length
@@ -305,7 +299,6 @@
 #ifdef CONFIG_REED_SOLOMON_DEC16
 /**
  *  decode_rs16 - Decode codeword (16bit data width)
- *
  *  @rs:	the rs control structure
  *  @data:	data field of a given type
  *  @par:	received parity data field
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b07db5c..797428a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -187,49 +187,49 @@
 	size -= precision;
 	if (!(type&(ZEROPAD+LEFT))) {
 		while(size-->0) {
-			if (buf <= end)
+			if (buf < end)
 				*buf = ' ';
 			++buf;
 		}
 	}
 	if (sign) {
-		if (buf <= end)
+		if (buf < end)
 			*buf = sign;
 		++buf;
 	}
 	if (type & SPECIAL) {
 		if (base==8) {
-			if (buf <= end)
+			if (buf < end)
 				*buf = '0';
 			++buf;
 		} else if (base==16) {
-			if (buf <= end)
+			if (buf < end)
 				*buf = '0';
 			++buf;
-			if (buf <= end)
+			if (buf < end)
 				*buf = digits[33];
 			++buf;
 		}
 	}
 	if (!(type & LEFT)) {
 		while (size-- > 0) {
-			if (buf <= end)
+			if (buf < end)
 				*buf = c;
 			++buf;
 		}
 	}
 	while (i < precision--) {
-		if (buf <= end)
+		if (buf < end)
 			*buf = '0';
 		++buf;
 	}
 	while (i-- > 0) {
-		if (buf <= end)
+		if (buf < end)
 			*buf = tmp[i];
 		++buf;
 	}
 	while (size-- > 0) {
-		if (buf <= end)
+		if (buf < end)
 			*buf = ' ';
 		++buf;
 	}
@@ -272,7 +272,8 @@
 				/* 'z' changed to 'Z' --davidm 1/25/99 */
 				/* 't' added for ptrdiff_t */
 
-	/* Reject out-of-range values early */
+	/* Reject out-of-range values early.  Large positive sizes are
+	   used for unknown buffer sizes. */
 	if (unlikely((int) size < 0)) {
 		/* There can be only one.. */
 		static int warn = 1;
@@ -282,16 +283,17 @@
 	}
 
 	str = buf;
-	end = buf + size - 1;
+	end = buf + size;
 
-	if (end < buf - 1) {
-		end = ((void *) -1);
-		size = end - buf + 1;
+	/* Make sure end is always >= buf */
+	if (end < buf) {
+		end = ((void *)-1);
+		size = end - buf;
 	}
 
 	for (; *fmt ; ++fmt) {
 		if (*fmt != '%') {
-			if (str <= end)
+			if (str < end)
 				*str = *fmt;
 			++str;
 			continue;
@@ -357,17 +359,17 @@
 			case 'c':
 				if (!(flags & LEFT)) {
 					while (--field_width > 0) {
-						if (str <= end)
+						if (str < end)
 							*str = ' ';
 						++str;
 					}
 				}
 				c = (unsigned char) va_arg(args, int);
-				if (str <= end)
+				if (str < end)
 					*str = c;
 				++str;
 				while (--field_width > 0) {
-					if (str <= end)
+					if (str < end)
 						*str = ' ';
 					++str;
 				}
@@ -382,18 +384,18 @@
 
 				if (!(flags & LEFT)) {
 					while (len < field_width--) {
-						if (str <= end)
+						if (str < end)
 							*str = ' ';
 						++str;
 					}
 				}
 				for (i = 0; i < len; ++i) {
-					if (str <= end)
+					if (str < end)
 						*str = *s;
 					++str; ++s;
 				}
 				while (len < field_width--) {
-					if (str <= end)
+					if (str < end)
 						*str = ' ';
 					++str;
 				}
@@ -426,7 +428,7 @@
 				continue;
 
 			case '%':
-				if (str <= end)
+				if (str < end)
 					*str = '%';
 				++str;
 				continue;
@@ -449,11 +451,11 @@
 				break;
 
 			default:
-				if (str <= end)
+				if (str < end)
 					*str = '%';
 				++str;
 				if (*fmt) {
-					if (str <= end)
+					if (str < end)
 						*str = *fmt;
 					++str;
 				} else {
@@ -483,14 +485,13 @@
 		str = number(str, end, num, base,
 				field_width, precision, flags);
 	}
-	if (str <= end)
-		*str = '\0';
-	else if (size > 0)
-		/* don't write out a null byte if the buf size is zero */
-		*end = '\0';
-	/* the trailing null byte doesn't count towards the total
-	* ++str;
-	*/
+	if (size > 0) {
+		if (str < end)
+			*str = '\0';
+		else
+			*end = '\0';
+	}
+	/* the trailing null byte doesn't count towards the total */
 	return str-buf;
 }
 
@@ -848,3 +849,26 @@
 }
 
 EXPORT_SYMBOL(sscanf);
+
+
+/* Simplified asprintf. */
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+	va_list ap;
+	unsigned int len;
+	char *p;
+
+	va_start(ap, fmt);
+	len = vsnprintf(NULL, 0, fmt, ap);
+	va_end(ap);
+
+	p = kmalloc(len+1, gfp);
+	if (!p)
+		return NULL;
+	va_start(ap, fmt);
+	vsnprintf(p, len+1, fmt, ap);
+	va_end(ap);
+	return p;
+}
+
+EXPORT_SYMBOL(kasprintf);
diff --git a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c
index 62343c5..da665fb 100644
--- a/lib/zlib_inflate/inftrees.c
+++ b/lib/zlib_inflate/inftrees.c
@@ -8,15 +8,6 @@
 
 #define MAXBITS 15
 
-const char inflate_copyright[] =
-   " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
-/*
-  If you use the zlib library in a product, an acknowledgment is welcome
-  in the documentation of your product. If for some reason you cannot
-  include such an acknowledgment, I would appreciate that you keep this
-  copyright string in the executable of your product.
- */
-
 /*
    Build a set of tables to decode the provided canonical Huffman code.
    The code lengths are lens[0..codes-1].  The result starts at *table,
diff --git a/mm/filemap.c b/mm/filemap.c
index 807a463f..9c7334b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -828,6 +828,32 @@
 }
 EXPORT_SYMBOL(grab_cache_page_nowait);
 
+/*
+ * CD/DVDs are error prone. When a medium error occurs, the driver may fail
+ * a _large_ part of the i/o request. Imagine the worst scenario:
+ *
+ *      ---R__________________________________________B__________
+ *         ^ reading here                             ^ bad block(assume 4k)
+ *
+ * read(R) => miss => readahead(R...B) => media error => frustrating retries
+ * => failing the whole request => read(R) => read(R+1) =>
+ * readahead(R+1...B+1) => bang => read(R+2) => read(R+3) =>
+ * readahead(R+3...B+2) => bang => read(R+3) => read(R+4) =>
+ * readahead(R+4...B+3) => bang => read(R+4) => read(R+5) => ......
+ *
+ * It is going insane. Fix it by quickly scaling down the readahead size.
+ */
+static void shrink_readahead_size_eio(struct file *filp,
+					struct file_ra_state *ra)
+{
+	if (!ra->ra_pages)
+		return;
+
+	ra->ra_pages /= 4;
+	printk(KERN_WARNING "Reducing readahead size to %luK\n",
+			ra->ra_pages << (PAGE_CACHE_SHIFT - 10));
+}
+
 /**
  * do_generic_mapping_read - generic file read routine
  * @mapping:	address_space to be read
@@ -985,6 +1011,7 @@
 				}
 				unlock_page(page);
 				error = -EIO;
+				shrink_readahead_size_eio(filp, &ra);
 				goto readpage_error;
 			}
 			unlock_page(page);
@@ -1522,6 +1549,7 @@
 	 * Things didn't work out. Return zero to tell the
 	 * mm layer so, possibly freeing the page cache page first.
 	 */
+	shrink_readahead_size_eio(file, ra);
 	page_cache_release(page);
 	return NULL;
 }
@@ -1892,7 +1920,7 @@
 EXPORT_SYMBOL(remove_suid);
 
 size_t
-__filemap_copy_from_user_iovec(char *vaddr, 
+__filemap_copy_from_user_iovec_inatomic(char *vaddr,
 			const struct iovec *iov, size_t base, size_t bytes)
 {
 	size_t copied = 0, left = 0;
@@ -1908,12 +1936,8 @@
 		vaddr += copy;
 		iov++;
 
-		if (unlikely(left)) {
-			/* zero the rest of the target like __copy_from_user */
-			if (bytes)
-				memset(vaddr, 0, bytes);
+		if (unlikely(left))
 			break;
-		}
 	}
 	return copied - left;
 }
diff --git a/mm/filemap.h b/mm/filemap.h
index 5683cde..536979f 100644
--- a/mm/filemap.h
+++ b/mm/filemap.h
@@ -16,15 +16,23 @@
 #include <linux/uaccess.h>
 
 size_t
-__filemap_copy_from_user_iovec(char *vaddr,
-			       const struct iovec *iov,
-			       size_t base,
-			       size_t bytes);
+__filemap_copy_from_user_iovec_inatomic(char *vaddr,
+					const struct iovec *iov,
+					size_t base,
+					size_t bytes);
 
 /*
  * Copy as much as we can into the page and return the number of bytes which
  * were sucessfully copied.  If a fault is encountered then clear the page
  * out to (offset+bytes) and return the number of bytes which were copied.
+ *
+ * NOTE: For this to work reliably we really want copy_from_user_inatomic_nocache
+ * to *NOT* zero any tail of the buffer that it failed to copy.  If it does,
+ * and if the following non-atomic copy succeeds, then there is a small window
+ * where the target page contains neither the data before the write, nor the
+ * data after the write (it contains zero).  A read at this time will see
+ * data that is inconsistent with any ordering of the read and the write.
+ * (This has been detected in practice).
  */
 static inline size_t
 filemap_copy_from_user(struct page *page, unsigned long offset,
@@ -60,13 +68,15 @@
 	size_t copied;
 
 	kaddr = kmap_atomic(page, KM_USER0);
-	copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
-						base, bytes);
+	copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov,
+							 base, bytes);
 	kunmap_atomic(kaddr, KM_USER0);
 	if (copied != bytes) {
 		kaddr = kmap(page);
-		copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
-							base, bytes);
+		copied = __filemap_copy_from_user_iovec_inatomic(kaddr + offset, iov,
+								 base, bytes);
+		if (bytes - copied)
+			memset(kaddr + offset + copied, 0, bytes - copied);
 		kunmap(page);
 	}
 	return copied;
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index ec4a1a9..6b9740b 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -632,6 +632,10 @@
 
   	down_read(&mm->mmap_sem);
 
+	err = migrate_vmas(mm, from_nodes, to_nodes, flags);
+	if (err)
+		goto out;
+
 /*
  * Find a 'source' bit set in 'tmp' whose corresponding 'dest'
  * bit in 'to' is not also set in 'tmp'.  Clear the found 'source'
@@ -691,7 +695,7 @@
 		if (err < 0)
 			break;
 	}
-
+out:
 	up_read(&mm->mmap_sem);
 	if (err < 0)
 		return err;
@@ -1817,7 +1821,7 @@
 
 int show_numa_map(struct seq_file *m, void *v)
 {
-	struct task_struct *task = m->private;
+	struct proc_maps_private *priv = m->private;
 	struct vm_area_struct *vma = v;
 	struct numa_maps *md;
 	struct file *file = vma->vm_file;
@@ -1833,7 +1837,7 @@
 		return 0;
 
 	mpol_to_str(buffer, sizeof(buffer),
-			get_vma_policy(task, vma, vma->vm_start));
+			    get_vma_policy(priv->task, vma, vma->vm_start));
 
 	seq_printf(m, "%08lx %s", vma->vm_start, buffer);
 
@@ -1887,7 +1891,7 @@
 	kfree(md);
 
 	if (m->count < m->size)
-		m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
+		m->version = (vma != priv->tail_vma) ? vma->vm_start : 0;
 	return 0;
 }
 
diff --git a/mm/migrate.c b/mm/migrate.c
index 1c2a71aa..3f1e0c2 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -616,15 +616,13 @@
 	/*
 	 * Establish migration ptes or remove ptes
 	 */
-	if (try_to_unmap(page, 1) != SWAP_FAIL) {
-		if (!page_mapped(page))
-			rc = move_to_new_page(newpage, page);
-	} else
-		/* A vma has VM_LOCKED set -> permanent failure */
-		rc = -EPERM;
+	try_to_unmap(page, 1);
+	if (!page_mapped(page))
+		rc = move_to_new_page(newpage, page);
 
 	if (rc)
 		remove_migration_ptes(page, page);
+
 unlock:
 	unlock_page(page);
 
@@ -976,3 +974,23 @@
 }
 #endif
 
+/*
+ * Call migration functions in the vma_ops that may prepare
+ * memory in a vm for migration. migration functions may perform
+ * the migration for vmas that do not have an underlying page struct.
+ */
+int migrate_vmas(struct mm_struct *mm, const nodemask_t *to,
+	const nodemask_t *from, unsigned long flags)
+{
+ 	struct vm_area_struct *vma;
+ 	int err = 0;
+
+ 	for(vma = mm->mmap; vma->vm_next && !err; vma = vma->vm_next) {
+ 		if (vma->vm_ops && vma->vm_ops->migrate) {
+ 			err = vma->vm_ops->migrate(vma, to, from, flags);
+ 			if (err)
+ 				break;
+ 		}
+ 	}
+ 	return err;
+}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 423db0d..9f86191 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -266,7 +266,7 @@
  * satisfies the following equation:
  *     P = B & ~(1 << O)
  *
- * Assumption: *_mem_map is contigious at least up to MAX_ORDER
+ * Assumption: *_mem_map is contiguous at least up to MAX_ORDER
  */
 static inline struct page *
 __page_find_buddy(struct page *page, unsigned long page_idx, unsigned int order)
@@ -957,8 +957,7 @@
 		goto got_pg;
 
 	do {
-		if (cpuset_zone_allowed(*z, gfp_mask|__GFP_HARDWALL))
-			wakeup_kswapd(*z, order);
+		wakeup_kswapd(*z, order);
 	} while (*(++z));
 
 	/*
diff --git a/mm/pdflush.c b/mm/pdflush.c
index df7e50b..b02102f 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -104,21 +104,20 @@
 		list_move(&my_work->list, &pdflush_list);
 		my_work->when_i_went_to_sleep = jiffies;
 		spin_unlock_irq(&pdflush_lock);
-
 		schedule();
-		if (try_to_freeze()) {
-			spin_lock_irq(&pdflush_lock);
-			continue;
-		}
-
+		try_to_freeze();
 		spin_lock_irq(&pdflush_lock);
 		if (!list_empty(&my_work->list)) {
-			printk("pdflush: bogus wakeup!\n");
+			/*
+			 * Someone woke us up, but without removing our control
+			 * structure from the global list.  swsusp will do this
+			 * in try_to_freeze()->refrigerator().  Handle it.
+			 */
 			my_work->fn = NULL;
 			continue;
 		}
 		if (my_work->fn == NULL) {
-			printk("pdflush: NULL work function\n");
+			printk("pdflush: bogus wakeup\n");
 			continue;
 		}
 		spin_unlock_irq(&pdflush_lock);
diff --git a/mm/readahead.c b/mm/readahead.c
index 0f142a4..aa7ec42 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -118,8 +118,7 @@
 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
 
 /**
- * read_cache_pages - populate an address space with some pages, and
- * 			start reads against them.
+ * read_cache_pages - populate an address space with some pages & start reads against them
  * @mapping: the address_space
  * @pages: The address of a list_head which contains the target pages.  These
  *   pages have their ->index populated and are otherwise uninitialised.
@@ -182,14 +181,11 @@
 		list_del(&page->lru);
 		if (!add_to_page_cache(page, mapping,
 					page->index, GFP_KERNEL)) {
-			ret = mapping->a_ops->readpage(filp, page);
-			if (ret != AOP_TRUNCATED_PAGE) {
-				if (!pagevec_add(&lru_pvec, page))
-					__pagevec_lru_add(&lru_pvec);
-				continue;
-			} /* else fall through to release */
-		}
-		page_cache_release(page);
+			mapping->a_ops->readpage(filp, page);
+			if (!pagevec_add(&lru_pvec, page))
+				__pagevec_lru_add(&lru_pvec);
+		} else
+			page_cache_release(page);
 	}
 	pagevec_lru_add(&lru_pvec);
 	ret = 0;
@@ -394,8 +390,8 @@
  * Read 'nr_to_read' pages starting at page 'offset'. If the flag 'block'
  * is set wait till the read completes.  Otherwise attempt to read without
  * blocking.
- * Returns 1 meaning 'success' if read is succesfull without switching off
- * readhaead mode. Otherwise return failure.
+ * Returns 1 meaning 'success' if read is successful without switching off
+ * readahead mode. Otherwise return failure.
  */
 static int
 blockable_page_cache_readahead(struct address_space *mapping, struct file *filp,
diff --git a/mm/rmap.c b/mm/rmap.c
index 882a858..e76909e 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -562,9 +562,8 @@
 	 * If it's recently referenced (perhaps page_referenced
 	 * skipped over this mm) then we should reactivate it.
 	 */
-	if ((vma->vm_flags & VM_LOCKED) ||
-			(ptep_clear_flush_young(vma, address, pte)
-				&& !migration)) {
+	if (!migration && ((vma->vm_flags & VM_LOCKED) ||
+			(ptep_clear_flush_young(vma, address, pte)))) {
 		ret = SWAP_FAIL;
 		goto out_unmap;
 	}
@@ -771,7 +770,7 @@
 
 	list_for_each_entry(vma, &mapping->i_mmap_nonlinear,
 						shared.vm_set.list) {
-		if (vma->vm_flags & VM_LOCKED)
+		if ((vma->vm_flags & VM_LOCKED) && !migration)
 			continue;
 		cursor = (unsigned long) vma->vm_private_data;
 		if (cursor > max_nl_cursor)
@@ -805,7 +804,7 @@
 	do {
 		list_for_each_entry(vma, &mapping->i_mmap_nonlinear,
 						shared.vm_set.list) {
-			if (vma->vm_flags & VM_LOCKED)
+			if ((vma->vm_flags & VM_LOCKED) && !migration)
 				continue;
 			cursor = (unsigned long) vma->vm_private_data;
 			while ( cursor < max_nl_cursor &&
diff --git a/mm/shmem.c b/mm/shmem.c
index 84b5cf9..38bc333 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2255,7 +2255,7 @@
 #ifdef CONFIG_TMPFS
 	devfs_mk_dir("shm");
 #endif
-	shm_mnt = do_kern_mount(tmpfs_fs_type.name, MS_NOUSER,
+	shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
 				tmpfs_fs_type.name, NULL);
 	if (IS_ERR(shm_mnt)) {
 		error = PTR_ERR(shm_mnt);
diff --git a/mm/swap.c b/mm/swap.c
index 03ae207..990868a 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -86,8 +86,7 @@
 	zone = page_zone(page);
 	spin_lock_irqsave(&zone->lru_lock, flags);
 	if (PageLRU(page) && !PageActive(page)) {
-		list_del(&page->lru);
-		list_add_tail(&page->lru, &zone->inactive_list);
+		list_move_tail(&page->lru, &zone->inactive_list);
 		inc_page_state(pgrotated);
 	}
 	if (!test_clear_page_writeback(page))
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index a48a5d5..5fe77df 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -1113,10 +1113,9 @@
 
 static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
 {
-	unsigned char *ip;
-
 	uint32_t dst_ip = msg->content.in_info.in_dst_ip;
 	in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
+
 	dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip));
 	ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry);
 	if(entry == NULL){
diff --git a/net/core/dev.c b/net/core/dev.c
index ea24693..f1c52cb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -230,7 +230,7 @@
  *	For efficiency
  */
 
-int netdev_nit;
+static int netdev_nit;
 
 /*
  *	Add a protocol ID to the list. Now that the input handler is
@@ -1325,9 +1325,12 @@
 		nskb->next = NULL;
 		rc = dev->hard_start_xmit(nskb, dev);
 		if (unlikely(rc)) {
+			nskb->next = skb->next;
 			skb->next = nskb;
 			return rc;
 		}
+		if (unlikely(netif_queue_stopped(dev) && skb->next))
+			return NETDEV_TX_BUSY;
 	} while (skb->next);
 	
 	skb->destructor = DEV_GSO_CB(skb)->destructor;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 9cb7818..471da45 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -54,6 +54,7 @@
 				sizeof(struct iphdr) + sizeof(struct ethhdr))
 
 static void zap_completion_queue(void);
+static void arp_reply(struct sk_buff *skb);
 
 static void queue_process(void *p)
 {
@@ -153,6 +154,22 @@
 	}
 }
 
+static void service_arp_queue(struct netpoll_info *npi)
+{
+	struct sk_buff *skb;
+
+	if (unlikely(!npi))
+		return;
+
+	skb = skb_dequeue(&npi->arp_tx);
+
+	while (skb != NULL) {
+		arp_reply(skb);
+		skb = skb_dequeue(&npi->arp_tx);
+	}
+	return;
+}
+
 void netpoll_poll(struct netpoll *np)
 {
 	if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
@@ -163,6 +180,8 @@
 	if (np->dev->poll)
 		poll_napi(np);
 
+	service_arp_queue(np->dev->npinfo);
+
 	zap_completion_queue();
 }
 
@@ -279,14 +298,10 @@
 		 * network drivers do not expect to be called if the queue is
 		 * stopped.
 		 */
-		if (netif_queue_stopped(np->dev)) {
-			netif_tx_unlock(np->dev);
-			netpoll_poll(np);
-			udelay(50);
-			continue;
-		}
+		status = NETDEV_TX_BUSY;
+		if (!netif_queue_stopped(np->dev))
+			status = np->dev->hard_start_xmit(skb, np->dev);
 
-		status = np->dev->hard_start_xmit(skb, np->dev);
 		netif_tx_unlock(np->dev);
 
 		/* success */
@@ -446,7 +461,9 @@
 	int proto, len, ulen;
 	struct iphdr *iph;
 	struct udphdr *uh;
-	struct netpoll *np = skb->dev->npinfo->rx_np;
+	struct netpoll_info *npi = skb->dev->npinfo;
+	struct netpoll *np = npi->rx_np;
+
 
 	if (!np)
 		goto out;
@@ -456,7 +473,7 @@
 	/* check if netpoll clients need ARP */
 	if (skb->protocol == __constant_htons(ETH_P_ARP) &&
 	    atomic_read(&trapped)) {
-		arp_reply(skb);
+		skb_queue_tail(&npi->arp_tx, skb);
 		return 1;
 	}
 
@@ -651,6 +668,7 @@
 		npinfo->poll_owner = -1;
 		npinfo->tries = MAX_RETRIES;
 		spin_lock_init(&npinfo->rx_lock);
+		skb_queue_head_init(&npinfo->arp_tx);
 	} else
 		npinfo = ndev->npinfo;
 
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 8e5044b..6edbb90 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1739,12 +1739,15 @@
 			   unsigned int to, struct ts_config *config,
 			   struct ts_state *state)
 {
+	unsigned int ret;
+
 	config->get_next_block = skb_ts_get_next_block;
 	config->finish = skb_ts_finish;
 
 	skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));
 
-	return textsearch_find(config, state);
+	ret = textsearch_find(config, state);
+	return (ret <= to - from ? ret : UINT_MAX);
 }
 
 /**
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index cee3397..706c002 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1761,7 +1761,7 @@
 		goto free_newinfo;
 
 	/* And one copy for every other CPU */
-	for_each_cpu(i)
+	for_each_possible_cpu(i)
 		if (newinfo->entries[i] && newinfo->entries[i] != entry1)
 			memcpy(newinfo->entries[i], entry1, newinfo->size);
 
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index cc9423d..60b11ae 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -244,7 +244,7 @@
 
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
 #define RT_CACHE_STAT_INC(field) \
-	(per_cpu(rt_cache_stat, raw_smp_processor_id()).field++)
+	(__raw_get_cpu_var(rt_cache_stat).field++)
 
 static int rt_intern_hash(unsigned hash, struct rtable *rth,
 				struct rtable **res);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0e029c4..c04176b 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2166,7 +2166,7 @@
 	if (!pskb_may_pull(skb, thlen))
 		goto out;
 
-	oldlen = ~htonl(skb->len);
+	oldlen = (u16)~skb->len;
 	__skb_pull(skb, thlen);
 
 	segs = skb_segment(skb, sg);
@@ -2174,7 +2174,7 @@
 		goto out;
 
 	len = skb_shinfo(skb)->gso_size;
-	delta = csum_add(oldlen, htonl(thlen + len));
+	delta = htonl(oldlen + (thlen + len));
 
 	skb = segs;
 	th = skb->h.th;
@@ -2183,10 +2183,10 @@
 	do {
 		th->fin = th->psh = 0;
 
-		if (skb->ip_summed == CHECKSUM_NONE) {
-			th->check = csum_fold(csum_partial(
-				skb->h.raw, thlen, csum_add(skb->csum, delta)));
-		}
+		th->check = ~csum_fold(th->check + delta);
+		if (skb->ip_summed != CHECKSUM_HW)
+			th->check = csum_fold(csum_partial(skb->h.raw, thlen,
+							   skb->csum));
 
 		seq += len;
 		skb = skb->next;
@@ -2196,11 +2196,11 @@
 		th->cwr = 0;
 	} while (skb->next);
 
-	if (skb->ip_summed == CHECKSUM_NONE) {
-		delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw));
-		th->check = csum_fold(csum_partial(
-			skb->h.raw, thlen, csum_add(skb->csum, delta)));
-	}
+	delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
+	th->check = ~csum_fold(th->check + delta);
+	if (skb->ip_summed != CHECKSUM_HW)
+		th->check = csum_fold(csum_partial(skb->h.raw, thlen,
+						   skb->csum));
 
 out:
 	return segs;
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index b3b9097..c11737f 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -725,15 +725,17 @@
 	struct nr_node  *nr_node = NULL;
 
 	spin_lock_bh(&nr_neigh_list_lock);
-	nr_neigh_for_each(s, node, &nr_neigh_list)
+	nr_neigh_for_each(s, node, &nr_neigh_list) {
 		if (s->ax25 == ax25) {
 			nr_neigh_hold(s);
 			nr_neigh = s;
 			break;
 		}
+	}
 	spin_unlock_bh(&nr_neigh_list_lock);
 
-	if (nr_neigh == NULL) return;
+	if (nr_neigh == NULL)
+		return;
 
 	nr_neigh->ax25 = NULL;
 	ax25_cb_put(ax25);
@@ -743,11 +745,13 @@
 		return;
 	}
 	spin_lock_bh(&nr_node_list_lock);
-	nr_node_for_each(nr_node, node, &nr_node_list)
+	nr_node_for_each(nr_node, node, &nr_node_list) {
 		nr_node_lock(nr_node);
-		if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh)
+		if (nr_node->which < nr_node->count &&
+		    nr_node->routes[nr_node->which].neighbour == nr_neigh)
 			nr_node->which++;
 		nr_node_unlock(nr_node);
+	}
 	spin_unlock_bh(&nr_node_list_lock);
 	nr_neigh_put(nr_neigh);
 }
diff --git a/net/rxrpc/call.c b/net/rxrpc/call.c
index c4aeb7d..d07122b 100644
--- a/net/rxrpc/call.c
+++ b/net/rxrpc/call.c
@@ -1098,8 +1098,7 @@
 
 		call->app_ready_seq = pmsg->seq;
 		call->app_ready_qty += pmsg->dsize;
-		list_del_init(&pmsg->link);
-		list_add_tail(&pmsg->link, &call->app_readyq);
+		list_move_tail(&pmsg->link, &call->app_readyq);
 	}
 
 	/* see if we've got the last packet yet */
diff --git a/net/rxrpc/connection.c b/net/rxrpc/connection.c
index 0e0a455..573b572 100644
--- a/net/rxrpc/connection.c
+++ b/net/rxrpc/connection.c
@@ -402,8 +402,7 @@
 
 	/* move to graveyard queue */
 	_debug("burying connection: {%08x}", ntohl(conn->conn_id));
-	list_del(&conn->link);
-	list_add_tail(&conn->link, &peer->conn_graveyard);
+	list_move_tail(&conn->link, &peer->conn_graveyard);
 
 	rxrpc_krxtimod_add_timer(&conn->timeout, rxrpc_conn_timeout * HZ);
 
diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c
index 1aadd02..cea4eb5 100644
--- a/net/rxrpc/krxsecd.c
+++ b/net/rxrpc/krxsecd.c
@@ -160,8 +160,7 @@
 	list_for_each_safe(_p, _n, &rxrpc_krxsecd_initmsgq) {
 		msg = list_entry(_p, struct rxrpc_message, link);
 		if (msg->trans == trans) {
-			list_del(&msg->link);
-			list_add_tail(&msg->link, &tmp);
+			list_move_tail(&msg->link, &tmp);
 			atomic_dec(&rxrpc_krxsecd_qcount);
 		}
 	}
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 129e2bd..b8714a8 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -169,7 +169,7 @@
 	}
 
 	ctx_id->internal_ctx_id = ctx;
-	dprintk("RPC:      Succesfully imported new context.\n");
+	dprintk("RPC:      Successfully imported new context.\n");
 	return 0;
 
 out_err_free_key2:
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 5bf11cc..3d0432a 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -201,7 +201,7 @@
 
 	ctx_id->internal_ctx_id = ctx;
 
-	dprintk("Succesfully imported new spkm context.\n");
+	dprintk("Successfully imported new spkm context.\n");
 	return 0;
 
 out_err_free_key2:
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index f56767a..2eccffa 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -118,6 +118,8 @@
 	.au_cslack	= 4,
 	.au_rslack	= 2,
 	.au_ops		= &authnull_ops,
+	.au_flavor	= RPC_AUTH_NULL,
+	.au_count	= ATOMIC_INIT(0),
 };
 
 static
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index df14b6b..74c7406 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -225,6 +225,7 @@
 	.au_cslack	= UNX_WRITESLACK,
 	.au_rslack	= 2,			/* assume AUTH_NULL verf */
 	.au_ops		= &authunix_ops,
+	.au_flavor	= RPC_AUTH_UNIX,
 	.au_count	= ATOMIC_INIT(0),
 	.au_credcache	= &unix_cred_cache,
 };
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 8241fa7..dafe793 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -439,7 +439,7 @@
 {
 	int err;
 
-	err = simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
+	err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count);
 	if (err != 0)
 		return ERR_PTR(err);
 	return rpc_mount;
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index ca4bfa5..49174f0 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -568,8 +568,7 @@
  *
  * Moves data beyond the current pointer position from the XDR head[] buffer
  * into the page list. Any data that lies beyond current position + "len"
- * bytes is moved into the XDR tail[]. The current pointer is then
- * repositioned at the beginning of the XDR tail.
+ * bytes is moved into the XDR tail[].
  */
 void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 {
@@ -606,6 +605,31 @@
 }
 EXPORT_SYMBOL(xdr_read_pages);
 
+/**
+ * xdr_enter_page - decode data from the XDR page
+ * @xdr: pointer to xdr_stream struct
+ * @len: number of bytes of page data
+ *
+ * Moves data beyond the current pointer position from the XDR head[] buffer
+ * into the page list. Any data that lies beyond current position + "len"
+ * bytes is moved into the XDR tail[]. The current pointer is then
+ * repositioned at the beginning of the first XDR page.
+ */
+void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
+{
+	char * kaddr = page_address(xdr->buf->pages[0]);
+	xdr_read_pages(xdr, len);
+	/*
+	 * Position current pointer at beginning of tail, and
+	 * set remaining message length.
+	 */
+	if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
+		len = PAGE_CACHE_SIZE - xdr->buf->page_base;
+	xdr->p = (uint32_t *)(kaddr + xdr->buf->page_base);
+	xdr->end = (uint32_t *)((char *)xdr->p + len);
+}
+EXPORT_SYMBOL(xdr_enter_page);
+
 static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
 
 void
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 4dd5b3c..02060d0 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -41,7 +41,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
-#include <linux/random.h>
+#include <linux/net.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/metrics.h>
@@ -830,7 +830,7 @@
 
 static inline void xprt_init_xid(struct rpc_xprt *xprt)
 {
-	get_random_bytes(&xprt->xid, sizeof(xprt->xid));
+	xprt->xid = net_random();
 }
 
 static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 4b4e7df..21006b1 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -930,6 +930,13 @@
 	xprt_adjust_cwnd(task, -ETIMEDOUT);
 }
 
+static unsigned short xs_get_random_port(void)
+{
+	unsigned short range = xprt_max_resvport - xprt_min_resvport;
+	unsigned short rand = (unsigned short) net_random() % range;
+	return rand + xprt_min_resvport;
+}
+
 /**
  * xs_set_port - reset the port number in the remote endpoint address
  * @xprt: generic transport
@@ -1275,7 +1282,7 @@
 	memset(xprt->slot, 0, slot_table_size);
 
 	xprt->prot = IPPROTO_UDP;
-	xprt->port = xprt_max_resvport;
+	xprt->port = xs_get_random_port();
 	xprt->tsh_size = 0;
 	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
 	/* XXX: header size can vary due to auth type, IPv6, etc. */
@@ -1317,7 +1324,7 @@
 	memset(xprt->slot, 0, slot_table_size);
 
 	xprt->prot = IPPROTO_TCP;
-	xprt->port = xprt_max_resvport;
+	xprt->port = xs_get_random_port();
 	xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
 	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
 	xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 2c4ecbe..5412804 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -49,13 +49,19 @@
 #include "name_table.h"
 #include "bcast.h"
 
-
 #define MAX_PKT_DEFAULT_MCAST 1500	/* bcast link max packet size (fixed) */
 
 #define BCLINK_WIN_DEFAULT 20		/* bcast link window size (default) */
 
 #define BCLINK_LOG_BUF_SIZE 0
 
+/*
+ * Loss rate for incoming broadcast frames; used to test retransmission code.
+ * Set to N to cause every N'th frame to be discarded; 0 => don't discard any.
+ */
+ 
+#define TIPC_BCAST_LOSS_RATE 0
+
 /**
  * struct bcbearer_pair - a pair of bearers used by broadcast link
  * @primary: pointer to primary bearer
@@ -75,7 +81,14 @@
  * @bearer: (non-standard) broadcast bearer structure
  * @media: (non-standard) broadcast media structure
  * @bpairs: array of bearer pairs
- * @bpairs_temp: array of bearer pairs used during creation of "bpairs"
+ * @bpairs_temp: temporary array of bearer pairs used by tipc_bcbearer_sort()
+ * @remains: temporary node map used by tipc_bcbearer_send()
+ * @remains_new: temporary node map used tipc_bcbearer_send()
+ * 
+ * Note: The fields labelled "temporary" are incorporated into the bearer
+ * to avoid consuming potentially limited stack space through the use of
+ * large local variables within multicast routines.  Concurrent access is
+ * prevented through use of the spinlock "bc_lock".
  */
 
 struct bcbearer {
@@ -83,6 +96,8 @@
 	struct media media;
 	struct bcbearer_pair bpairs[MAX_BEARERS];
 	struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
+	struct node_map remains;
+	struct node_map remains_new;
 };
 
 /**
@@ -165,21 +180,18 @@
  * @after: sequence number of last packet to *not* retransmit
  * @to: sequence number of last packet to retransmit
  * 
- * Called with 'node' locked, bc_lock unlocked
+ * Called with bc_lock locked
  */
 
 static void bclink_retransmit_pkt(u32 after, u32 to)
 {
 	struct sk_buff *buf;
 
-	spin_lock_bh(&bc_lock);
 	buf = bcl->first_out;
 	while (buf && less_eq(buf_seqno(buf), after)) {
 		buf = buf->next;                
 	}
-	if (buf != NULL)
-		tipc_link_retransmit(bcl, buf, mod(to - after));
-	spin_unlock_bh(&bc_lock);              
+	tipc_link_retransmit(bcl, buf, mod(to - after));
 }
 
 /** 
@@ -346,8 +358,10 @@
 		for (; buf; buf = buf->next) {
 			u32 seqno = buf_seqno(buf);
 
-			if (mod(seqno - prev) != 1)
+			if (mod(seqno - prev) != 1) {
 				buf = NULL;
+				break;
+			}
 			if (seqno == gap_after)
 				break;
 			prev = seqno;
@@ -399,7 +413,10 @@
  */
 
 void tipc_bclink_recv_pkt(struct sk_buff *buf)
-{        
+{
+#if (TIPC_BCAST_LOSS_RATE)
+	static int rx_count = 0;
+#endif
 	struct tipc_msg *msg = buf_msg(buf);
 	struct node* node = tipc_node_find(msg_prevnode(msg));
 	u32 next_in;
@@ -420,9 +437,13 @@
 			tipc_node_lock(node);
 			tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
 			tipc_node_unlock(node);
+			spin_lock_bh(&bc_lock);
 			bcl->stats.recv_nacks++;
+			bcl->owner->next = node;   /* remember requestor */
 			bclink_retransmit_pkt(msg_bcgap_after(msg),
 					      msg_bcgap_to(msg));
+			bcl->owner->next = NULL;
+			spin_unlock_bh(&bc_lock);              
 		} else {
 			tipc_bclink_peek_nack(msg_destnode(msg),
 					      msg_bcast_tag(msg),
@@ -433,6 +454,14 @@
 		return;
 	}
 
+#if (TIPC_BCAST_LOSS_RATE)
+	if (++rx_count == TIPC_BCAST_LOSS_RATE) {
+		rx_count = 0;
+		buf_discard(buf);
+		return;
+	}
+#endif
+
 	tipc_node_lock(node);
 receive:
 	deferred = node->bclink.deferred_head;
@@ -531,12 +560,8 @@
 {
 	static int send_count = 0;
 
-	struct node_map *remains;
-	struct node_map *remains_new;
-	struct node_map *remains_tmp;
 	int bp_index;
 	int swap_time;
-	int err;
 
 	/* Prepare buffer for broadcasting (if first time trying to send it) */
 
@@ -557,9 +582,7 @@
 
 	/* Send buffer over bearers until all targets reached */
 	
-	remains = kmalloc(sizeof(struct node_map), GFP_ATOMIC);
-	remains_new = kmalloc(sizeof(struct node_map), GFP_ATOMIC);
-	*remains = tipc_cltr_bcast_nodes;
+	bcbearer->remains = tipc_cltr_bcast_nodes;
 
 	for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
 		struct bearer *p = bcbearer->bpairs[bp_index].primary;
@@ -568,8 +591,8 @@
 		if (!p)
 			break;	/* no more bearers to try */
 
-		tipc_nmap_diff(remains, &p->nodes, remains_new);
-		if (remains_new->count == remains->count)
+		tipc_nmap_diff(&bcbearer->remains, &p->nodes, &bcbearer->remains_new);
+		if (bcbearer->remains_new.count == bcbearer->remains.count)
 			continue;	/* bearer pair doesn't add anything */
 
 		if (!p->publ.blocked &&
@@ -587,27 +610,17 @@
 		bcbearer->bpairs[bp_index].primary = s;
 		bcbearer->bpairs[bp_index].secondary = p;
 update:
-		if (remains_new->count == 0) {
-			err = TIPC_OK;
-			goto out;
-		}
+		if (bcbearer->remains_new.count == 0)
+			return TIPC_OK;
 
-		/* swap map */
-		remains_tmp = remains;
-		remains = remains_new;
-		remains_new = remains_tmp;
+		bcbearer->remains = bcbearer->remains_new;
 	}
 	
 	/* Unable to reach all targets */
 
 	bcbearer->bearer.publ.blocked = 1;
 	bcl->stats.bearer_congs++;
-	err = ~TIPC_OK;
-
- out:
-	kfree(remains_new);
-	kfree(remains);
-	return err;
+	return ~TIPC_OK;
 }
 
 /**
@@ -765,7 +778,7 @@
 	bclink = kmalloc(sizeof(*bclink), GFP_ATOMIC);
 	if (!bcbearer || !bclink) {
  nomem:
-	 	warn("Memory squeeze; Failed to create multicast link\n");
+	 	warn("Multicast link creation failed, no memory\n");
 		kfree(bcbearer);
 		bcbearer = NULL;
 		kfree(bclink);
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index 0e3be2a..b243d9d 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -180,7 +180,7 @@
 		if (!item->next) {
 			item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
 			if (!item->next) {
-				warn("Memory squeeze: multicast destination port list is incomplete\n");
+				warn("Incomplete multicast delivery, no memory\n");
 				return;
 			}
 			item->next->next = NULL;
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index e213a8e..4fa24b5 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -112,39 +112,42 @@
 		goto exit;
 
 	if (!media_name_valid(name)) {
-		warn("Media registration error: illegal name <%s>\n", name);
+		warn("Media <%s> rejected, illegal name\n", name);
 		goto exit;
 	}
 	if (!bcast_addr) {
-		warn("Media registration error: no broadcast address supplied\n");
+		warn("Media <%s> rejected, no broadcast address\n", name);
 		goto exit;
 	}
 	if ((bearer_priority < TIPC_MIN_LINK_PRI) &&
 	    (bearer_priority > TIPC_MAX_LINK_PRI)) {
-		warn("Media registration error: priority %u\n", bearer_priority);
+		warn("Media <%s> rejected, illegal priority (%u)\n", name, 
+		     bearer_priority);
 		goto exit;
 	}
 	if ((link_tolerance < TIPC_MIN_LINK_TOL) || 
 	    (link_tolerance > TIPC_MAX_LINK_TOL)) {
-		warn("Media registration error: tolerance %u\n", link_tolerance);
+		warn("Media <%s> rejected, illegal tolerance (%u)\n", name,
+		     link_tolerance);
 		goto exit;
 	}
 
 	media_id = media_count++;
 	if (media_id >= MAX_MEDIA) {
-		warn("Attempt to register more than %u media\n", MAX_MEDIA);
+		warn("Media <%s> rejected, media limit reached (%u)\n", name,
+		     MAX_MEDIA);
 		media_count--;
 		goto exit;
 	}
 	for (i = 0; i < media_id; i++) {
 		if (media_list[i].type_id == media_type) {
-			warn("Attempt to register second media with type %u\n", 
+			warn("Media <%s> rejected, duplicate type (%u)\n", name,
 			     media_type);
 			media_count--;
 			goto exit;
 		}
 		if (!strcmp(name, media_list[i].name)) {
-			warn("Attempt to re-register media name <%s>\n", name);
+			warn("Media <%s> rejected, duplicate name\n", name);
 			media_count--;
 			goto exit;
 		}
@@ -283,6 +286,9 @@
 	struct bearer *b_ptr;
 	u32 i;
 
+	if (tipc_mode != TIPC_NET_MODE)
+		return NULL;
+
 	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
 		if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
 			return b_ptr;
@@ -475,26 +481,33 @@
 	u32 i;
 	int res = -EINVAL;
 
-	if (tipc_mode != TIPC_NET_MODE)
+	if (tipc_mode != TIPC_NET_MODE) {
+		warn("Bearer <%s> rejected, not supported in standalone mode\n",
+		     name);
 		return -ENOPROTOOPT;
-
-	if (!bearer_name_validate(name, &b_name) ||
-	    !tipc_addr_domain_valid(bcast_scope) ||
-	    !in_scope(bcast_scope, tipc_own_addr))
+	}
+	if (!bearer_name_validate(name, &b_name)) {
+		warn("Bearer <%s> rejected, illegal name\n", name);
 		return -EINVAL;
-
+	}
+	if (!tipc_addr_domain_valid(bcast_scope) || 
+	    !in_scope(bcast_scope, tipc_own_addr)) {
+		warn("Bearer <%s> rejected, illegal broadcast scope\n", name);
+		return -EINVAL;
+	}
 	if ((priority < TIPC_MIN_LINK_PRI ||
 	     priority > TIPC_MAX_LINK_PRI) &&
-	    (priority != TIPC_MEDIA_LINK_PRI))
+	    (priority != TIPC_MEDIA_LINK_PRI)) {
+		warn("Bearer <%s> rejected, illegal priority\n", name);
 		return -EINVAL;
+	}
 
 	write_lock_bh(&tipc_net_lock);
-	if (!tipc_bearers)
-		goto failed;
 
 	m_ptr = media_find(b_name.media_name);
 	if (!m_ptr) {
-		warn("No media <%s>\n", b_name.media_name);
+		warn("Bearer <%s> rejected, media <%s> not registered\n", name,
+		     b_name.media_name);
 		goto failed;
 	}
 
@@ -510,23 +523,24 @@
 			continue;
 		}
 		if (!strcmp(name, tipc_bearers[i].publ.name)) {
-			warn("Bearer <%s> already enabled\n", name);
+			warn("Bearer <%s> rejected, already enabled\n", name);
 			goto failed;
 		}
 		if ((tipc_bearers[i].priority == priority) &&
 		    (++with_this_prio > 2)) {
 			if (priority-- == 0) {
-				warn("Third bearer <%s> with priority %u, unable to lower to %u\n",
-				     name, priority + 1, priority);
+				warn("Bearer <%s> rejected, duplicate priority\n",
+				     name);
 				goto failed;
 			}
-			warn("Third bearer <%s> with priority %u, lowering to %u\n",
+			warn("Bearer <%s> priority adjustment required %u->%u\n",
 			     name, priority + 1, priority);
 			goto restart;
 		}
 	}
 	if (bearer_id >= MAX_BEARERS) {
-		warn("Attempt to enable more than %d bearers\n", MAX_BEARERS);
+		warn("Bearer <%s> rejected, bearer limit reached (%u)\n", 
+		     name, MAX_BEARERS);
 		goto failed;
 	}
 
@@ -536,7 +550,7 @@
 	strcpy(b_ptr->publ.name, name);
 	res = m_ptr->enable_bearer(&b_ptr->publ);
 	if (res) {
-		warn("Failed to enable bearer <%s>\n", name);
+		warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res);
 		goto failed;
 	}
 
@@ -573,9 +587,6 @@
 	struct link *l_ptr;
 	struct link *temp_l_ptr;
 
-	if (tipc_mode != TIPC_NET_MODE)
-		return -ENOPROTOOPT;
-
 	read_lock_bh(&tipc_net_lock);
 	b_ptr = bearer_find(name);
 	if (!b_ptr) {
@@ -584,6 +595,7 @@
 		return -EINVAL;
 	}
 
+	info("Blocking bearer <%s>\n", name);
 	spin_lock_bh(&b_ptr->publ.lock);
 	b_ptr->publ.blocked = 1;
 	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
@@ -595,7 +607,6 @@
 	}
 	spin_unlock_bh(&b_ptr->publ.lock);
 	read_unlock_bh(&tipc_net_lock);
-	info("Blocked bearer <%s>\n", name);
 	return TIPC_OK;
 }
 
@@ -611,15 +622,13 @@
 	struct link *l_ptr;
 	struct link *temp_l_ptr;
 
-	if (tipc_mode != TIPC_NET_MODE)
-		return -ENOPROTOOPT;
-
 	b_ptr = bearer_find(name);
 	if (!b_ptr) {
 		warn("Attempt to disable unknown bearer <%s>\n", name);
 		return -EINVAL;
 	}
 
+	info("Disabling bearer <%s>\n", name);
 	tipc_disc_stop_link_req(b_ptr->link_req);
 	spin_lock_bh(&b_ptr->publ.lock);
 	b_ptr->link_req = NULL;
@@ -635,7 +644,6 @@
 		tipc_link_delete(l_ptr);
 	}
 	spin_unlock_bh(&b_ptr->publ.lock);
-	info("Disabled bearer <%s>\n", name);
 	memset(b_ptr, 0, sizeof(struct bearer));
 	return TIPC_OK;
 }
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
index 1aed815..1dcb694 100644
--- a/net/tipc/cluster.c
+++ b/net/tipc/cluster.c
@@ -60,8 +60,10 @@
 	int alloc;
 
 	c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC);
-	if (c_ptr == NULL)
+	if (c_ptr == NULL) {
+		warn("Cluster creation failure, no memory\n");
 		return NULL;
+	}
 	memset(c_ptr, 0, sizeof(*c_ptr));
 
 	c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
@@ -70,30 +72,32 @@
 	else
 		max_nodes = tipc_max_nodes + 1;
 	alloc = sizeof(void *) * (max_nodes + 1);
+
 	c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC);
 	if (c_ptr->nodes == NULL) {
+		warn("Cluster creation failure, no memory for node area\n");
 		kfree(c_ptr);
 		return NULL;
 	}
-	memset(c_ptr->nodes, 0, alloc);  
+	memset(c_ptr->nodes, 0, alloc);
+
 	if (in_own_cluster(addr))
 		tipc_local_nodes = c_ptr->nodes;
 	c_ptr->highest_slave = LOWEST_SLAVE - 1;
 	c_ptr->highest_node = 0;
 	
 	z_ptr = tipc_zone_find(tipc_zone(addr));
-	if (z_ptr == NULL) {
+	if (!z_ptr) {
 		z_ptr = tipc_zone_create(addr);
 	}
-	if (z_ptr != NULL) {
-		tipc_zone_attach_cluster(z_ptr, c_ptr);
-		c_ptr->owner = z_ptr;
-	}
-	else {
+	if (!z_ptr) {
+		kfree(c_ptr->nodes);
 		kfree(c_ptr);
-		c_ptr = NULL;
+		return NULL;
 	}
 
+	tipc_zone_attach_cluster(z_ptr, c_ptr);
+	c_ptr->owner = z_ptr;
 	return c_ptr;
 }
 
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 48b5de2..3ec502fa 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -291,13 +291,22 @@
 	if (!tipc_addr_node_valid(addr))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (node address)");
-	if (tipc_own_addr)
+	if (tipc_mode == TIPC_NET_MODE)
 		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 						   " (cannot change node address once assigned)");
+	tipc_own_addr = addr;
+
+	/* 
+	 * Must release all spinlocks before calling start_net() because
+	 * Linux version of TIPC calls eth_media_start() which calls
+	 * register_netdevice_notifier() which may block!
+	 *
+	 * Temporarily releasing the lock should be harmless for non-Linux TIPC,
+	 * but Linux version of eth_media_start() should really be reworked
+	 * so that it can be called with spinlocks held.
+	 */
 
 	spin_unlock_bh(&config_lock);
-	tipc_core_stop_net();
-	tipc_own_addr = addr;
 	tipc_core_start_net();
 	spin_lock_bh(&config_lock);
 	return tipc_cfg_reply_none();
@@ -350,50 +359,21 @@
 
 static struct sk_buff *cfg_set_max_ports(void)
 {
-	int orig_mode;
 	u32 value;
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 	value = *(u32 *)TLV_DATA(req_tlv_area);
 	value = ntohl(value);
+	if (value == tipc_max_ports)
+		return tipc_cfg_reply_none();
 	if (value != delimit(value, 127, 65535))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max ports must be 127-65535)");
-
-	if (value == tipc_max_ports)
-		return tipc_cfg_reply_none();
-
-	if (atomic_read(&tipc_user_count) > 2)
+	if (tipc_mode != TIPC_NOT_RUNNING)
 		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
-						   " (cannot change max ports while TIPC users exist)");
-
-	spin_unlock_bh(&config_lock);
-	orig_mode = tipc_get_mode();
-	if (orig_mode == TIPC_NET_MODE)
-		tipc_core_stop_net();
-	tipc_core_stop();
+			" (cannot change max ports while TIPC is active)");
 	tipc_max_ports = value;
-	tipc_core_start();
-	if (orig_mode == TIPC_NET_MODE)
-		tipc_core_start_net();
-	spin_lock_bh(&config_lock);
-	return tipc_cfg_reply_none();
-}
-
-static struct sk_buff *set_net_max(int value, int *parameter)
-{
-	int orig_mode;
-
-	if (value != *parameter) {
-		orig_mode = tipc_get_mode();
-		if (orig_mode == TIPC_NET_MODE)
-			tipc_core_stop_net();
-		*parameter = value;
-		if (orig_mode == TIPC_NET_MODE)
-			tipc_core_start_net();
-	}
-
 	return tipc_cfg_reply_none();
 }
 
@@ -405,10 +385,16 @@
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 	value = *(u32 *)TLV_DATA(req_tlv_area);
 	value = ntohl(value);
+	if (value == tipc_max_zones)
+		return tipc_cfg_reply_none();
 	if (value != delimit(value, 1, 255))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max zones must be 1-255)");
-	return set_net_max(value, &tipc_max_zones);
+	if (tipc_mode == TIPC_NET_MODE)
+		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+			" (cannot change max zones once TIPC has joined a network)");
+	tipc_max_zones = value;
+	return tipc_cfg_reply_none();
 }
 
 static struct sk_buff *cfg_set_max_clusters(void)
@@ -419,8 +405,8 @@
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 	value = *(u32 *)TLV_DATA(req_tlv_area);
 	value = ntohl(value);
-	if (value != 1)
-		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+	if (value != delimit(value, 1, 1))
+		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max clusters fixed at 1)");
 	return tipc_cfg_reply_none();
 }
@@ -433,10 +419,16 @@
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 	value = *(u32 *)TLV_DATA(req_tlv_area);
 	value = ntohl(value);
+	if (value == tipc_max_nodes)
+		return tipc_cfg_reply_none();
 	if (value != delimit(value, 8, 2047))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (max nodes must be 8-2047)");
-	return set_net_max(value, &tipc_max_nodes);
+	if (tipc_mode == TIPC_NET_MODE)
+		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+			" (cannot change max nodes once TIPC has joined a network)");
+	tipc_max_nodes = value;
+	return tipc_cfg_reply_none();
 }
 
 static struct sk_buff *cfg_set_max_slaves(void)
@@ -461,15 +453,16 @@
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 	value = *(u32 *)TLV_DATA(req_tlv_area);
 	value = ntohl(value);
+	if (value == tipc_net_id)
+		return tipc_cfg_reply_none();
 	if (value != delimit(value, 1, 9999))
 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 						   " (network id must be 1-9999)");
-
-	if (tipc_own_addr)
+	if (tipc_mode == TIPC_NET_MODE)
 		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
-						   " (cannot change network id once part of network)");
-	
-	return set_net_max(value, &tipc_net_id);
+			" (cannot change network id once TIPC has joined a network)");
+	tipc_net_id = value;
+	return tipc_cfg_reply_none();
 }
 
 struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
@@ -649,7 +642,7 @@
 	if ((size < sizeof(*req_hdr)) ||
 	    (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
 	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
-		warn("discarded invalid configuration message\n");
+		warn("Invalid configuration message discarded\n");
 		return;
 	}
 
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 3d0a8ee..5003acb 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -2,7 +2,7 @@
  * net/tipc/core.c: TIPC module code
  *
  * Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,7 @@
 int  tipc_netlink_start(void);
 void tipc_netlink_stop(void);
 
-#define MOD_NAME "tipc_start: "
+#define TIPC_MOD_VER "1.6.1"
 
 #ifndef CONFIG_TIPC_ZONES
 #define CONFIG_TIPC_ZONES 3
@@ -198,7 +198,7 @@
 	tipc_max_publications = 10000;
 	tipc_max_subscriptions = 2000;
 	tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
-	tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 511);
+	tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 255);
 	tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
 	tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
 	tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
@@ -224,6 +224,7 @@
 
 MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(TIPC_MOD_VER);
 
 /* Native TIPC API for kernel-space applications (see tipc.h) */
 
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 1f2e8b2..86f54f3 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -2,7 +2,7 @@
  * net/tipc/core.h: Include file for TIPC global declarations
  * 
  * Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -111,10 +111,6 @@
 
 #else
 
-#ifndef DBG_OUTPUT
-#define DBG_OUTPUT NULL
-#endif
-
 /*
  * TIPC debug support not included:
  * - system messages are printed to system console
@@ -129,6 +125,19 @@
 #define msg_dbg(msg,txt) do {} while (0)
 #define dump(fmt,arg...) do {} while (0)
 
+
+/*	
+ * TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is
+ * the null print buffer.  Thes ensures that any system or debug messages 
+ * that are generated without using the above macros are handled correctly.
+ */
+
+#undef  TIPC_OUTPUT
+#define TIPC_OUTPUT TIPC_CONS
+
+#undef  DBG_OUTPUT
+#define DBG_OUTPUT NULL
+
 #endif			  
 
 
@@ -309,7 +318,7 @@
  * buf_discard - frees a TIPC message buffer
  * @skb: message buffer
  *
- * Frees a new buffer.  If passed NULL, just returns.
+ * Frees a message buffer.  If passed NULL, just returns.
  */
 
 static inline void buf_discard(struct sk_buff *skb)
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 9260138..2b84412 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -2,7 +2,7 @@
  * net/tipc/discover.c
  * 
  * Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -176,7 +176,6 @@
 			n_ptr = tipc_node_create(orig);
 		}
 		if (n_ptr == NULL) {
-			warn("Memory squeeze; Failed to create node\n");
 			return;
 		}
 		spin_lock_bh(&n_ptr->lock);
@@ -191,10 +190,8 @@
 		}
 		addr = &link->media_addr;
 		if (memcmp(addr, &media_addr, sizeof(*addr))) {
-			char addr_string[16];
-
-			warn("New bearer address for %s\n", 
-			     addr_string_fill(addr_string, orig));
+			warn("Resetting link <%s>, peer interface address changed\n",
+			     link->name);
 			memcpy(addr, &media_addr, sizeof(*addr));
 			tipc_link_reset(link);     
 		}
@@ -270,8 +267,8 @@
 		/* leave timer interval "as is" if already at a "normal" rate */
 	} else {
 		req->timer_intv *= 2;
-		if (req->timer_intv > TIPC_LINK_REQ_SLOW)
-			req->timer_intv = TIPC_LINK_REQ_SLOW;
+		if (req->timer_intv > TIPC_LINK_REQ_FAST)
+			req->timer_intv = TIPC_LINK_REQ_FAST;
 		if ((req->timer_intv == TIPC_LINK_REQ_FAST) && 
 		    (req->bearer->nodes.count))
 			req->timer_intv = TIPC_LINK_REQ_SLOW;
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 7a25278..682da4a 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -2,7 +2,7 @@
  * net/tipc/eth_media.c: Ethernet bearer support for TIPC
  * 
  * Copyright (c) 2001-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -98,17 +98,19 @@
 	u32 size;
 
 	if (likely(eb_ptr->bearer)) {
-		size = msg_size((struct tipc_msg *)buf->data);
-		skb_trim(buf, size);
-		if (likely(buf->len == size)) {
-			buf->next = NULL;
-			tipc_recv_msg(buf, eb_ptr->bearer);
-		} else {
-			kfree_skb(buf);
+	       if (likely(!dev->promiscuity) ||
+	           !memcmp(buf->mac.raw,dev->dev_addr,ETH_ALEN) ||
+	           !memcmp(buf->mac.raw,dev->broadcast,ETH_ALEN)) {
+		        size = msg_size((struct tipc_msg *)buf->data);
+	                skb_trim(buf, size);
+	        	if (likely(buf->len == size)) {
+		        	buf->next = NULL;
+			        tipc_recv_msg(buf, eb_ptr->bearer);
+			        return TIPC_OK;
+			}
 		}
-	} else {
-		kfree_skb(buf);
 	}
+	kfree_skb(buf);
 	return TIPC_OK;
 }
 
@@ -125,8 +127,7 @@
 
 	/* Find device with specified name */
 
-	while (dev && dev->name &&
-	       (memcmp(dev->name, driver_name, strlen(dev->name)))) {
+	while (dev && dev->name && strncmp(dev->name, driver_name, IFNAMSIZ)) {	
 		dev = dev->next;
 	}
 	if (!dev)
@@ -252,7 +253,9 @@
 	if (eth_started)
 		return -EINVAL;
 
-	memset(&bcast_addr, 0xff, sizeof(bcast_addr));
+	bcast_addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
+	memset(&bcast_addr.dev_addr, 0xff, ETH_ALEN);
+
 	memset(eth_bearers, 0, sizeof(eth_bearers));
 
 	res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth",
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 784b24b6..d646580 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -419,7 +419,7 @@
 
 	l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC);
 	if (!l_ptr) {
-		warn("Memory squeeze; Failed to create link\n");
+		warn("Link creation failed, no memory\n");
 		return NULL;
 	}
 	memset(l_ptr, 0, sizeof(*l_ptr));
@@ -469,7 +469,7 @@
 
 		if (!pb) {
 			kfree(l_ptr);
-			warn("Memory squeeze; Failed to create link\n");
+			warn("Link creation failed, no memory for print buffer\n");
 			return NULL;
 		}
 		tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
@@ -574,7 +574,6 @@
 			break;
 		list_del_init(&p_ptr->wait_list);
 		p_ptr->congested_link = NULL;
-		assert(p_ptr->wakeup);
 		spin_lock_bh(p_ptr->publ.lock);
 		p_ptr->publ.congested = 0;
 		p_ptr->wakeup(&p_ptr->publ);
@@ -691,6 +690,7 @@
 	struct sk_buff *buf;
 	u32 prev_state = l_ptr->state;
 	u32 checkpoint = l_ptr->next_in_no;
+	int was_active_link = tipc_link_is_active(l_ptr);
 	
 	msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
 
@@ -712,7 +712,7 @@
 	tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name);
 	dbg_link_dump();
 #endif
-	if (tipc_node_has_active_links(l_ptr->owner) &&
+	if (was_active_link && tipc_node_has_active_links(l_ptr->owner) &&
 	    l_ptr->owner->permit_changeover) {
 		l_ptr->reset_checkpoint = checkpoint;
 		l_ptr->exp_msg_count = START_CHANGEOVER;
@@ -755,7 +755,7 @@
 
 static void link_activate(struct link *l_ptr)
 {
-	l_ptr->next_in_no = 1;
+	l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
 	tipc_node_link_up(l_ptr->owner, l_ptr);
 	tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
 	link_send_event(tipc_cfg_link_event, l_ptr, 1);
@@ -820,6 +820,8 @@
 			break;
 		case RESET_MSG:
 			dbg_link("RES -> RR\n");
+			info("Resetting link <%s>, requested by peer\n", 
+			     l_ptr->name);
 			tipc_link_reset(l_ptr);
 			l_ptr->state = RESET_RESET;
 			l_ptr->fsm_msg_cnt = 0;
@@ -844,6 +846,8 @@
 			break;
 		case RESET_MSG:
 			dbg_link("RES -> RR\n");
+			info("Resetting link <%s>, requested by peer "
+			     "while probing\n", l_ptr->name);
 			tipc_link_reset(l_ptr);
 			l_ptr->state = RESET_RESET;
 			l_ptr->fsm_msg_cnt = 0;
@@ -875,6 +879,8 @@
 			} else {	/* Link has failed */
 				dbg_link("-> RU (%u probes unanswered)\n",
 					 l_ptr->fsm_msg_cnt);
+				warn("Resetting link <%s>, peer not responding\n",
+				     l_ptr->name);
 				tipc_link_reset(l_ptr);
 				l_ptr->state = RESET_UNKNOWN;
 				l_ptr->fsm_msg_cnt = 0;
@@ -1050,7 +1056,7 @@
 		msg_dbg(msg, "TIPC: Congestion, throwing away\n");
 		buf_discard(buf);
 		if (imp > CONN_MANAGER) {
-			warn("Resetting <%s>, send queue full", l_ptr->name);
+			warn("Resetting link <%s>, send queue full", l_ptr->name);
 			tipc_link_reset(l_ptr);
 		}
 		return dsz;
@@ -1135,9 +1141,13 @@
 	if (n_ptr) {
 		tipc_node_lock(n_ptr);
 		l_ptr = n_ptr->active_links[selector & 1];
-		dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest);
 		if (l_ptr) {
+			dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest);
 			res = tipc_link_send_buf(l_ptr, buf);
+		} else {
+			dbg("Attempt to send msg to unreachable node:\n");
+			msg_dbg(buf_msg(buf),">>>");
+			buf_discard(buf);
 		}
 		tipc_node_unlock(n_ptr);
 	} else {
@@ -1242,8 +1252,6 @@
 	int res;
 	u32 selector = msg_origport(hdr) & 1;
 
-	assert(destaddr != tipc_own_addr);
-
 again:
 	/*
 	 * Try building message using port's max_pkt hint.
@@ -1604,40 +1612,121 @@
 		tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
 }
 
+static void link_reset_all(unsigned long addr)
+{
+	struct node *n_ptr;
+	char addr_string[16];
+	u32 i;
+
+	read_lock_bh(&tipc_net_lock);
+	n_ptr = tipc_node_find((u32)addr);
+	if (!n_ptr) {
+		read_unlock_bh(&tipc_net_lock);
+		return;	/* node no longer exists */
+	}
+
+	tipc_node_lock(n_ptr);
+
+	warn("Resetting all links to %s\n", 
+	     addr_string_fill(addr_string, n_ptr->addr));
+
+	for (i = 0; i < MAX_BEARERS; i++) {
+		if (n_ptr->links[i]) {
+			link_print(n_ptr->links[i], TIPC_OUTPUT, 
+				   "Resetting link\n");
+			tipc_link_reset(n_ptr->links[i]);
+		}
+	}
+
+	tipc_node_unlock(n_ptr);
+	read_unlock_bh(&tipc_net_lock);
+}
+
+static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+
+	warn("Retransmission failure on link <%s>\n", l_ptr->name);
+	tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
+
+	if (l_ptr->addr) {
+
+		/* Handle failure on standard link */
+
+		link_print(l_ptr, TIPC_OUTPUT, "Resetting link\n");
+		tipc_link_reset(l_ptr);
+
+	} else {
+
+		/* Handle failure on broadcast link */
+
+		struct node *n_ptr;
+		char addr_string[16];
+
+		tipc_printf(TIPC_OUTPUT, "Msg seq number: %u,  ", msg_seqno(msg));
+		tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle);
+		
+		n_ptr = l_ptr->owner->next;
+		tipc_node_lock(n_ptr);
+
+		addr_string_fill(addr_string, n_ptr->addr);
+		tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string);
+		tipc_printf(TIPC_OUTPUT, "Supported: %d,  ", n_ptr->bclink.supported);
+		tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked);
+		tipc_printf(TIPC_OUTPUT, "Last in: %u,  ", n_ptr->bclink.last_in);
+		tipc_printf(TIPC_OUTPUT, "Gap after: %u,  ", n_ptr->bclink.gap_after);
+		tipc_printf(TIPC_OUTPUT, "Gap to: %u\n", n_ptr->bclink.gap_to);
+		tipc_printf(TIPC_OUTPUT, "Nack sync: %u\n\n", n_ptr->bclink.nack_sync);
+
+		tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
+
+		tipc_node_unlock(n_ptr);
+
+		l_ptr->stale_count = 0;
+	}
+}
+
 void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, 
 			  u32 retransmits)
 {
 	struct tipc_msg *msg;
 
+	if (!buf)
+		return;
+
+	msg = buf_msg(buf);
+	
 	dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
 
-	if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) {
-		msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>");
-		dbg_print_link(l_ptr, "   ");
-		l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
-		l_ptr->retransm_queue_size = retransmits;
-		return;
+	if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
+		if (!skb_cloned(buf)) {
+			msg_dbg(msg, ">NO_RETR->BCONG>");
+			dbg_print_link(l_ptr, "   ");
+			l_ptr->retransm_queue_head = msg_seqno(msg);
+			l_ptr->retransm_queue_size = retransmits;
+			return;
+		} else {
+			/* Don't retransmit if driver already has the buffer */
+		}
+	} else {
+		/* Detect repeated retransmit failures on uncongested bearer */
+
+		if (l_ptr->last_retransmitted == msg_seqno(msg)) {
+			if (++l_ptr->stale_count > 100) {
+				link_retransmit_failure(l_ptr, buf);
+				return;
+			}
+		} else {
+			l_ptr->last_retransmitted = msg_seqno(msg);
+			l_ptr->stale_count = 1;
+		}
 	}
+
 	while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
 		msg = buf_msg(buf);
 		msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
 		msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
 		if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
-                        /* Catch if retransmissions fail repeatedly: */
-                        if (l_ptr->last_retransmitted == msg_seqno(msg)) {
-                                if (++l_ptr->stale_count > 100) {
-                                        tipc_msg_print(TIPC_CONS, buf_msg(buf), ">RETR>");
-                                        info("...Retransmitted %u times\n",
-					     l_ptr->stale_count);
-                                        link_print(l_ptr, TIPC_CONS, "Resetting Link\n");
-                                        tipc_link_reset(l_ptr);
-                                        break;
-                                }
-                        } else {
-                                l_ptr->stale_count = 0;
-                        }
-                        l_ptr->last_retransmitted = msg_seqno(msg);
-
 			msg_dbg(buf_msg(buf), ">RETR>");
 			buf = buf->next;
 			retransmits--;
@@ -1650,6 +1739,7 @@
 			return;
 		}
 	}
+
 	l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
 }
 
@@ -1720,6 +1810,11 @@
 			link_recv_non_seq(buf);
 			continue;
 		}
+		
+		if (unlikely(!msg_short(msg) &&
+			     (msg_destnode(msg) != tipc_own_addr)))
+			goto cont;
+		
 		n_ptr = tipc_node_find(msg_prevnode(msg));
 		if (unlikely(!n_ptr))
 			goto cont;
@@ -2140,7 +2235,7 @@
 		
 		if (msg_linkprio(msg) && 
 		    (msg_linkprio(msg) != l_ptr->priority)) {
-			warn("Changing prio <%s>: %u->%u\n",
+			warn("Resetting link <%s>, priority change %u->%u\n",
 			     l_ptr->name, l_ptr->priority, msg_linkprio(msg));
 			l_ptr->priority = msg_linkprio(msg);
 			tipc_link_reset(l_ptr); /* Enforce change to take effect */
@@ -2209,17 +2304,22 @@
 	u32 length = msg_size(msg);
 
 	tunnel = l_ptr->owner->active_links[selector & 1];
-	if (!tipc_link_is_up(tunnel))
+	if (!tipc_link_is_up(tunnel)) {
+		warn("Link changeover error, "
+		     "tunnel link no longer available\n");
 		return;
+	}
 	msg_set_size(tunnel_hdr, length + INT_H_SIZE);
 	buf = buf_acquire(length + INT_H_SIZE);
-	if (!buf)
+	if (!buf) {
+		warn("Link changeover error, "
+		     "unable to send tunnel msg\n");
 		return;
+	}
 	memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
 	memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
 	dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
 	msg_dbg(buf_msg(buf), ">SEND>");
-	assert(tunnel);
 	tipc_link_send_buf(tunnel, buf);
 }
 
@@ -2235,23 +2335,27 @@
 	u32 msgcount = l_ptr->out_queue_size;
 	struct sk_buff *crs = l_ptr->first_out;
 	struct link *tunnel = l_ptr->owner->active_links[0];
-	int split_bundles = tipc_node_has_redundant_links(l_ptr->owner);
 	struct tipc_msg tunnel_hdr;
+	int split_bundles;
 
 	if (!tunnel)
 		return;
 
-	if (!l_ptr->owner->permit_changeover)
+	if (!l_ptr->owner->permit_changeover) {
+		warn("Link changeover error, "
+		     "peer did not permit changeover\n");
 		return;
+	}
 
 	msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
 		 ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
 	msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
 	msg_set_msgcnt(&tunnel_hdr, msgcount);
+	dbg("Link changeover requires %u tunnel messages\n", msgcount);
+
 	if (!l_ptr->first_out) {
 		struct sk_buff *buf;
 
-		assert(!msgcount);
 		buf = buf_acquire(INT_H_SIZE);
 		if (buf) {
 			memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
@@ -2261,10 +2365,15 @@
 			msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
 			tipc_link_send_buf(tunnel, buf);
 		} else {
-			warn("Memory squeeze; link changeover failed\n");
+			warn("Link changeover error, "
+			     "unable to send changeover msg\n");
 		}
 		return;
 	}
+
+	split_bundles = (l_ptr->owner->active_links[0] != 
+			 l_ptr->owner->active_links[1]);
+
 	while (crs) {
 		struct tipc_msg *msg = buf_msg(crs);
 
@@ -2310,7 +2419,8 @@
 		msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
 		outbuf = buf_acquire(length + INT_H_SIZE);
 		if (outbuf == NULL) {
-			warn("Memory squeeze; buffer duplication failed\n");
+			warn("Link changeover error, "
+			     "unable to send duplicate msg\n");
 			return;
 		}
 		memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
@@ -2364,11 +2474,15 @@
 	u32 msg_count = msg_msgcnt(tunnel_msg);
 
 	dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
-	assert(dest_link != *l_ptr);
 	if (!dest_link) {
 		msg_dbg(tunnel_msg, "NOLINK/<REC<");
 		goto exit;
 	}
+	if (dest_link == *l_ptr) {
+		err("Unexpected changeover message on link <%s>\n", 
+		    (*l_ptr)->name);
+		goto exit;
+	}
 	dbg("%c<-%c:", dest_link->b_ptr->net_plane,
 	    (*l_ptr)->b_ptr->net_plane);
 	*l_ptr = dest_link;
@@ -2381,7 +2495,7 @@
 		}
 		*buf = buf_extract(tunnel_buf,INT_H_SIZE);
 		if (*buf == NULL) {
-			warn("Memory squeeze; failed to extract msg\n");
+			warn("Link changeover error, duplicate msg dropped\n");
 			goto exit;
 		}
 		msg_dbg(tunnel_msg, "TNL<REC<");
@@ -2393,13 +2507,17 @@
 
 	if (tipc_link_is_up(dest_link)) {
 		msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
+		info("Resetting link <%s>, changeover initiated by peer\n",
+		     dest_link->name);
 		tipc_link_reset(dest_link);
 		dest_link->exp_msg_count = msg_count;
+		dbg("Expecting %u tunnelled messages\n", msg_count);
 		if (!msg_count)
 			goto exit;
 	} else if (dest_link->exp_msg_count == START_CHANGEOVER) {
 		msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
 		dest_link->exp_msg_count = msg_count;
+		dbg("Expecting %u tunnelled messages\n", msg_count);
 		if (!msg_count)
 			goto exit;
 	}
@@ -2407,6 +2525,8 @@
 	/* Receive original message */
 
 	if (dest_link->exp_msg_count == 0) {
+		warn("Link switchover error, "
+		     "got too many tunnelled messages\n");
 		msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
 		dbg_print_link(dest_link, "LINK:");
 		goto exit;
@@ -2422,7 +2542,7 @@
 			buf_discard(tunnel_buf);
 			return 1;
 		} else {
-			warn("Memory squeeze; dropped incoming msg\n");
+			warn("Link changeover error, original msg dropped\n");
 		}
 	}
 exit:
@@ -2444,13 +2564,8 @@
 	while (msgcount--) {
 		obuf = buf_extract(buf, pos);
 		if (obuf == NULL) {
-			char addr_string[16];
-
-			warn("Buffer allocation failure;\n");
-			warn("  incoming message(s) from %s lost\n",
-			     addr_string_fill(addr_string, 
-					      msg_orignode(buf_msg(buf))));
-			return;
+			warn("Link unable to unbundle message(s)\n");
+			break;
 		};
 		pos += align(msg_size(buf_msg(obuf)));
 		msg_dbg(buf_msg(obuf), "     /");
@@ -2508,7 +2623,7 @@
 		}
 		fragm = buf_acquire(fragm_sz + INT_H_SIZE);
 		if (fragm == NULL) {
-			warn("Memory squeeze; failed to fragment msg\n");
+			warn("Link unable to fragment message\n");
 			dsz = -ENOMEM;
 			goto exit;
 		}
@@ -2623,7 +2738,7 @@
 			set_fragm_size(pbuf,fragm_sz); 
 			set_expected_frags(pbuf,exp_fragm_cnt - 1); 
 		} else {
-			warn("Memory squeeze; got no defragmenting buffer\n");
+			warn("Link unable to reassemble fragmented message\n");
 		}
 		buf_discard(fbuf);
 		return 0;
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index a3bbc89..f0b063b 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -127,7 +127,7 @@
 
 	buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
 	if (!buf) {
-		warn("Memory squeeze; failed to distribute publication\n");
+		warn("Publication distribution failure\n");
 		return;
 	}
 
@@ -151,7 +151,7 @@
 
 	buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
 	if (!buf) {
-		warn("Memory squeeze; failed to distribute withdrawal\n");
+		warn("Withdrawl distribution failure\n");
 		return;
 	}
 
@@ -174,7 +174,6 @@
 	u32 rest;
 	u32 max_item_buf;
 
-	assert(in_own_cluster(node));
 	read_lock_bh(&tipc_nametbl_lock); 
 	max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
 	max_item_buf *= ITEM_SIZE;
@@ -185,8 +184,8 @@
 			left = (rest <= max_item_buf) ? rest : max_item_buf;
 			rest -= left;
 			buf = named_prepare_buf(PUBLICATION, left, node);       
-			if (buf == NULL) {
-				warn("Memory Squeeze; could not send publication\n");
+			if (!buf) {
+				warn("Bulk publication distribution failure\n");
 				goto exit;
 			}
 			item = (struct distr_item *)msg_data(buf_msg(buf));
@@ -221,15 +220,24 @@
 static void node_is_down(struct publication *publ)
 {
 	struct publication *p;
+
         write_lock_bh(&tipc_nametbl_lock);
 	dbg("node_is_down: withdrawing %u, %u, %u\n", 
 	    publ->type, publ->lower, publ->upper);
         publ->key += 1222345;
 	p = tipc_nametbl_remove_publ(publ->type, publ->lower, 
 				     publ->node, publ->ref, publ->key);
-        assert(p == publ);
 	write_unlock_bh(&tipc_nametbl_lock);
-	kfree(publ);
+
+        if (p != publ) {
+		err("Unable to remove publication from failed node\n"
+		    "(type=%u, lower=%u, node=0x%x, ref=%u, key=%u)\n",
+		    publ->type, publ->lower, publ->node, publ->ref, publ->key);
+	}
+
+	if (p) {
+		kfree(p);
+	}
 }
 
 /**
@@ -275,9 +283,15 @@
 			if (publ) {
 				tipc_nodesub_unsubscribe(&publ->subscr);
         			kfree(publ);
+			} else {
+				err("Unable to remove publication by node 0x%x\n"
+				    "(type=%u, lower=%u, ref=%u, key=%u)\n",
+				    msg_orignode(msg),
+				    ntohl(item->type), ntohl(item->lower),
+				    ntohl(item->ref), ntohl(item->key));
 			}
 		} else {
-			warn("tipc_named_recv: unknown msg\n");
+			warn("Unrecognized name table message received\n");
 		}
 		item++;
 	}
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index d129422..3857130 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -71,7 +71,7 @@
  * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
  *        sub-sequences are sorted in ascending order
  * @alloc: number of sub-sequences currently in array
- * @first_free: upper bound of highest sub-sequence + 1
+ * @first_free: array index of first unused sub-sequence entry
  * @ns_list: links to adjacent name sequences in hash chain
  * @subscriptions: list of subscriptions for this 'type'
  * @lock: spinlock controlling access to name sequence structure
@@ -120,7 +120,7 @@
 	struct publication *publ =
 		(struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
 	if (publ == NULL) {
-		warn("Memory squeeze; failed to create publication\n");
+		warn("Publication creation failure, no memory\n");
 		return NULL;
 	}
 
@@ -165,7 +165,7 @@
 	struct sub_seq *sseq = tipc_subseq_alloc(1);
 
 	if (!nseq || !sseq) {
-		warn("Memory squeeze; failed to create name sequence\n");
+		warn("Name sequence creation failed, no memory\n");
 		kfree(nseq);
 		kfree(sseq);
 		return NULL;
@@ -175,7 +175,7 @@
 	nseq->lock = SPIN_LOCK_UNLOCKED;
 	nseq->type = type;
 	nseq->sseqs = sseq;
-	dbg("tipc_nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n",
+	dbg("tipc_nameseq_create(): nseq = %p, type %u, ssseqs %p, ff: %u\n",
 	    nseq, type, nseq->sseqs, nseq->first_free);
 	nseq->alloc = 1;
 	INIT_HLIST_NODE(&nseq->ns_list);
@@ -253,16 +253,16 @@
 	struct sub_seq *sseq;
 	int created_subseq = 0;
 
-	assert(nseq->first_free <= nseq->alloc);
 	sseq = nameseq_find_subseq(nseq, lower);
-	dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n",
+	dbg("nameseq_ins: for seq %p, {%u,%u}, found sseq %p\n",
 	    nseq, type, lower, sseq);
 	if (sseq) {
 
 		/* Lower end overlaps existing entry => need an exact match */
 
 		if ((sseq->lower != lower) || (sseq->upper != upper)) {
-			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
+			warn("Cannot publish {%u,%u,%u}, overlap error\n",
+			     type, lower, upper);
 			return NULL;
 		}
 	} else {
@@ -277,25 +277,27 @@
 
 		if ((inspos < nseq->first_free) &&
 		    (upper >= nseq->sseqs[inspos].lower)) {
-			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
+			warn("Cannot publish {%u,%u,%u}, overlap error\n",
+			     type, lower, upper);
 			return NULL;
 		}
 
 		/* Ensure there is space for new sub-sequence */
 
 		if (nseq->first_free == nseq->alloc) {
-			struct sub_seq *sseqs = nseq->sseqs;
-			nseq->sseqs = tipc_subseq_alloc(nseq->alloc * 2);
-			if (nseq->sseqs != NULL) {
-				memcpy(nseq->sseqs, sseqs,
-				       nseq->alloc * sizeof (struct sub_seq));
-				kfree(sseqs);
-				dbg("Allocated %u sseqs\n", nseq->alloc);
-				nseq->alloc *= 2;
-			} else {
-				warn("Memory squeeze; failed to create sub-sequence\n");
+			struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);
+
+			if (!sseqs) {
+				warn("Cannot publish {%u,%u,%u}, no memory\n",
+				     type, lower, upper);
 				return NULL;
 			}
+			dbg("Allocated %u more sseqs\n", nseq->alloc);
+			memcpy(sseqs, nseq->sseqs,
+			       nseq->alloc * sizeof(struct sub_seq));
+			kfree(nseq->sseqs);
+			nseq->sseqs = sseqs;
+			nseq->alloc *= 2;
 		}
 		dbg("Have %u sseqs for type %u\n", nseq->alloc, type);
 
@@ -311,7 +313,7 @@
 		sseq->upper = upper;
 		created_subseq = 1;
 	}
-	dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n",
+	dbg("inserting {%u,%u,%u} from <0x%x:%u> into sseq %p(%u,%u) of seq %p\n",
 	    type, lower, upper, node, port, sseq,
 	    sseq->lower, sseq->upper, nseq);
 
@@ -320,7 +322,7 @@
 	publ = publ_create(type, lower, upper, scope, node, port, key);
 	if (!publ)
 		return NULL;
-	dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n",
+	dbg("inserting publ %p, node=0x%x publ->node=0x%x, subscr->node=%p\n",
 	    publ, node, publ->node, publ->subscr.node);
 
 	if (!sseq->zone_list)
@@ -367,45 +369,47 @@
 
 /**
  * tipc_nameseq_remove_publ -
+ * 
+ * NOTE: There may be cases where TIPC is asked to remove a publication
+ * that is not in the name table.  For example, if another node issues a
+ * publication for a name sequence that overlaps an existing name sequence
+ * the publication will not be recorded, which means the publication won't
+ * be found when the name sequence is later withdrawn by that node.
+ * A failed withdraw request simply returns a failure indication and lets the
+ * caller issue any error or warning messages associated with such a problem.
  */
 
 static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
 						    u32 node, u32 ref, u32 key)
 {
 	struct publication *publ;
+	struct publication *curr;
 	struct publication *prev;
 	struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
 	struct sub_seq *free;
 	struct subscription *s, *st;
 	int removed_subseq = 0;
 
-	assert(nseq);
-
-	if (!sseq) {
-		int i;
-
-		warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst);
-		assert(nseq->sseqs);
-		dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n",
-		    nseq->sseqs, nseq, nseq->alloc, 
-		    nseq->first_free);
-		for (i = 0; i < nseq->first_free; i++) {
-			dbg("Subseq %u(%x): lower = %u,upper = %u\n",
-			    i, &nseq->sseqs[i], nseq->sseqs[i].lower,
-			    nseq->sseqs[i].upper);
-		}
+	if (!sseq)
 		return NULL;
-	}
-	dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n",
+
+	dbg("tipc_nameseq_remove_publ: seq: %p, sseq %p, {%u,%u}, key %u\n",
 	    nseq, sseq, nseq->type, inst, key);
 
+	/* Remove publication from zone scope list */
+
 	prev = sseq->zone_list;
 	publ = sseq->zone_list->zone_list_next;
 	while ((publ->key != key) || (publ->ref != ref) || 
 	       (publ->node && (publ->node != node))) {
 		prev = publ;
 		publ = publ->zone_list_next;
-		assert(prev != sseq->zone_list);
+		if (prev == sseq->zone_list) {
+			
+			/* Prevent endless loop if publication not found */
+
+			return NULL;
+		}
 	}
 	if (publ != sseq->zone_list)
 		prev->zone_list_next = publ->zone_list_next;
@@ -416,14 +420,24 @@
 		sseq->zone_list = NULL;
 	}
 
+	/* Remove publication from cluster scope list, if present */
+
 	if (in_own_cluster(node)) {
 		prev = sseq->cluster_list;
-		publ = sseq->cluster_list->cluster_list_next;
-		while ((publ->key != key) || (publ->ref != ref) || 
-		       (publ->node && (publ->node != node))) {
-			prev = publ;
-			publ = publ->cluster_list_next;
-			assert(prev != sseq->cluster_list);
+		curr = sseq->cluster_list->cluster_list_next;
+		while (curr != publ) {
+			prev = curr;
+			curr = curr->cluster_list_next;
+			if (prev == sseq->cluster_list) {
+
+				/* Prevent endless loop for malformed list */
+
+				err("Unable to de-list cluster publication\n"
+				    "{%u%u}, node=0x%x, ref=%u, key=%u)\n",
+				    publ->type, publ->lower, publ->node, 
+				    publ->ref, publ->key);
+				goto end_cluster;
+			}
 		}
 		if (publ != sseq->cluster_list)
 			prev->cluster_list_next = publ->cluster_list_next;
@@ -434,15 +448,26 @@
 			sseq->cluster_list = NULL;
 		}
 	}
+end_cluster:
+
+	/* Remove publication from node scope list, if present */
 
 	if (node == tipc_own_addr) {
 		prev = sseq->node_list;
-		publ = sseq->node_list->node_list_next;
-		while ((publ->key != key) || (publ->ref != ref) || 
-		       (publ->node && (publ->node != node))) {
-			prev = publ;
-			publ = publ->node_list_next;
-			assert(prev != sseq->node_list);
+		curr = sseq->node_list->node_list_next;
+		while (curr != publ) {
+			prev = curr;
+			curr = curr->node_list_next;
+			if (prev == sseq->node_list) {
+
+				/* Prevent endless loop for malformed list */
+
+				err("Unable to de-list node publication\n"
+				    "{%u%u}, node=0x%x, ref=%u, key=%u)\n",
+				    publ->type, publ->lower, publ->node, 
+				    publ->ref, publ->key);
+				goto end_node;
+			}
 		}
 		if (publ != sseq->node_list)
 			prev->node_list_next = publ->node_list_next;
@@ -453,22 +478,18 @@
 			sseq->node_list = NULL;
 		}
 	}
-	assert(!publ->node || (publ->node == node));
-	assert(publ->ref == ref);
-	assert(publ->key == key);
+end_node:
 
-	/* 
-	 * Contract subseq list if no more publications:
-	 */
-	if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) {
+	/* Contract subseq list if no more publications for that subseq */
+
+	if (!sseq->zone_list) {
 		free = &nseq->sseqs[nseq->first_free--];
 		memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq));
 		removed_subseq = 1;
 	}
 
-	/* 
-	 * Any subscriptions waiting ? 
-	 */
+	/* Notify any waiting subscriptions */
+
 	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
 		tipc_subscr_report_overlap(s,
 					   publ->lower,
@@ -478,6 +499,7 @@
 					   publ->node,
 					   removed_subseq);
 	}
+
 	return publ;
 }
 
@@ -530,7 +552,7 @@
 	seq_head = &table.types[hash(type)];
 	hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
 		if (ns->type == type) {
-			dbg("found %x\n", ns);
+			dbg("found %p\n", ns);
 			return ns;
 		}
 	}
@@ -543,22 +565,21 @@
 {
 	struct name_seq *seq = nametbl_find_seq(type);
 
-	dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq);
+	dbg("tipc_nametbl_insert_publ: {%u,%u,%u} found %p\n", type, lower, upper, seq);
 	if (lower > upper) {
-		warn("Failed to publish illegal <%u,%u,%u>\n",
+		warn("Failed to publish illegal {%u,%u,%u}\n",
 		     type, lower, upper);
 		return NULL;
 	}
 
-	dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node);
+	dbg("Publishing {%u,%u,%u} from 0x%x\n", type, lower, upper, node);
 	if (!seq) {
 		seq = tipc_nameseq_create(type, &table.types[hash(type)]);
-		dbg("tipc_nametbl_insert_publ: created %x\n", seq);
+		dbg("tipc_nametbl_insert_publ: created %p\n", seq);
 	}
 	if (!seq)
 		return NULL;
 
-	assert(seq->type == type);
 	return tipc_nameseq_insert_publ(seq, type, lower, upper,
 					scope, node, port, key);
 }
@@ -572,7 +593,7 @@
 	if (!seq)
 		return NULL;
 
-	dbg("Withdrawing <%u,%u> from %x\n", type, lower, node);
+	dbg("Withdrawing {%u,%u} from 0x%x\n", type, lower, node);
 	publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
 
 	if (!seq->first_free && list_empty(&seq->subscriptions)) {
@@ -738,12 +759,12 @@
 	struct publication *publ;
 
 	if (table.local_publ_count >= tipc_max_publications) {
-		warn("Failed publish: max %u local publication\n", 
+		warn("Publication failed, local publication limit reached (%u)\n", 
 		     tipc_max_publications);
 		return NULL;
 	}
 	if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
-		warn("Failed to publish reserved name <%u,%u,%u>\n",
+		warn("Publication failed, reserved name {%u,%u,%u}\n",
 		     type, lower, upper);
 		return NULL;
 	}
@@ -767,10 +788,10 @@
 {
 	struct publication *publ;
 
-	dbg("tipc_nametbl_withdraw:<%d,%d,%d>\n", type, lower, key);
+	dbg("tipc_nametbl_withdraw: {%u,%u}, key=%u\n", type, lower, key);
 	write_lock_bh(&tipc_nametbl_lock);
 	publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
-	if (publ) {
+	if (likely(publ)) {
 		table.local_publ_count--;
 		if (publ->scope != TIPC_NODE_SCOPE)
 			tipc_named_withdraw(publ);
@@ -780,6 +801,9 @@
 		return 1;
 	}
 	write_unlock_bh(&tipc_nametbl_lock);
+	err("Unable to remove local publication\n"
+	    "(type=%u, lower=%u, ref=%u, key=%u)\n",
+	    type, lower, ref, key);
 	return 0;
 }
 
@@ -787,8 +811,7 @@
  * tipc_nametbl_subscribe - add a subscription object to the name table
  */
 
-void
-tipc_nametbl_subscribe(struct subscription *s)
+void tipc_nametbl_subscribe(struct subscription *s)
 {
 	u32 type = s->seq.type;
 	struct name_seq *seq;
@@ -800,11 +823,13 @@
 	}
         if (seq){
                 spin_lock_bh(&seq->lock);
-                dbg("tipc_nametbl_subscribe:found %x for <%u,%u,%u>\n",
+                dbg("tipc_nametbl_subscribe:found %p for {%u,%u,%u}\n",
                     seq, type, s->seq.lower, s->seq.upper);
-                assert(seq->type == type);
                 tipc_nameseq_subscribe(seq, s);
                 spin_unlock_bh(&seq->lock);
+        } else {
+		warn("Failed to create subscription for {%u,%u,%u}\n",
+		     s->seq.type, s->seq.lower, s->seq.upper);
         }
         write_unlock_bh(&tipc_nametbl_lock);
 }
@@ -813,8 +838,7 @@
  * tipc_nametbl_unsubscribe - remove a subscription object from name table
  */
 
-void
-tipc_nametbl_unsubscribe(struct subscription *s)
+void tipc_nametbl_unsubscribe(struct subscription *s)
 {
 	struct name_seq *seq;
 
@@ -1049,35 +1073,20 @@
 
 void tipc_nametbl_stop(void)
 {
-	struct hlist_head *seq_head;
-	struct hlist_node *seq_node;
-	struct hlist_node *tmp;
-	struct name_seq *seq;
 	u32 i;
 
 	if (!table.types)
 		return;
 
+	/* Verify name table is empty, then release it */
+
 	write_lock_bh(&tipc_nametbl_lock);
 	for (i = 0; i < tipc_nametbl_size; i++) {
-		seq_head = &table.types[i];
-		hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) {
-			struct sub_seq *sseq = seq->sseqs;
-
-			for (; sseq != &seq->sseqs[seq->first_free]; sseq++) {
-				struct publication *publ = sseq->zone_list;
-				assert(publ);
-				do {
-					struct publication *next =
-						publ->zone_list_next;
-					kfree(publ);
-					publ = next;
-				}
-				while (publ != sseq->zone_list);
-			}
-		}
+		if (!hlist_empty(&table.types[i]))
+			err("tipc_nametbl_stop(): hash chain %u is non-null\n", i);
 	}
 	kfree(table.types);
 	table.types = NULL;
 	write_unlock_bh(&tipc_nametbl_lock);
 }
+
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 0d5db06..ce9678e 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -61,34 +61,37 @@
         struct node **curr_node;
 
 	n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC);
-        if (n_ptr != NULL) {
-                memset(n_ptr, 0, sizeof(*n_ptr));
-                n_ptr->addr = addr;
-                n_ptr->lock =  SPIN_LOCK_UNLOCKED;	
-                INIT_LIST_HEAD(&n_ptr->nsub);
-	
-		c_ptr = tipc_cltr_find(addr);
-                if (c_ptr == NULL)
-                        c_ptr = tipc_cltr_create(addr);
-                if (c_ptr != NULL) {
-                        n_ptr->owner = c_ptr;
-                        tipc_cltr_attach_node(c_ptr, n_ptr);
-                        n_ptr->last_router = -1;
+	if (!n_ptr) {
+		warn("Node creation failed, no memory\n");
+		return NULL;
+	}
 
-                        /* Insert node into ordered list */
-                        for (curr_node = &tipc_nodes; *curr_node; 
-			     curr_node = &(*curr_node)->next) {
-                                if (addr < (*curr_node)->addr) {
-                                        n_ptr->next = *curr_node;
-                                        break;
-                                }
-                        }
-                        (*curr_node) = n_ptr;
-                } else {
-                        kfree(n_ptr);
-                        n_ptr = NULL;
-                }
-        }
+	c_ptr = tipc_cltr_find(addr);
+	if (!c_ptr) {
+		c_ptr = tipc_cltr_create(addr);
+	}
+	if (!c_ptr) {
+		kfree(n_ptr);
+		return NULL;
+	}
+		
+	memset(n_ptr, 0, sizeof(*n_ptr));
+	n_ptr->addr = addr;
+	n_ptr->lock =  SPIN_LOCK_UNLOCKED;	
+	INIT_LIST_HEAD(&n_ptr->nsub);
+	n_ptr->owner = c_ptr;
+	tipc_cltr_attach_node(c_ptr, n_ptr);
+	n_ptr->last_router = -1;
+
+	/* Insert node into ordered list */
+	for (curr_node = &tipc_nodes; *curr_node; 
+	     curr_node = &(*curr_node)->next) {
+		if (addr < (*curr_node)->addr) {
+			n_ptr->next = *curr_node;
+			break;
+		}
+	}
+	(*curr_node) = n_ptr;
 	return n_ptr;
 }
 
@@ -122,6 +125,8 @@
 {
 	struct link **active = &n_ptr->active_links[0];
 
+	n_ptr->working_links++;
+
 	info("Established link <%s> on network plane %c\n",
 	     l_ptr->name, l_ptr->b_ptr->net_plane);
 	
@@ -132,7 +137,7 @@
 		return;
 	}
 	if (l_ptr->priority < active[0]->priority) { 
-		info("Link is standby\n");
+		info("New link <%s> becomes standby\n", l_ptr->name);
 		return;
 	}
 	tipc_link_send_duplicate(active[0], l_ptr);
@@ -140,8 +145,9 @@
 		active[0] = l_ptr;
 		return;
 	}
-	info("Link <%s> on network plane %c becomes standby\n",
-	     active[0]->name, active[0]->b_ptr->net_plane);
+	info("Old link <%s> becomes standby\n", active[0]->name);
+	if (active[1] != active[0])
+		info("Old link <%s> becomes standby\n", active[1]->name);
 	active[0] = active[1] = l_ptr;
 }
 
@@ -181,6 +187,8 @@
 {
 	struct link **active;
 
+	n_ptr->working_links--;
+
 	if (!tipc_link_is_active(l_ptr)) {
 		info("Lost standby link <%s> on network plane %c\n",
 		     l_ptr->name, l_ptr->b_ptr->net_plane);
@@ -210,8 +218,7 @@
 
 int tipc_node_has_redundant_links(struct node *n_ptr)
 {
-	return (tipc_node_has_active_links(n_ptr) &&
-		(n_ptr->active_links[0] != n_ptr->active_links[1]));
+	return (n_ptr->working_links > 1);
 }
 
 static int tipc_node_has_active_routes(struct node *n_ptr)
@@ -234,7 +241,6 @@
 		u32 bearer_id = l_ptr->b_ptr->identity;
 		char addr_string[16];
 
-                assert(bearer_id < MAX_BEARERS);
                 if (n_ptr->link_cnt >= 2) {
 			char addr_string[16];
 
@@ -249,7 +255,7 @@
                         n_ptr->link_cnt++;
                         return n_ptr;
                 }
-                err("Attempt to establish second link on <%s> to <%s> \n",
+                err("Attempt to establish second link on <%s> to %s \n",
                     l_ptr->b_ptr->publ.name, 
 		    addr_string_fill(addr_string, l_ptr->addr));
         }
@@ -314,7 +320,7 @@
 	struct cluster *c_ptr;
 
 	dbg("node_established_contact:-> %x\n", n_ptr->addr);
-	if (!tipc_node_has_active_routes(n_ptr)) { 
+	if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) { 
 		tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
 	}
 
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 781126e..a07cc79 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -51,6 +51,7 @@
  * @nsub: list of "node down" subscriptions monitoring node
  * @active_links: pointers to active links to node
  * @links: pointers to all links to node
+ * @working_links: number of working links to node (both active and standby)
  * @link_cnt: number of links to node
  * @permit_changeover: non-zero if node has redundant links to this system
  * @routers: bitmap (used for multicluster communication)
@@ -76,6 +77,7 @@
 	struct link *active_links[2];
 	struct link *links[MAX_BEARERS];
 	int link_cnt;
+	int working_links;
 	int permit_changeover;
 	u32 routers[512/32];
 	int last_router;
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c
index cff4068..cc3fff3 100644
--- a/net/tipc/node_subscr.c
+++ b/net/tipc/node_subscr.c
@@ -47,18 +47,19 @@
 void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, 
 		       void *usr_handle, net_ev_handler handle_down)
 {
-	node_sub->node = NULL;
-	if (addr == tipc_own_addr)
-		return;
-	if (!tipc_addr_node_valid(addr)) {
-		warn("node_subscr with illegal %x\n", addr);
+	if (addr == tipc_own_addr) {
+		node_sub->node = NULL;
 		return;
 	}
-
+	
+	node_sub->node = tipc_node_find(addr);
+	if (!node_sub->node) {
+		warn("Node subscription rejected, unknown node 0x%x\n", addr);
+		return;
+	}
 	node_sub->handle_node_down = handle_down;
 	node_sub->usr_handle = usr_handle;
-	node_sub->node = tipc_node_find(addr);
-	assert(node_sub->node);
+
 	tipc_node_lock(node_sub->node);
 	list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub);
 	tipc_node_unlock(node_sub->node);
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 67e96cb..47d9740 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -168,7 +168,6 @@
 	struct port_list *item = dp;
 	int cnt = 0;
 
-	assert(buf);
 	msg = buf_msg(buf);
 
 	/* Create destination port list, if one wasn't supplied */
@@ -196,7 +195,7 @@
 			struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
 
 			if (b == NULL) {
-				warn("Buffer allocation failure\n");
+				warn("Unable to deliver multicast message(s)\n");
 				msg_dbg(msg, "LOST:");
 				goto exit;
 			}
@@ -228,14 +227,14 @@
 	u32 ref;
 
 	p_ptr = kmalloc(sizeof(*p_ptr), GFP_ATOMIC);
-	if (p_ptr == NULL) {
-		warn("Memory squeeze; failed to create port\n");
+	if (!p_ptr) {
+		warn("Port creation failed, no memory\n");
 		return 0;
 	}
 	memset(p_ptr, 0, sizeof(*p_ptr));
 	ref = tipc_ref_acquire(p_ptr, &p_ptr->publ.lock);
 	if (!ref) {
-		warn("Reference Table Exhausted\n");
+		warn("Port creation failed, reference table exhausted\n");
 		kfree(p_ptr);
 		return 0;
 	}
@@ -810,18 +809,20 @@
 		void *usr_handle;
 		int connected;
 		int published;
+		u32 message_type;
 
 		struct sk_buff *next = buf->next;
 		struct tipc_msg *msg = buf_msg(buf);
 		u32 dref = msg_destport(msg);
 		
+		message_type = msg_type(msg);
+		if (message_type > TIPC_DIRECT_MSG)
+			goto reject;	/* Unsupported message type */
+
 		p_ptr = tipc_port_lock(dref);
-		if (!p_ptr) {
-			/* Port deleted while msg in queue */
-			tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
-			buf = next;
-			continue;
-		}
+		if (!p_ptr)
+			goto reject;	/* Port deleted while msg in queue */
+
 		orig.ref = msg_origport(msg);
 		orig.node = msg_orignode(msg);
 		up_ptr = p_ptr->user_port;
@@ -832,7 +833,7 @@
 		if (unlikely(msg_errcode(msg)))
 			goto err;
 
-		switch (msg_type(msg)) {
+		switch (message_type) {
 		
 		case TIPC_CONN_MSG:{
 				tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
@@ -874,6 +875,7 @@
 				   &orig);
 				break;
 			}
+		case TIPC_MCAST_MSG:
 		case TIPC_NAMED_MSG:{
 				tipc_named_msg_event cb = up_ptr->named_msg_cb;
 
@@ -886,7 +888,8 @@
 					goto reject;
 				dseq.type =  msg_nametype(msg);
 				dseq.lower = msg_nameinst(msg);
-				dseq.upper = dseq.lower;
+				dseq.upper = (message_type == TIPC_NAMED_MSG)
+					? dseq.lower : msg_nameupper(msg);
 				skb_pull(buf, msg_hdr_sz(msg));
 				cb(usr_handle, dref, &buf, msg_data(msg), 
 				   msg_data_sz(msg), msg_importance(msg),
@@ -899,7 +902,7 @@
 		buf = next;
 		continue;
 err:
-		switch (msg_type(msg)) {
+		switch (message_type) {
 		
 		case TIPC_CONN_MSG:{
 				tipc_conn_shutdown_event cb = 
@@ -931,6 +934,7 @@
 				   msg_data_sz(msg), msg_errcode(msg), &orig);
 				break;
 			}
+		case TIPC_MCAST_MSG:
 		case TIPC_NAMED_MSG:{
 				tipc_named_msg_err_event cb = 
 					up_ptr->named_err_cb;
@@ -940,7 +944,8 @@
 					break;
 				dseq.type =  msg_nametype(msg);
 				dseq.lower = msg_nameinst(msg);
-				dseq.upper = dseq.lower;
+				dseq.upper = (message_type == TIPC_NAMED_MSG)
+					? dseq.lower : msg_nameupper(msg);
 				skb_pull(buf, msg_hdr_sz(msg));
 				cb(usr_handle, dref, &buf, msg_data(msg), 
 				   msg_data_sz(msg), msg_errcode(msg), &dseq);
@@ -1054,7 +1059,8 @@
 	u32 ref;
 
 	up_ptr = (struct user_port *)kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
-	if (up_ptr == NULL) {
+	if (!up_ptr) {
+		warn("Port creation failed, no memory\n");
 		return -ENOMEM;
 	}
 	ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
@@ -1165,8 +1171,6 @@
 	p_ptr = tipc_port_lock(ref);
 	if (!p_ptr)
 		return -EINVAL;
-	if (!p_ptr->publ.published)
-		goto exit;
 	if (!seq) {
 		list_for_each_entry_safe(publ, tpubl, 
 					 &p_ptr->publications, pport_list) {
@@ -1193,7 +1197,6 @@
 	}
 	if (list_empty(&p_ptr->publications))
 		p_ptr->publ.published = 0;
-exit:
 	tipc_port_unlock(p_ptr);
 	return res;
 }
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 33bbf50..d2f0cce 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -127,7 +127,14 @@
 	u32 next_plus_upper;
 	u32 reference = 0;
 
-	assert(tipc_ref_table.entries && object);
+	if (!object) {
+		err("Attempt to acquire reference to non-existent object\n");
+		return 0;
+	}
+	if (!tipc_ref_table.entries) {
+		err("Reference table not found during acquisition attempt\n");
+		return 0;
+	}
 
 	write_lock_bh(&ref_table_lock);
 	if (tipc_ref_table.first_free) {
@@ -162,15 +169,28 @@
 	u32 index; 
 	u32 index_mask;
 
-	assert(tipc_ref_table.entries);
-	assert(ref != 0);
+	if (!ref) {
+		err("Attempt to discard reference 0\n");
+		return;
+	}
+	if (!tipc_ref_table.entries) {
+		err("Reference table not found during discard attempt\n");
+		return;
+	}
 
 	write_lock_bh(&ref_table_lock);
 	index_mask = tipc_ref_table.index_mask;
 	index = ref & index_mask;
 	entry = &(tipc_ref_table.entries[index]);
-	assert(entry->object != 0);
-	assert(entry->data.reference == ref);
+
+	if (!entry->object) {
+		err("Attempt to discard reference to non-existent object\n");
+		goto exit;
+	}
+	if (entry->data.reference != ref) {
+		err("Attempt to discard non-existent reference\n");
+		goto exit;
+	}
 
 	/* mark entry as unused */
 	entry->object = NULL;
@@ -184,6 +204,7 @@
 
 	/* increment upper bits of entry to invalidate subsequent references */
 	entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1);
+exit:
 	write_unlock_bh(&ref_table_lock);
 }
 
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 648a734..32d7784 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -169,12 +169,6 @@
 	struct sock *sk;
         u32 ref;
 
-	if ((sock->type != SOCK_STREAM) && 
-	    (sock->type != SOCK_SEQPACKET) &&
-	    (sock->type != SOCK_DGRAM) &&
-	    (sock->type != SOCK_RDM))
-		return -EPROTOTYPE;
-
 	if (unlikely(protocol != 0))
 		return -EPROTONOSUPPORT;
 
@@ -199,6 +193,9 @@
 		sock->ops = &msg_ops;
 		sock->state = SS_READY;
 		break;
+	default:
+		tipc_deleteport(ref);
+		return -EPROTOTYPE;
 	}
 
 	sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1);
@@ -426,7 +423,7 @@
 
         if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))
 		return -EFAULT;
-	if ((ntohs(hdr.tcm_type) & 0xC000) & (!capable(CAP_NET_ADMIN)))
+	if ((ntohs(hdr.tcm_type) & 0xC000) && (!capable(CAP_NET_ADMIN)))
 		return -EACCES;
         
 	return 0;
@@ -437,7 +434,7 @@
  * @iocb: (unused)
  * @sock: socket structure
  * @m: message to send
- * @total_len: (unused)
+ * @total_len: length of message
  * 
  * Message must have an destination specified explicitly.
  * Used for SOCK_RDM and SOCK_DGRAM messages, 
@@ -458,7 +455,8 @@
 
 	if (unlikely(!dest))
 		return -EDESTADDRREQ;
-	if (unlikely(dest->family != AF_TIPC))
+	if (unlikely((m->msg_namelen < sizeof(*dest)) ||
+		     (dest->family != AF_TIPC)))
 		return -EINVAL;
 
 	needs_conn = (sock->state != SS_READY);
@@ -470,6 +468,10 @@
 		if ((tsock->p->published) ||
 		    ((sock->type == SOCK_STREAM) && (total_len != 0)))
 			return -EOPNOTSUPP;
+		if (dest->addrtype == TIPC_ADDR_NAME) {
+			tsock->p->conn_type = dest->addr.name.name.type;
+			tsock->p->conn_instance = dest->addr.name.name.instance;
+		}
 	}
 
 	if (down_interruptible(&tsock->sem))
@@ -538,7 +540,7 @@
  * @iocb: (unused)
  * @sock: socket structure
  * @m: message to send
- * @total_len: (unused)
+ * @total_len: length of message
  * 
  * Used for SOCK_SEQPACKET messages and SOCK_STREAM data.
  * 
@@ -561,15 +563,15 @@
 		return -ERESTARTSYS;
         }
 
-        if (unlikely(sock->state != SS_CONNECTED)) {
-                if (sock->state == SS_DISCONNECTING)
-                        res = -EPIPE;   
-                else
-                        res = -ENOTCONN;
-                goto exit;
-        }
-
         do {
+		if (unlikely(sock->state != SS_CONNECTED)) {
+			if (sock->state == SS_DISCONNECTING)
+				res = -EPIPE;   
+			else
+				res = -ENOTCONN;
+			goto exit;
+		}
+
                 res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
                 if (likely(res != -ELINKCONG)) {
 exit:
@@ -597,7 +599,8 @@
  * 
  * Used for SOCK_STREAM data.
  * 
- * Returns the number of bytes sent on success, or errno otherwise
+ * Returns the number of bytes sent on success (or partial success), 
+ * or errno if no data sent
  */
 
 
@@ -611,6 +614,7 @@
 	char __user *curr_start;
 	int curr_left;
 	int bytes_to_send;
+	int bytes_sent;
 	int res;
 	
 	if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
@@ -633,11 +637,11 @@
 	 * of small iovec entries into send_packet().
 	 */
 
-	my_msg = *m;
-	curr_iov = my_msg.msg_iov;
-	curr_iovlen = my_msg.msg_iovlen;
+	curr_iov = m->msg_iov;
+	curr_iovlen = m->msg_iovlen;
 	my_msg.msg_iov = &my_iov;
 	my_msg.msg_iovlen = 1;
+	bytes_sent = 0;
 
 	while (curr_iovlen--) {
 		curr_start = curr_iov->iov_base;
@@ -648,16 +652,18 @@
 				? curr_left : TIPC_MAX_USER_MSG_SIZE;
 			my_iov.iov_base = curr_start;
 			my_iov.iov_len = bytes_to_send;
-                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0)
-                                return res;
+                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) {
+				return bytes_sent ? bytes_sent : res;
+			}
 			curr_left -= bytes_to_send;
 			curr_start += bytes_to_send;
+			bytes_sent += bytes_to_send;
 		}
 
 		curr_iov++;
 	}
 
-	return total_len;
+	return bytes_sent;
 }
 
 /**
@@ -727,6 +733,7 @@
 	u32 anc_data[3];
 	u32 err;
 	u32 dest_type;
+	int has_name;
 	int res;
 
 	if (likely(m->msg_controllen == 0))
@@ -738,10 +745,10 @@
 	if (unlikely(err)) {
 		anc_data[0] = err;
 		anc_data[1] = msg_data_sz(msg);
-		if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data)))
+		if ((res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data)))
 			return res;
 		if (anc_data[1] &&
-		    (res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1], 
+		    (res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1], 
 				    msg_data(msg))))
 			return res;
 	}
@@ -751,25 +758,28 @@
 	dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
 	switch (dest_type) {
 	case TIPC_NAMED_MSG:
+		has_name = 1;
 		anc_data[0] = msg_nametype(msg);
 		anc_data[1] = msg_namelower(msg);
 		anc_data[2] = msg_namelower(msg);
 		break;
 	case TIPC_MCAST_MSG:
+		has_name = 1;
 		anc_data[0] = msg_nametype(msg);
 		anc_data[1] = msg_namelower(msg);
 		anc_data[2] = msg_nameupper(msg);
 		break;
 	case TIPC_CONN_MSG:
+		has_name = (tport->conn_type != 0);
 		anc_data[0] = tport->conn_type;
 		anc_data[1] = tport->conn_instance;
 		anc_data[2] = tport->conn_instance;
 		break;
 	default:
-		anc_data[0] = 0;
+		has_name = 0;
 	}
-	if (anc_data[0] &&
-	    (res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data)))
+	if (has_name &&
+	    (res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data)))
 		return res;
 
 	return 0;
@@ -960,7 +970,7 @@
 restart:
 	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
 		     (flags & MSG_DONTWAIT))) {
-		res = (sz_copied == 0) ? -EWOULDBLOCK : 0;
+		res = -EWOULDBLOCK;
 		goto exit;
 	}
 
@@ -1051,7 +1061,7 @@
 
 exit:
 	up(&tsock->sem);
-	return res ? res : sz_copied;
+	return sz_copied ? sz_copied : res;
 }
 
 /**
@@ -1236,7 +1246,8 @@
    if (sock->state == SS_READY)
 	   return -EOPNOTSUPP;
 
-   /* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */
+   /* Issue Posix-compliant error code if socket is in the wrong state */
+
    if (sock->state == SS_LISTENING)
 	   return -EOPNOTSUPP;
    if (sock->state == SS_CONNECTING)
@@ -1244,13 +1255,20 @@
    if (sock->state != SS_UNCONNECTED)
            return -EISCONN;
 
-   if ((dst->family != AF_TIPC) ||
-       ((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID)))
+   /*
+    * Reject connection attempt using multicast address
+    *
+    * Note: send_msg() validates the rest of the address fields,
+    *       so there's no need to do it here
+    */
+
+   if (dst->addrtype == TIPC_ADDR_MCAST)
            return -EINVAL;
 
    /* Send a 'SYN-' to destination */
 
    m.msg_name = dest;
+   m.msg_namelen = destlen;
    if ((res = send_msg(NULL, sock, &m, 0)) < 0) {
 	   sock->state = SS_DISCONNECTING;
 	   return res;
@@ -1269,10 +1287,6 @@
 	   msg = buf_msg(buf);
            res = auto_connect(sock, tsock, msg);
            if (!res) {
-		   if (dst->addrtype == TIPC_ADDR_NAME) {
-			   tsock->p->conn_type = dst->addr.name.name.type;
-			   tsock->p->conn_instance = dst->addr.name.name.instance;
-		   }
 		   if (!msg_data_sz(msg))
 			   advance_queue(tsock);
 	   }
@@ -1386,7 +1400,7 @@
 /**
  * shutdown - shutdown socket connection
  * @sock: socket structure
- * @how: direction to close (always treated as read + write)
+ * @how: direction to close (unused; always treated as read + write)
  *
  * Terminates connection (if necessary), then purges socket's receive queue.
  * 
@@ -1469,7 +1483,8 @@
  * Returns 0 on success, errno otherwise
  */
 
-static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol)
+static int setsockopt(struct socket *sock, 
+		      int lvl, int opt, char __user *ov, int ol)
 {
 	struct tipc_sock *tsock = tipc_sk(sock->sk);
 	u32 value;
@@ -1525,7 +1540,8 @@
  * Returns 0 on success, errno otherwise
  */
 
-static int getsockopt(struct socket *sock, int lvl, int opt, char *ov, int *ol)
+static int getsockopt(struct socket *sock, 
+		      int lvl, int opt, char __user *ov, int *ol)
 {
 	struct tipc_sock *tsock = tipc_sk(sock->sk);
         int len;
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index c5f026c..fc17187 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -266,7 +266,8 @@
 	/* Refuse subscription if global limit exceeded */
 
 	if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
-		warn("Failed: max %u subscriptions\n", tipc_max_subscriptions);
+		warn("Subscription rejected, subscription limit reached (%u)\n",
+		     tipc_max_subscriptions);
 		subscr_terminate(subscriber);
 		return;
 	}
@@ -274,8 +275,8 @@
 	/* Allocate subscription object */
 
 	sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
-	if (sub == NULL) {
-		warn("Memory squeeze; ignoring subscription\n");
+	if (!sub) {
+		warn("Subscription rejected, no memory\n");
 		subscr_terminate(subscriber);
 		return;
 	}
@@ -298,8 +299,7 @@
 	if ((((sub->filter != TIPC_SUB_PORTS) 
 	      && (sub->filter != TIPC_SUB_SERVICE)))
 	    || (sub->seq.lower > sub->seq.upper)) {
-		warn("Rejecting illegal subscription %u,%u,%u\n",
-		     sub->seq.type, sub->seq.lower, sub->seq.upper);
+		warn("Subscription rejected, illegal request\n");
 		kfree(sub);
 		subscr_terminate(subscriber);
 		return;
@@ -387,7 +387,7 @@
 	dbg("subscr_named_msg_event: orig = %x own = %x,\n",
 	    orig->node, tipc_own_addr);
 	if (size && (size != sizeof(struct tipc_subscr))) {
-		warn("Received tipc_subscr of invalid size\n");
+		warn("Subscriber rejected, invalid subscription size\n");
 		return;
 	}
 
@@ -395,7 +395,7 @@
 
 	subscriber = kmalloc(sizeof(struct subscriber), GFP_ATOMIC);
 	if (subscriber == NULL) {
-		warn("Memory squeeze; ignoring subscriber setup\n");
+		warn("Subscriber rejected, no memory\n");
 		return;
 	}
 	memset(subscriber, 0, sizeof(struct subscriber));
@@ -403,7 +403,7 @@
 	INIT_LIST_HEAD(&subscriber->subscriber_list);
 	subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock);
 	if (subscriber->ref == 0) {
-		warn("Failed to acquire subscriber reference\n");
+		warn("Subscriber rejected, reference table exhausted\n");
 		kfree(subscriber);
 		return;
 	}
@@ -422,7 +422,7 @@
 			NULL,
 			&subscriber->port_ref);
 	if (subscriber->port_ref == 0) {
-		warn("Memory squeeze; failed to create subscription port\n");
+		warn("Subscriber rejected, unable to create port\n");
 		tipc_ref_discard(subscriber->ref);
 		kfree(subscriber);
 		return;
diff --git a/net/tipc/zone.c b/net/tipc/zone.c
index 2803e1b..316c487 100644
--- a/net/tipc/zone.c
+++ b/net/tipc/zone.c
@@ -44,19 +44,24 @@
 
 struct _zone *tipc_zone_create(u32 addr)
 {
-	struct _zone *z_ptr = NULL;
+	struct _zone *z_ptr;
 	u32 z_num;
 
-	if (!tipc_addr_domain_valid(addr))
+	if (!tipc_addr_domain_valid(addr)) {
+		err("Zone creation failed, invalid domain 0x%x\n", addr);
 		return NULL;
+	}
 
 	z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC);
-	if (z_ptr != NULL) {
-		memset(z_ptr, 0, sizeof(*z_ptr));
-		z_num = tipc_zone(addr);
-		z_ptr->addr = tipc_addr(z_num, 0, 0);
-		tipc_net.zones[z_num] = z_ptr;
+	if (!z_ptr) {
+		warn("Zone creation failed, insufficient memory\n");
+		return NULL;
 	}
+
+	memset(z_ptr, 0, sizeof(*z_ptr));
+	z_num = tipc_zone(addr);
+	z_ptr->addr = tipc_addr(z_num, 0, 0);
+	tipc_net.zones[z_num] = z_ptr;
 	return z_ptr;
 }
 
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index b0d067b..ac5f275 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -13,6 +13,11 @@
 depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
 
 ###
+# basetarget equals the filename of the target with no extension.
+# So 'foo/bar.o' becomes 'bar'
+basetarget = $(basename $(notdir $@))
+
+###
 # Escape single quote for use in echo statements
 escsq = $(subst $(squote),'\$(squote)',$1)
 
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index e48e60d..3cb445c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -8,7 +8,7 @@
 __build:
 
 # Read .config if it exist, otherwise ignore
--include .config
+-include include/config/auto.conf
 
 include scripts/Kbuild.include
 
@@ -117,7 +117,7 @@
 $(obj-m)              : quiet_modtag := [M]
 
 # Default for not multi-part modules
-modname = $(*F)
+modname = $(basetarget)
 
 $(multi-objs-m)         : modname = $(modname-multi)
 $(multi-objs-m:.o=.i)   : modname = $(modname-multi)
@@ -140,6 +140,15 @@
 %.i: %.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
+quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
+cmd_cc_symtypes_c	   = \
+		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
+		| $(GENKSYMS) -T $@ >/dev/null;				\
+		test -s $@ || rm -f $@
+
+%.symtypes : %.c FORCE
+	$(call if_changed_dep,cc_symtypes_c)
+
 # C (.c) files
 # The C file is compiled and updated dependency information is generated.
 # (See cmd_cc_o_c + relevant part of rule_cc_o_c)
@@ -166,7 +175,8 @@
 cmd_modversions =							\
 	if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then	\
 		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
-		| $(GENKSYMS) -a $(ARCH)				\
+		| $(GENKSYMS) $(if $(KBUILD_SYMTYPES),			\
+			      -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH)	\
 		> $(@D)/.tmp_$(@F:.o=.ver);				\
 									\
 		$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 		\
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 2d51970..18ecd4d 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -33,8 +33,8 @@
 __hostprogs := $(sort $(hostprogs-y)$(hostprogs-m))
 
 # hostprogs-y := tools/build may have been specified. Retreive directory
-obj-dirs += $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
-obj-dirs := $(strip $(sort $(filter-out ./,$(obj-dirs))))
+host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
+host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
 
 
 # C code
@@ -73,13 +73,17 @@
 host-cxxobjs	:= $(addprefix $(obj)/,$(host-cxxobjs))
 host-cshlib	:= $(addprefix $(obj)/,$(host-cshlib))
 host-cshobjs	:= $(addprefix $(obj)/,$(host-cshobjs))
-obj-dirs        := $(addprefix $(obj)/,$(obj-dirs))
+host-objdirs    := $(addprefix $(obj)/,$(host-objdirs))
+
+obj-dirs += $(host-objdirs)
 
 #####
 # Handle options to gcc. Support building with separate output directory
 
-_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   $(HOSTCFLAGS_$(*F).o)
-_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) $(HOSTCXXFLAGS_$(*F).o)
+_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   \
+                 $(HOSTCFLAGS_$(basetarget).o)
+_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
+                 $(HOSTCXXFLAGS_$(basetarget).o)
 
 ifeq ($(KBUILD_SRC),)
 __hostc_flags	= $(_hostc_flags)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 2cb4935..fc498fe 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -82,12 +82,12 @@
 #       than one module. In that case KBUILD_MODNAME will be set to foo_bar,
 #       where foo and bar are the name of the modules.
 name-fix = $(subst $(comma),_,$(subst -,_,$1))
-basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(*F)))"
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
 modname_flags  = $(if $(filter 1,$(words $(modname))),\
                  -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
 
-_c_flags       = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o)
-_a_flags       = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+_c_flags       = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(basetarget).o)
+_a_flags       = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o)
 _cpp_flags     = $(CPPFLAGS) $(EXTRA_CPPFLAGS) $(CPPFLAGS_$(@F))
 
 # If building the kernel in a separate objtree expand all occurrences
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index 2686dd5..f0ff248 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -17,7 +17,7 @@
 	@:
 
 quiet_cmd_modules_install = INSTALL $@
-      cmd_modules_install = mkdir -p $(2); cp $@ $(2)
+      cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@)
 
 # Modules built outside the kernel source tree go into extra by default
 INSTALL_MOD_DIR ?= extra
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 0e056cf..e83613e 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -35,7 +35,7 @@
 PHONY := _modpost
 _modpost: __modpost
 
-include .config
+include include/config/auto.conf
 include scripts/Kbuild.include
 include scripts/Makefile.lib
 
@@ -72,7 +72,7 @@
 # Step 5), compile all *.mod.c files
 
 # modname is set to make c_flags define KBUILD_MODNAME
-modname = $(*F)
+modname = $(basetarget)
 
 quiet_cmd_cc_o_c = CC      $@
       cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE)	\
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index f22e94c..2f60070 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -1,17 +1,15 @@
 ###
 # Makefile.basic list the most basic programs used during the build process.
 # The programs listed herein is what is needed to do the basic stuff,
-# such as splitting .config and fix dependency file.
+# such as fix dependency file.
 # This initial step is needed to avoid files to be recompiled
 # when kernel configuration changes (which is what happens when
 # .config is included by main Makefile.
 # ---------------------------------------------------------------------------
 # fixdep: 	 Used to generate dependency information during build process
-# split-include: Divide all config symbols up in a number of files in
-#                include/config/...
 # docproc:	 Used in Documentation/docbook
 
-hostprogs-y	:= fixdep split-include docproc
+hostprogs-y	:= fixdep docproc
 always		:= $(hostprogs-y)
 
 # fixdep is needed to compile other host programs
diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c
deleted file mode 100644
index 459c4527..0000000
--- a/scripts/basic/split-include.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * split-include.c
- *
- * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
- * This is a C version of syncdep.pl by Werner Almesberger.
- *
- * This program takes autoconf.h as input and outputs a directory full
- * of one-line include files, merging onto the old values.
- *
- * Think of the configuration options as key-value pairs.  Then there
- * are five cases:
- *
- *    key      old value   new value   action
- *
- *    KEY-1    VALUE-1     VALUE-1     leave file alone
- *    KEY-2    VALUE-2A    VALUE-2B    write VALUE-2B into file
- *    KEY-3    -           VALUE-3     write VALUE-3  into file
- *    KEY-4    VALUE-4     -           write an empty file
- *    KEY-5    (empty)     -           leave old empty file alone
- */
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define ERROR_EXIT(strExit)						\
-    {									\
-	const int errnoSave = errno;					\
-	fprintf(stderr, "%s: ", str_my_name);				\
-	errno = errnoSave;						\
-	perror((strExit));						\
-	exit(1);							\
-    }
-
-
-
-int main(int argc, const char * argv [])
-{
-    const char * str_my_name;
-    const char * str_file_autoconf;
-    const char * str_dir_config;
-
-    FILE * fp_config;
-    FILE * fp_target;
-    FILE * fp_find;
-
-    int buffer_size;
-
-    char * line;
-    char * old_line;
-    char * list_target;
-    char * ptarget;
-
-    struct stat stat_buf;
-
-    /* Check arg count. */
-    if (argc != 3)
-    {
-	fprintf(stderr, "%s: wrong number of arguments.\n", argv[0]);
-	exit(1);
-    }
-
-    str_my_name       = argv[0];
-    str_file_autoconf = argv[1];
-    str_dir_config    = argv[2];
-
-    /* Find a buffer size. */
-    if (stat(str_file_autoconf, &stat_buf) != 0)
-	ERROR_EXIT(str_file_autoconf);
-    buffer_size = 2 * stat_buf.st_size + 4096;
-
-    /* Allocate buffers. */
-    if ( (line        = malloc(buffer_size)) == NULL
-    ||   (old_line    = malloc(buffer_size)) == NULL
-    ||   (list_target = malloc(buffer_size)) == NULL )
-	ERROR_EXIT(str_file_autoconf);
-
-    /* Open autoconfig file. */
-    if ((fp_config = fopen(str_file_autoconf, "r")) == NULL)
-	ERROR_EXIT(str_file_autoconf);
-
-    /* Make output directory if needed. */
-    if (stat(str_dir_config, &stat_buf) != 0)
-    {
-	if (mkdir(str_dir_config, 0755) != 0)
-	    ERROR_EXIT(str_dir_config);
-    }
-
-    /* Change to output directory. */
-    if (chdir(str_dir_config) != 0)
-	ERROR_EXIT(str_dir_config);
-
-    /* Put initial separator into target list. */
-    ptarget = list_target;
-    *ptarget++ = '\n';
-
-    /* Read config lines. */
-    while (fgets(line, buffer_size, fp_config))
-    {
-	const char * str_config;
-	int is_same;
-	int itarget;
-
-	if (line[0] != '#')
-	    continue;
-	if ((str_config = strstr(line, "CONFIG_")) == NULL)
-	    continue;
-
-	/* Make the output file name. */
-	str_config += sizeof("CONFIG_") - 1;
-	for (itarget = 0; !isspace(str_config[itarget]); itarget++)
-	{
-	    int c = (unsigned char) str_config[itarget];
-	    if (isupper(c)) c = tolower(c);
-	    if (c == '_')   c = '/';
-	    ptarget[itarget] = c;
-	}
-	ptarget[itarget++] = '.';
-	ptarget[itarget++] = 'h';
-	ptarget[itarget++] = '\0';
-
-	/* Check for existing file. */
-	is_same = 0;
-	if ((fp_target = fopen(ptarget, "r")) != NULL)
-	{
-	    fgets(old_line, buffer_size, fp_target);
-	    if (fclose(fp_target) != 0)
-		ERROR_EXIT(ptarget);
-	    if (!strcmp(line, old_line))
-		is_same = 1;
-	}
-
-	if (!is_same)
-	{
-	    /* Auto-create directories. */
-	    int islash;
-	    for (islash = 0; islash < itarget; islash++)
-	    {
-		if (ptarget[islash] == '/')
-		{
-		    ptarget[islash] = '\0';
-		    if (stat(ptarget, &stat_buf) != 0
-		    &&  mkdir(ptarget, 0755)     != 0)
-			ERROR_EXIT( ptarget );
-		    ptarget[islash] = '/';
-		}
-	    }
-
-	    /* Write the file. */
-	    if ((fp_target = fopen(ptarget, "w" )) == NULL)
-		ERROR_EXIT(ptarget);
-	    fputs(line, fp_target);
-	    if (ferror(fp_target) || fclose(fp_target) != 0)
-		ERROR_EXIT(ptarget);
-	}
-
-	/* Update target list */
-	ptarget += itarget;
-	*(ptarget-1) = '\n';
-    }
-
-    /*
-     * Close autoconfig file.
-     * Terminate the target list.
-     */
-    if (fclose(fp_config) != 0)
-	ERROR_EXIT(str_file_autoconf);
-    *ptarget = '\0';
-
-    /*
-     * Fix up existing files which have no new value.
-     * This is Case 4 and Case 5.
-     *
-     * I re-read the tree and filter it against list_target.
-     * This is crude.  But it avoids data copies.  Also, list_target
-     * is compact and contiguous, so it easily fits into cache.
-     *
-     * Notice that list_target contains strings separated by \n,
-     * with a \n before the first string and after the last.
-     * fgets gives the incoming names a terminating \n.
-     * So by having an initial \n, strstr will find exact matches.
-     */
-
-    fp_find = popen("find * -type f -name \"*.h\" -print", "r");
-    if (fp_find == 0)
-	ERROR_EXIT( "find" );
-
-    line[0] = '\n';
-    while (fgets(line+1, buffer_size, fp_find))
-    {
-	if (strstr(list_target, line) == NULL)
-	{
-	    /*
-	     * This is an old file with no CONFIG_* flag in autoconf.h.
-	     */
-
-	    /* First strip the \n. */
-	    line[strlen(line)-1] = '\0';
-
-	    /* Grab size. */
-	    if (stat(line+1, &stat_buf) != 0)
-		ERROR_EXIT(line);
-
-	    /* If file is not empty, make it empty and give it a fresh date. */
-	    if (stat_buf.st_size != 0)
-	    {
-		if ((fp_target = fopen(line+1, "w")) == NULL)
-		    ERROR_EXIT(line);
-		if (fclose(fp_target) != 0)
-		    ERROR_EXIT(line);
-	    }
-	}
-    }
-
-    if (pclose(fp_find) != 0)
-	ERROR_EXIT("find");
-
-    return 0;
-}
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index 75f21d8..ce59fc2 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -18,7 +18,8 @@
     for l in os.popen("nm --size-sort " + file).readlines():
         size, type, name = l[:-1].split()
         if type in "tTdDbB":
-            sym[name] = int(size, 16)
+            if "." in name: name = "static." + name.split(".")[0]
+            sym[name] = sym.get(name, 0) + int(size, 16)
     return sym
 
 old = getsizes(sys.argv[1])
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index dadfa20..b349246 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -89,11 +89,21 @@
 #
 my $funcre = qr/^$x* <(.*)>:$/;
 my $func;
+my $file, $lastslash;
+
 while (my $line = <STDIN>) {
 	if ($line =~ m/$funcre/) {
 		$func = $1;
 	}
-	if ($line =~ m/$re/) {
+	elsif ($line =~ m/(.*):\s*file format/) {
+		$file = $1;
+		$file =~ s/\.ko//;
+		$lastslash = rindex($file, "/");
+		if ($lastslash != -1) {
+			$file = substr($file, $lastslash + 1);
+		}
+	}
+	elsif ($line =~ m/$re/) {
 		my $size = $1;
 		$size = hex($size) if ($size =~ /^0x/);
 
@@ -109,7 +119,7 @@
 		$addr =~ s/ /0/g;
 		$addr = "0x$addr";
 
-		my $intro = "$addr $func:";
+		my $intro = "$addr $func [$file]:";
 		my $padlen = 56 - length($intro);
 		while ($padlen > 0) {
 			$intro .= '	';
diff --git a/scripts/export_report.pl b/scripts/export_report.pl
new file mode 100644
index 0000000..9ed00d9
--- /dev/null
+++ b/scripts/export_report.pl
@@ -0,0 +1,169 @@
+#!/usr/bin/perl -w
+#
+# (C) Copyright IBM Corporation 2006.
+#	Released under GPL v2.
+#	Author : Ram Pai (linuxram@us.ibm.com)
+#
+# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c
+#
+
+use Getopt::Std;
+use strict;
+
+sub numerically {
+	my $no1 = (split /\s+/, $a)[1];
+	my $no2 = (split /\s+/, $b)[1];
+	return $no1 <=> $no2;
+}
+
+sub alphabetically {
+	my ($module1, $value1) = @{$a};
+	my ($module2, $value2) = @{$b};
+	return $value1 <=> $value2 || $module2 cmp $module1;
+}
+
+sub print_depends_on {
+	my ($href) = @_;
+	print "\n";
+	while (my ($mod, $list) = each %$href) {
+		print "\t$mod:\n";
+		foreach my $sym (sort numerically @{$list}) {
+			my ($symbol, $no) = split /\s+/, $sym;
+			printf("\t\t%-25s\t%-25d\n", $symbol, $no);
+		}
+		print "\n";
+	}
+	print "\n";
+	print "~"x80 , "\n";
+}
+
+sub usage {
+        print "Usage: @_ -h -k Module.symvers  [ -o outputfile ] \n",
+	      "\t-f: treat all the non-option argument as .mod.c files. ",
+	      "Recommend using this as the last option\n",
+	      "\t-h: print detailed help\n",
+	      "\t-k: the path to Module.symvers file. By default uses ",
+	      "the file from the current directory\n",
+	      "\t-o outputfile: output the report to outputfile\n";
+	exit 0;
+}
+
+sub collectcfiles {
+        my @file = `cat .tmp_versions/*.mod | grep '.*\.ko\$'`;
+        @file = grep {s/\.ko/.mod.c/} @file;
+	chomp @file;
+        return @file;
+}
+
+my (%SYMBOL, %MODULE, %opt, @allcfiles);
+
+if (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) {
+        usage($0);
+}
+
+if (defined $opt{'f'}) {
+	@allcfiles = @ARGV;
+} else {
+	@allcfiles = collectcfiles();
+}
+
+if (not defined $opt{'k'}) {
+	$opt{'k'} = "Module.symvers";
+}
+
+unless (open(MODULE_SYMVERS, $opt{'k'})) {
+	die "Sorry, cannot open $opt{'k'}: $!\n";
+}
+
+if (defined $opt{'o'}) {
+	unless (open(OUTPUT_HANDLE, ">$opt{'o'}")) {
+		die "Sorry, cannot open $opt{'o'} $!\n";
+	}
+	select OUTPUT_HANDLE;
+}
+#
+# collect all the symbols and their attributes from the
+# Module.symvers file
+#
+while ( <MODULE_SYMVERS> ) {
+	chomp;
+	my (undef, $symbol, $module, $gpl) = split;
+	$SYMBOL { $symbol } =  [ $module , "0" , $symbol, $gpl];
+}
+close(MODULE_SYMVERS);
+
+#
+# collect the usage count of each symbol.
+#
+foreach my $thismod (@allcfiles) {
+	unless (open(MODULE_MODULE, $thismod)) {
+		print "Sorry, cannot open $thismod: $!\n";
+		next;
+	}
+	my $state=0;
+	while ( <MODULE_MODULE> ) {
+		chomp;
+		if ($state eq 0) {
+			$state = 1 if ($_ =~ /static const struct modversion_info/);
+			next;
+		}
+		if ($state eq 1) {
+			$state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/);
+			next;
+		}
+		if ($state eq 2) {
+			if ( $_ !~ /0x[0-9a-f]{7,8},/ ) {
+				next;
+			}
+			my $sym = (split /([,"])/,)[4];
+			my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}};
+			$SYMBOL{ $sym } =  [ $module, $value+1, $symbol, $gpl];
+			push(@{$MODULE{$thismod}} , $sym);
+		}
+	}
+	if ($state ne 2) {
+		print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n";
+	}
+	close(MODULE_MODULE);
+}
+
+print "\tThis file reports the exported symbols usage patterns by in-tree\n",
+	"\t\t\t\tmodules\n";
+printf("%s\n\n\n","x"x80);
+printf("\t\t\t\tINDEX\n\n\n");
+printf("SECTION 1: Usage counts of all exported symbols\n");
+printf("SECTION 2: List of modules and the exported symbols they use\n");
+printf("%s\n\n\n","x"x80);
+printf("SECTION 1:\tThe exported symbols and their usage count\n\n");
+printf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count",
+	"export type");
+
+#
+# print the list of unused exported symbols
+#
+foreach my $list (sort alphabetically values(%SYMBOL)) {
+	my ($module, $value, $symbol, $gpl) = @{$list};
+	printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value);
+	if (defined $gpl) {
+		printf("%-25s\n",$gpl);
+	} else {
+		printf("\n");
+	}
+}
+printf("%s\n\n\n","x"x80);
+
+printf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel
+modules. Each module lists the modules, and the symbols from that module that
+it uses.  Each listed symbol reports the number of modules using it\n");
+
+print "~"x80 , "\n";
+while (my ($thismod, $list) = each %MODULE) {
+	my %depends;
+	$thismod =~ s/\.mod\.c/.ko/;
+	print "\t\t\t$thismod\n";
+	foreach my $symbol (@{$list}) {
+		my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}};
+		push (@{$depends{"$module"}}, "$symbol $value");
+	}
+	print_depends_on(\%depends);
+}
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index 5b0344e..b038182 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -42,7 +42,7 @@
 int cur_line = 1;
 char *cur_filename;
 
-static int flag_debug, flag_dump_defs, flag_warnings;
+static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings;
 static const char *arch = "";
 static const char *mod_prefix = "";
 
@@ -50,6 +50,7 @@
 static int nsyms;
 
 static struct symbol *expansion_trail;
+static struct symbol *visited_symbols;
 
 static const char *const symbol_type_name[] = {
 	"normal", "typedef", "enum", "struct", "union"
@@ -176,6 +177,7 @@
 	sym->type = type;
 	sym->defn = defn;
 	sym->expansion_trail = NULL;
+	sym->visited = NULL;
 	sym->is_extern = is_extern;
 
 	sym->hash_next = symtab[h];
@@ -236,26 +238,11 @@
 
 static void print_node(FILE * f, struct string_list *list)
 {
-	switch (list->tag) {
-	case SYM_STRUCT:
-		putc('s', f);
-		goto printit;
-	case SYM_UNION:
-		putc('u', f);
-		goto printit;
-	case SYM_ENUM:
-		putc('e', f);
-		goto printit;
-	case SYM_TYPEDEF:
-		putc('t', f);
-		goto printit;
-
-	      printit:
+	if (list->tag != SYM_NORMAL) {
+		putc(symbol_type_name[list->tag][0], f);
 		putc('#', f);
-	case SYM_NORMAL:
-		fputs(list->string, f);
-		break;
 	}
+	fputs(list->string, f);
 }
 
 static void print_list(FILE * f, struct string_list *list)
@@ -287,9 +274,9 @@
 	}
 }
 
-static unsigned long expand_and_crc_list(struct string_list *list,
-					 unsigned long crc)
+static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
 {
+	struct string_list *list = sym->defn;
 	struct string_list **e, **b;
 	struct string_list *tmp, **tmp2;
 	int elem = 1;
@@ -332,7 +319,7 @@
 			} else {
 				subsym->expansion_trail = expansion_trail;
 				expansion_trail = subsym;
-				crc = expand_and_crc_list(subsym->defn, crc);
+				crc = expand_and_crc_sym(subsym, crc);
 			}
 			break;
 
@@ -382,12 +369,22 @@
 			} else {
 				subsym->expansion_trail = expansion_trail;
 				expansion_trail = subsym;
-				crc = expand_and_crc_list(subsym->defn, crc);
+				crc = expand_and_crc_sym(subsym, crc);
 			}
 			break;
 		}
 	}
 
+	{
+		static struct symbol **end = &visited_symbols;
+
+		if (!sym->visited) {
+			*end = sym;
+			end = &sym->visited;
+			sym->visited = (struct symbol *)-1L;
+		}
+	}
+
 	return crc;
 }
 
@@ -406,7 +403,7 @@
 
 		expansion_trail = (struct symbol *)-1L;
 
-		crc = expand_and_crc_list(sym->defn, 0xffffffff) ^ 0xffffffff;
+		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 
 		sym = expansion_trail;
 		while (sym != (struct symbol *)-1L) {
@@ -464,6 +461,7 @@
 
 int main(int argc, char **argv)
 {
+	FILE *dumpfile = NULL;
 	int o;
 
 #ifdef __GNU_LIBRARY__
@@ -473,15 +471,16 @@
 		{"warnings", 0, 0, 'w'},
 		{"quiet", 0, 0, 'q'},
 		{"dump", 0, 0, 'D'},
+		{"dump-types", 1, 0, 'T'},
 		{"version", 0, 0, 'V'},
 		{"help", 0, 0, 'h'},
 		{0, 0, 0, 0}
 	};
 
-	while ((o = getopt_long(argc, argv, "a:dwqVDk:p:",
+	while ((o = getopt_long(argc, argv, "a:dwqVDT:k:p:",
 				&long_opts[0], NULL)) != EOF)
 #else				/* __GNU_LIBRARY__ */
-	while ((o = getopt(argc, argv, "a:dwqVDk:p:")) != EOF)
+	while ((o = getopt(argc, argv, "a:dwqVDT:k:p:")) != EOF)
 #endif				/* __GNU_LIBRARY__ */
 		switch (o) {
 		case 'a':
@@ -502,6 +501,14 @@
 		case 'D':
 			flag_dump_defs = 1;
 			break;
+		case 'T':
+			flag_dump_types = 1;
+			dumpfile = fopen(optarg, "w");
+			if (!dumpfile) {
+				perror(optarg);
+				return 1;
+			}
+			break;
 		case 'h':
 			genksyms_usage();
 			return 0;
@@ -524,6 +531,24 @@
 
 	yyparse();
 
+	if (flag_dump_types && visited_symbols) {
+		while (visited_symbols != (struct symbol *)-1L) {
+			struct symbol *sym = visited_symbols;
+
+			if (sym->type != SYM_NORMAL) {
+				putc(symbol_type_name[sym->type][0], dumpfile);
+				putc('#', dumpfile);
+			}
+			fputs(sym->name, dumpfile);
+			putc(' ', dumpfile);
+			print_list(dumpfile, sym->defn);
+			putc('\n', dumpfile);
+
+			visited_symbols = sym->visited;
+			sym->visited = NULL;
+		}
+	}
+
 	if (flag_debug) {
 		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
 			nsyms, HASH_BUCKETS,
diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h
index ab6f34f..2668287 100644
--- a/scripts/genksyms/genksyms.h
+++ b/scripts/genksyms/genksyms.h
@@ -41,6 +41,7 @@
 	enum symbol_type type;
 	struct string_list *defn;
 	struct symbol *expansion_trail;
+	struct symbol *visited;
 	int is_extern;
 };
 
diff --git a/scripts/genksyms/lex.c_shipped b/scripts/genksyms/lex.c_shipped
index 1218053..37ba982 100644
--- a/scripts/genksyms/lex.c_shipped
+++ b/scripts/genksyms/lex.c_shipped
@@ -2023,7 +2023,7 @@
       break;
 
     default:
-      abort();
+      exit(1);
     }
 fini:
 
diff --git a/scripts/genksyms/lex.l b/scripts/genksyms/lex.l
index fe0dfee..5e544a0 100644
--- a/scripts/genksyms/lex.l
+++ b/scripts/genksyms/lex.l
@@ -392,7 +392,7 @@
       break;
 
     default:
-      abort();
+      exit(1);
     }
 fini:
 
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 8012d10..4dcb886 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -539,6 +539,7 @@
   	name = av[i];
 	if (!name) {
 		printf(_("%s: Kconfig file missing\n"), av[0]);
+		exit(1);
 	}
 	conf_parse(name);
 	//zconfdump(stdout);
@@ -573,7 +574,7 @@
 	case set_random:
 		name = getenv("KCONFIG_ALLCONFIG");
 		if (name && !stat(name, &tmpstat)) {
-			conf_read_simple(name);
+			conf_read_simple(name, S_DEF_USER);
 			break;
 		}
 		switch (input_mode) {
@@ -584,9 +585,9 @@
 		default: break;
 		}
 		if (!stat(name, &tmpstat))
-			conf_read_simple(name);
+			conf_read_simple(name, S_DEF_USER);
 		else if (!stat("all.config", &tmpstat))
-			conf_read_simple("all.config");
+			conf_read_simple("all.config", S_DEF_USER);
 		break;
 	default:
 		break;
@@ -599,7 +600,15 @@
 			input_mode = ask_silent;
 			valid_stdin = 1;
 		}
-	}
+	} else if (sym_change_count) {
+		name = getenv("KCONFIG_NOSILENTUPDATE");
+		if (name && *name) {
+			fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n"));
+			return 1;
+		}
+	} else
+		goto skip_check;
+
 	do {
 		conf_cnt = 0;
 		check_conf(&rootmenu);
@@ -608,5 +617,11 @@
 		fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
 		return 1;
 	}
+skip_check:
+	if (input_mode == ask_silent && conf_write_autoconf()) {
+		fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
+		return 1;
+	}
+
 	return 0;
 }
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 1b5df58..2ee48c3 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -5,6 +5,7 @@
 
 #include <sys/stat.h>
 #include <ctype.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -20,19 +21,8 @@
 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";
 
-const char *conf_confnames[] = {
-	".config",
-	"/lib/modules/$UNAME_RELEASE/.config",
-	"/etc/kernel-config",
-	"/boot/config-$UNAME_RELEASE",
-	conf_defname,
-	NULL,
-};
-
 static void conf_warning(const char *fmt, ...)
 {
 	va_list ap;
@@ -44,6 +34,13 @@
 	conf_warnings++;
 }
 
+const char *conf_get_configname(void)
+{
+	char *name = getenv("KCONFIG_CONFIG");
+
+	return name ? name : ".config";
+}
+
 static char *conf_expand_value(const char *in)
 {
 	struct symbol *sym;
@@ -86,51 +83,65 @@
 	return name;
 }
 
-int conf_read_simple(const char *name)
+int conf_read_simple(const char *name, int def)
 {
 	FILE *in = NULL;
 	char line[1024];
 	char *p, *p2;
 	struct symbol *sym;
-	int i;
+	int i, def_flags;
 
 	if (name) {
 		in = zconf_fopen(name);
 	} else {
-		const char **names = conf_confnames;
-		while ((name = *names++)) {
-			name = conf_expand_value(name);
+		struct property *prop;
+
+		name = conf_get_configname();
+		in = zconf_fopen(name);
+		if (in)
+			goto load;
+		sym_change_count++;
+		if (!sym_defconfig_list)
+			return 1;
+
+		for_all_defaults(sym_defconfig_list, prop) {
+			if (expr_calc_value(prop->visible.expr) == no ||
+			    prop->expr->type != E_SYMBOL)
+				continue;
+			name = conf_expand_value(prop->expr->left.sym->name);
 			in = zconf_fopen(name);
 			if (in) {
 				printf(_("#\n"
-				         "# using defaults found in %s\n"
-				         "#\n"), name);
-				break;
+					 "# using defaults found in %s\n"
+					 "#\n"), name);
+				goto load;
 			}
 		}
 	}
 	if (!in)
 		return 1;
 
+load:
 	conf_filename = name;
 	conf_lineno = 0;
 	conf_warnings = 0;
 	conf_unsaved = 0;
 
+	def_flags = SYMBOL_DEF << def;
 	for_all_symbols(i, sym) {
-		sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
+		sym->flags |= SYMBOL_CHANGED;
+		sym->flags &= ~(def_flags|SYMBOL_VALID);
 		if (sym_is_choice(sym))
-			sym->flags &= ~SYMBOL_NEW;
-		sym->flags &= ~SYMBOL_VALID;
+			sym->flags |= def_flags;
 		switch (sym->type) {
 		case S_INT:
 		case S_HEX:
 		case S_STRING:
-			if (sym->user.val)
-				free(sym->user.val);
+			if (sym->def[def].val)
+				free(sym->def[def].val);
 		default:
-			sym->user.val = NULL;
-			sym->user.tri = no;
+			sym->def[def].val = NULL;
+			sym->def[def].tri = no;
 		}
 	}
 
@@ -147,19 +158,26 @@
 			*p++ = 0;
 			if (strncmp(p, "is not set", 10))
 				continue;
-			sym = sym_find(line + 9);
-			if (!sym) {
-				conf_warning("trying to assign nonexistent symbol %s", line + 9);
-				break;
-			} else if (!(sym->flags & SYMBOL_NEW)) {
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 9);
+				if (!sym) {
+					conf_warning("trying to assign nonexistent symbol %s", line + 9);
+					break;
+				}
+			} else {
+				sym = sym_lookup(line + 9, 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_BOOLEAN;
+			}
+			if (sym->flags & def_flags) {
 				conf_warning("trying to reassign symbol %s", sym->name);
 				break;
 			}
 			switch (sym->type) {
 			case S_BOOLEAN:
 			case S_TRISTATE:
-				sym->user.tri = no;
-				sym->flags &= ~SYMBOL_NEW;
+				sym->def[def].tri = no;
+				sym->flags |= def_flags;
 				break;
 			default:
 				;
@@ -177,34 +195,48 @@
 			p2 = strchr(p, '\n');
 			if (p2)
 				*p2 = 0;
-			sym = sym_find(line + 7);
-			if (!sym) {
-				conf_warning("trying to assign nonexistent symbol %s", line + 7);
-				break;
-			} else if (!(sym->flags & SYMBOL_NEW)) {
+			if (def == S_DEF_USER) {
+				sym = sym_find(line + 7);
+				if (!sym) {
+					conf_warning("trying to assign nonexistent symbol %s", line + 7);
+					break;
+				}
+			} else {
+				sym = sym_lookup(line + 7, 0);
+				if (sym->type == S_UNKNOWN)
+					sym->type = S_OTHER;
+			}
+			if (sym->flags & def_flags) {
 				conf_warning("trying to reassign symbol %s", sym->name);
 				break;
 			}
 			switch (sym->type) {
 			case S_TRISTATE:
 				if (p[0] == 'm') {
-					sym->user.tri = mod;
-					sym->flags &= ~SYMBOL_NEW;
+					sym->def[def].tri = mod;
+					sym->flags |= def_flags;
 					break;
 				}
 			case S_BOOLEAN:
 				if (p[0] == 'y') {
-					sym->user.tri = yes;
-					sym->flags &= ~SYMBOL_NEW;
+					sym->def[def].tri = yes;
+					sym->flags |= def_flags;
 					break;
 				}
 				if (p[0] == 'n') {
-					sym->user.tri = no;
-					sym->flags &= ~SYMBOL_NEW;
+					sym->def[def].tri = no;
+					sym->flags |= def_flags;
 					break;
 				}
 				conf_warning("symbol value '%s' invalid for %s", p, sym->name);
 				break;
+			case S_OTHER:
+				if (*p != '"') {
+					for (p2 = p; *p2 && !isspace(*p2); p2++)
+						;
+					sym->type = S_STRING;
+					goto done;
+				}
 			case S_STRING:
 				if (*p++ != '"')
 					break;
@@ -221,9 +253,10 @@
 				}
 			case S_INT:
 			case S_HEX:
+			done:
 				if (sym_string_valid(sym, p)) {
-					sym->user.val = strdup(p);
-					sym->flags &= ~SYMBOL_NEW;
+					sym->def[def].val = strdup(p);
+					sym->flags |= def_flags;
 				} else {
 					conf_warning("symbol value '%s' invalid for %s", p, sym->name);
 					continue;
@@ -241,24 +274,24 @@
 		}
 		if (sym && sym_is_choice_value(sym)) {
 			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
-			switch (sym->user.tri) {
+			switch (sym->def[def].tri) {
 			case no:
 				break;
 			case mod:
-				if (cs->user.tri == yes) {
+				if (cs->def[def].tri == yes) {
 					conf_warning("%s creates inconsistent choice state", sym->name);
-					cs->flags |= SYMBOL_NEW;
+					cs->flags &= ~def_flags;
 				}
 				break;
 			case yes:
-				if (cs->user.tri != no) {
+				if (cs->def[def].tri != no) {
 					conf_warning("%s creates inconsistent choice state", sym->name);
-					cs->flags |= SYMBOL_NEW;
+					cs->flags &= ~def_flags;
 				} else
-					cs->user.val = sym;
+					cs->def[def].val = sym;
 				break;
 			}
-			cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
+			cs->def[def].tri = E_OR(cs->def[def].tri, sym->def[def].tri);
 		}
 	}
 	fclose(in);
@@ -273,9 +306,11 @@
 	struct symbol *sym;
 	struct property *prop;
 	struct expr *e;
-	int i;
+	int i, flags;
 
-	if (conf_read_simple(name))
+	sym_change_count = 0;
+
+	if (conf_read_simple(name, S_DEF_USER))
 		return 1;
 
 	for_all_symbols(i, sym) {
@@ -287,12 +322,12 @@
 			switch (sym->type) {
 			case S_BOOLEAN:
 			case S_TRISTATE:
-				if (sym->user.tri != sym_get_tristate_value(sym))
+				if (sym->def[S_DEF_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))
+				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
 					goto sym_ok;
 				break;
 			}
@@ -304,15 +339,13 @@
 	sym_ok:
 		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
 			if (sym->visible == no)
-				sym->flags |= SYMBOL_NEW;
+				sym->flags &= ~SYMBOL_DEF_USER;
 			switch (sym->type) {
 			case S_STRING:
 			case S_INT:
 			case S_HEX:
-				if (!sym_string_within_range(sym, sym->user.val)) {
-					sym->flags |= SYMBOL_NEW;
-					sym->flags &= ~SYMBOL_VALID;
-				}
+				if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+					sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
 			default:
 				break;
 			}
@@ -320,19 +353,21 @@
 		if (!sym_is_choice(sym))
 			continue;
 		prop = sym_get_choice_prop(sym);
+		flags = sym->flags;
 		for (e = prop->expr; e; e = e->left.expr)
 			if (e->right.sym->visible != no)
-				sym->flags |= e->right.sym->flags & SYMBOL_NEW;
+				flags &= e->right.sym->flags;
+		sym->flags |= flags & SYMBOL_DEF_USER;
 	}
 
-	sym_change_count = conf_warnings || conf_unsaved;
+	sym_change_count += conf_warnings || conf_unsaved;
 
 	return 0;
 }
 
 int conf_write(const char *name)
 {
-	FILE *out, *out_h;
+	FILE *out;
 	struct symbol *sym;
 	struct menu *menu;
 	const char *basename;
@@ -351,7 +386,7 @@
 		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
 			strcpy(dirname, name);
 			strcat(dirname, "/");
-			basename = conf_def_filename;
+			basename = conf_get_configname();
 		} else if ((slash = strrchr(name, '/'))) {
 			int size = slash - name + 1;
 			memcpy(dirname, name, size);
@@ -359,23 +394,24 @@
 			if (slash[1])
 				basename = slash + 1;
 			else
-				basename = conf_def_filename;
+				basename = conf_get_configname();
 		} else
 			basename = name;
 	} else
-		basename = conf_def_filename;
+		basename = conf_get_configname();
 
-	sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
-	out = fopen(newname, "w");
+	sprintf(newname, "%s%s", dirname, basename);
+	env = getenv("KCONFIG_OVERWRITECONFIG");
+	if (!env || !*env) {
+		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+		out = fopen(tmpname, "w");
+	} else {
+		*tmpname = 0;
+		out = fopen(newname, "w");
+	}
 	if (!out)
 		return 1;
-	out_h = NULL;
-	if (!name) {
-		out_h = fopen(".tmpconfig.h", "w");
-		if (!out_h)
-			return 1;
-		file_write_dep(NULL);
-	}
+
 	sym = sym_lookup("KERNELVERSION", 0);
 	sym_calc_value(sym);
 	time(&now);
@@ -391,16 +427,6 @@
 		     sym_get_string_value(sym),
 		     use_timestamp ? "# " : "",
 		     use_timestamp ? ctime(&now) : "");
-	if (out_h)
-		fprintf(out_h, "/*\n"
-			       " * Automatically generated C config: don't edit\n"
-			       " * Linux kernel version: %s\n"
-			       "%s%s"
-			       " */\n"
-			       "#define AUTOCONF_INCLUDED\n",
-			       sym_get_string_value(sym),
-			       use_timestamp ? " * " : "",
-			       use_timestamp ? ctime(&now) : "");
 
 	if (!sym_change_count)
 		sym_clear_all_valid();
@@ -416,11 +442,6 @@
 				     "#\n"
 				     "# %s\n"
 				     "#\n", str);
-			if (out_h)
-				fprintf(out_h, "\n"
-					       "/*\n"
-					       " * %s\n"
-					       " */\n", str);
 		} else if (!(sym->flags & SYMBOL_CHOICE)) {
 			sym_calc_value(sym);
 			if (!(sym->flags & SYMBOL_WRITE))
@@ -438,59 +459,39 @@
 				switch (sym_get_tristate_value(sym)) {
 				case no:
 					fprintf(out, "# CONFIG_%s is not set\n", sym->name);
-					if (out_h)
-						fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
 					break;
 				case mod:
 					fprintf(out, "CONFIG_%s=m\n", sym->name);
-					if (out_h)
-						fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
 					break;
 				case yes:
 					fprintf(out, "CONFIG_%s=y\n", sym->name);
-					if (out_h)
-						fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
 					break;
 				}
 				break;
 			case S_STRING:
-				// fix me
 				str = sym_get_string_value(sym);
 				fprintf(out, "CONFIG_%s=\"", sym->name);
-				if (out_h)
-					fprintf(out_h, "#define CONFIG_%s \"", sym->name);
-				do {
+				while (1) {
 					l = strcspn(str, "\"\\");
 					if (l) {
 						fwrite(str, l, 1, out);
-						if (out_h)
-							fwrite(str, l, 1, out_h);
+						str += l;
 					}
-					str += l;
-					while (*str == '\\' || *str == '"') {
-						fprintf(out, "\\%c", *str);
-						if (out_h)
-							fprintf(out_h, "\\%c", *str);
-						str++;
-					}
-				} while (*str);
+					if (!*str)
+						break;
+					fprintf(out, "\\%c", *str++);
+				}
 				fputs("\"\n", out);
-				if (out_h)
-					fputs("\"\n", out_h);
 				break;
 			case S_HEX:
 				str = sym_get_string_value(sym);
 				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
 					fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
-					if (out_h)
-						fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
 					break;
 				}
 			case S_INT:
 				str = sym_get_string_value(sym);
 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
-				if (out_h)
-					fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
 				break;
 			}
 		}
@@ -510,21 +511,253 @@
 		}
 	}
 	fclose(out);
-	if (out_h) {
-		fclose(out_h);
-		rename(".tmpconfig.h", "include/linux/autoconf.h");
+
+	if (*tmpname) {
+		strcat(dirname, name ? name : conf_get_configname());
+		strcat(dirname, ".old");
+		rename(newname, dirname);
+		if (rename(tmpname, newname))
+			return 1;
 	}
-	if (!name || basename != conf_def_filename) {
-		if (!name)
-			name = conf_def_filename;
-		sprintf(tmpname, "%s.old", name);
-		rename(name, tmpname);
-	}
-	sprintf(tmpname, "%s%s", dirname, basename);
-	if (rename(newname, tmpname))
-		return 1;
+
+	printf(_("#\n"
+		 "# configuration written to %s\n"
+		 "#\n"), newname);
 
 	sym_change_count = 0;
 
 	return 0;
 }
+
+int conf_split_config(void)
+{
+	char *name, path[128];
+	char *s, *d, c;
+	struct symbol *sym;
+	struct stat sb;
+	int res, i, fd;
+
+	name = getenv("KCONFIG_AUTOCONFIG");
+	if (!name)
+		name = "include/config/auto.conf";
+	conf_read_simple(name, S_DEF_AUTO);
+
+	if (chdir("include/config"))
+		return 1;
+
+	res = 0;
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+			continue;
+		if (sym->flags & SYMBOL_WRITE) {
+			if (sym->flags & SYMBOL_DEF_AUTO) {
+				/*
+				 * symbol has old and new value,
+				 * so compare them...
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) ==
+					    sym->def[S_DEF_AUTO].tri)
+						continue;
+					break;
+				case S_STRING:
+				case S_HEX:
+				case S_INT:
+					if (!strcmp(sym_get_string_value(sym),
+						    sym->def[S_DEF_AUTO].val))
+						continue;
+					break;
+				default:
+					break;
+				}
+			} else {
+				/*
+				 * If there is no old value, only 'no' (unset)
+				 * is allowed as new value.
+				 */
+				switch (sym->type) {
+				case S_BOOLEAN:
+				case S_TRISTATE:
+					if (sym_get_tristate_value(sym) == no)
+						continue;
+					break;
+				default:
+					break;
+				}
+			}
+		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
+			/* There is neither an old nor a new value. */
+			continue;
+		/* else
+		 *	There is an old value, but no new value ('no' (unset)
+		 *	isn't saved in auto.conf, so the old value is always
+		 *	different from 'no').
+		 */
+
+		/* Replace all '_' and append ".h" */
+		s = sym->name;
+		d = path;
+		while ((c = *s++)) {
+			c = tolower(c);
+			*d++ = (c == '_') ? '/' : c;
+		}
+		strcpy(d, ".h");
+
+		/* Assume directory path already exists. */
+		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+		if (fd == -1) {
+			if (errno != ENOENT) {
+				res = 1;
+				break;
+			}
+			/*
+			 * Create directory components,
+			 * unless they exist already.
+			 */
+			d = path;
+			while ((d = strchr(d, '/'))) {
+				*d = 0;
+				if (stat(path, &sb) && mkdir(path, 0755)) {
+					res = 1;
+					goto out;
+				}
+				*d++ = '/';
+			}
+			/* Try it again. */
+			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+			if (fd == -1) {
+				res = 1;
+				break;
+			}
+		}
+		close(fd);
+	}
+out:
+	if (chdir("../.."))
+		return 1;
+
+	return res;
+}
+
+int conf_write_autoconf(void)
+{
+	struct symbol *sym;
+	const char *str;
+	char *name;
+	FILE *out, *out_h;
+	time_t now;
+	int i, l;
+
+	sym_clear_all_valid();
+
+	file_write_dep("include/config/auto.conf.cmd");
+
+	if (conf_split_config())
+		return 1;
+
+	out = fopen(".tmpconfig", "w");
+	if (!out)
+		return 1;
+
+	out_h = fopen(".tmpconfig.h", "w");
+	if (!out_h) {
+		fclose(out);
+		return 1;
+	}
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym_calc_value(sym);
+	time(&now);
+	fprintf(out, "#\n"
+		     "# Automatically generated make config: don't edit\n"
+		     "# Linux kernel version: %s\n"
+		     "# %s"
+		     "#\n",
+		     sym_get_string_value(sym), ctime(&now));
+	fprintf(out_h, "/*\n"
+		       " * Automatically generated C config: don't edit\n"
+		       " * Linux kernel version: %s\n"
+		       " * %s"
+		       " */\n"
+		       "#define AUTOCONF_INCLUDED\n",
+		       sym_get_string_value(sym), ctime(&now));
+
+	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+			continue;
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			switch (sym_get_tristate_value(sym)) {
+			case no:
+				break;
+			case mod:
+				fprintf(out, "CONFIG_%s=m\n", sym->name);
+				fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
+				break;
+			case yes:
+				fprintf(out, "CONFIG_%s=y\n", sym->name);
+				fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
+				break;
+			}
+			break;
+		case S_STRING:
+			str = sym_get_string_value(sym);
+			fprintf(out, "CONFIG_%s=\"", sym->name);
+			fprintf(out_h, "#define CONFIG_%s \"", sym->name);
+			while (1) {
+				l = strcspn(str, "\"\\");
+				if (l) {
+					fwrite(str, l, 1, out);
+					fwrite(str, l, 1, out_h);
+					str += l;
+				}
+				if (!*str)
+					break;
+				fprintf(out, "\\%c", *str);
+				fprintf(out_h, "\\%c", *str);
+				str++;
+			}
+			fputs("\"\n", out);
+			fputs("\"\n", out_h);
+			break;
+		case S_HEX:
+			str = sym_get_string_value(sym);
+			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+				fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
+				break;
+			}
+		case S_INT:
+			str = sym_get_string_value(sym);
+			fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
+			fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
+			break;
+		default:
+			break;
+		}
+	}
+	fclose(out);
+	fclose(out_h);
+
+	name = getenv("KCONFIG_AUTOHEADER");
+	if (!name)
+		name = "include/linux/autoconf.h";
+	if (rename(".tmpconfig.h", name))
+		return 1;
+	name = getenv("KCONFIG_AUTOCONFIG");
+	if (!name)
+		name = "include/config/auto.conf";
+	/*
+	 * This must be the last step, kbuild has a dependency on auto.conf
+	 * and this marks the successful completion of the previous steps.
+	 */
+	if (rename(".tmpconfig", name))
+		return 1;
+
+	return 0;
+}
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index 30e4f9d..6f98dbf 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -145,7 +145,8 @@
 		return;
 	}
 	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
-	    e1->left.sym == e2->left.sym && (e1->left.sym->flags & (SYMBOL_YES|SYMBOL_NO)))
+	    e1->left.sym == e2->left.sym &&
+	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
 		return;
 	if (!expr_eq(e1, e2))
 		return;
@@ -1012,73 +1013,73 @@
 #endif
 }
 
-void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken)
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 {
 	if (!e) {
-		fn(data, "y");
+		fn(data, NULL, "y");
 		return;
 	}
 
 	if (expr_compare_type(prevtoken, e->type) > 0)
-		fn(data, "(");
+		fn(data, NULL, "(");
 	switch (e->type) {
 	case E_SYMBOL:
 		if (e->left.sym->name)
-			fn(data, e->left.sym->name);
+			fn(data, e->left.sym, e->left.sym->name);
 		else
-			fn(data, "<choice>");
+			fn(data, NULL, "<choice>");
 		break;
 	case E_NOT:
-		fn(data, "!");
+		fn(data, NULL, "!");
 		expr_print(e->left.expr, fn, data, E_NOT);
 		break;
 	case E_EQUAL:
-		fn(data, e->left.sym->name);
-		fn(data, "=");
-		fn(data, e->right.sym->name);
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, "=");
+		fn(data, e->right.sym, e->right.sym->name);
 		break;
 	case E_UNEQUAL:
-		fn(data, e->left.sym->name);
-		fn(data, "!=");
-		fn(data, e->right.sym->name);
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, "!=");
+		fn(data, e->right.sym, e->right.sym->name);
 		break;
 	case E_OR:
 		expr_print(e->left.expr, fn, data, E_OR);
-		fn(data, " || ");
+		fn(data, NULL, " || ");
 		expr_print(e->right.expr, fn, data, E_OR);
 		break;
 	case E_AND:
 		expr_print(e->left.expr, fn, data, E_AND);
-		fn(data, " && ");
+		fn(data, NULL, " && ");
 		expr_print(e->right.expr, fn, data, E_AND);
 		break;
 	case E_CHOICE:
-		fn(data, e->right.sym->name);
+		fn(data, e->right.sym, e->right.sym->name);
 		if (e->left.expr) {
-			fn(data, " ^ ");
+			fn(data, NULL, " ^ ");
 			expr_print(e->left.expr, fn, data, E_CHOICE);
 		}
 		break;
 	case E_RANGE:
-		fn(data, "[");
-		fn(data, e->left.sym->name);
-		fn(data, " ");
-		fn(data, e->right.sym->name);
-		fn(data, "]");
+		fn(data, NULL, "[");
+		fn(data, e->left.sym, e->left.sym->name);
+		fn(data, NULL, " ");
+		fn(data, e->right.sym, e->right.sym->name);
+		fn(data, NULL, "]");
 		break;
 	default:
 	  {
 		char buf[32];
 		sprintf(buf, "<unknown type %d>", e->type);
-		fn(data, buf);
+		fn(data, NULL, buf);
 		break;
 	  }
 	}
 	if (expr_compare_type(prevtoken, e->type) > 0)
-		fn(data, ")");
+		fn(data, NULL, ")");
 }
 
-static void expr_print_file_helper(void *data, const char *str)
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 {
 	fwrite(str, strlen(str), 1, data);
 }
@@ -1088,7 +1089,7 @@
 	expr_print(e, expr_print_file_helper, out, E_NONE);
 }
 
-static void expr_print_gstr_helper(void *data, const char *str)
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
 {
 	str_append((struct gstr*)data, str);
 }
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 1b36ef1..6084525 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -63,12 +63,18 @@
 	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
 };
 
+enum {
+	S_DEF_USER,		/* main user value */
+	S_DEF_AUTO,
+};
+
 struct symbol {
 	struct symbol *next;
 	char *name;
 	char *help;
 	enum symbol_type type;
-	struct symbol_value curr, user;
+	struct symbol_value curr;
+	struct symbol_value def[4];
 	tristate visible;
 	int flags;
 	struct property *prop;
@@ -78,10 +84,7 @@
 
 #define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
 
-#define SYMBOL_YES		0x0001
-#define SYMBOL_MOD		0x0002
-#define SYMBOL_NO		0x0004
-#define SYMBOL_CONST		0x0007
+#define SYMBOL_CONST		0x0001
 #define SYMBOL_CHECK		0x0008
 #define SYMBOL_CHOICE		0x0010
 #define SYMBOL_CHOICEVAL	0x0020
@@ -90,10 +93,14 @@
 #define SYMBOL_OPTIONAL		0x0100
 #define SYMBOL_WRITE		0x0200
 #define SYMBOL_CHANGED		0x0400
-#define SYMBOL_NEW		0x0800
 #define SYMBOL_AUTO		0x1000
 #define SYMBOL_CHECKED		0x2000
 #define SYMBOL_WARNED		0x8000
+#define SYMBOL_DEF		0x10000
+#define SYMBOL_DEF_USER		0x10000
+#define SYMBOL_DEF_AUTO		0x20000
+#define SYMBOL_DEF3		0x40000
+#define SYMBOL_DEF4		0x80000
 
 #define SYMBOL_MAXLENGTH	256
 #define SYMBOL_HASHSIZE		257
@@ -149,6 +156,7 @@
 
 extern struct symbol symbol_yes, symbol_no, symbol_mod;
 extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
 extern int cdebug;
 struct expr *expr_alloc_symbol(struct symbol *sym);
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 665bd53..7b0d3a9 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -114,12 +114,6 @@
 
 	bzero(buf, 256);
 
-	if (val & SYMBOL_YES)
-		strcat(buf, "yes/");
-	if (val & SYMBOL_MOD)
-		strcat(buf, "mod/");
-	if (val & SYMBOL_NO)
-		strcat(buf, "no/");
 	if (val & SYMBOL_CONST)
 		strcat(buf, "const/");
 	if (val & SYMBOL_CHECK)
@@ -138,8 +132,6 @@
 		strcat(buf, "write/");
 	if (val & SYMBOL_CHANGED)
 		strcat(buf, "changed/");
-	if (val & SYMBOL_NEW)
-		strcat(buf, "new/");
 	if (val & SYMBOL_AUTO)
 		strcat(buf, "auto/");
 
@@ -1192,9 +1184,7 @@
 
 	row[COL_OPTION] =
 	    g_strdup_printf("%s %s", menu_get_prompt(menu),
-			    sym ? (sym->
-				   flags & SYMBOL_NEW ? "(NEW)" : "") :
-			    "");
+			    sym && sym_has_value(sym) ? "(NEW)" : "");
 
 	if (show_all && !menu_is_visible(menu))
 		row[COL_COLOR] = g_strdup("DarkGray");
diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped
index 24e3c8c..800f8c7 100644
--- a/scripts/kconfig/lex.zconf.c_shipped
+++ b/scripts/kconfig/lex.zconf.c_shipped
@@ -8,7 +8,7 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 31
+#define YY_FLEX_SUBMINOR_VERSION 33
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -30,7 +30,15 @@
 
 /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
 
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
 #include <inttypes.h>
 typedef int8_t flex_int8_t;
 typedef uint8_t flex_uint8_t;
@@ -134,6 +142,10 @@
 #define YY_BUF_SIZE 16384
 #endif
 
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
 #define YY_TYPEDEF_YY_BUFFER_STATE
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
@@ -267,7 +279,7 @@
 
 /* Points to current character in buffer. */
 static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1;		/* whether we need to initialize */
+static int yy_init = 0;		/* whether we need to initialize */
 static int yy_start = 0;	/* start state number */
 
 /* Flag which is used to allow zconfwrap()'s to do buffer switches
@@ -820,6 +832,8 @@
 #define YY_EXTRA_TYPE void *
 #endif
 
+static int yy_init_globals (void );
+
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
  */
@@ -942,9 +956,9 @@
 	int str = 0;
 	int ts, i;
 
-	if ( (yy_init) )
+	if ( !(yy_init) )
 		{
-		(yy_init) = 0;
+		(yy_init) = 1;
 
 #ifdef YY_USER_INIT
 		YY_USER_INIT;
@@ -1452,7 +1466,7 @@
 
 	else
 		{
-			size_t num_to_read =
+			int num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
 		while ( num_to_read <= 0 )
@@ -1969,16 +1983,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 yy_str a NUL-terminated string to scan
+ * @param yystr 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 * yy_str )
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
 {
     
-	return zconf_scan_bytes(yy_str,strlen(yy_str) );
+	return zconf_scan_bytes(yystr,strlen(yystr) );
 }
 
 /** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
@@ -1988,7 +2002,7 @@
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * bytes, int  len )
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
 {
 	YY_BUFFER_STATE b;
 	char *buf;
@@ -1996,15 +2010,15 @@
 	int i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = len + 2;
+	n = _yybytes_len + 2;
 	buf = (char *) zconfalloc(n  );
 	if ( ! buf )
 		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
 
-	for ( i = 0; i < len; ++i )
-		buf[i] = bytes[i];
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
 
-	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
 	b = zconf_scan_buffer(buf,n );
 	if ( ! b )
@@ -2125,6 +2139,34 @@
         zconf_flex_debug = bdebug ;
 }
 
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
 /* zconflex_destroy is for both reentrant and non-reentrant scanners. */
 int zconflex_destroy  (void)
 {
@@ -2140,6 +2182,10 @@
 	zconffree((yy_buffer_stack) );
 	(yy_buffer_stack) = NULL;
 
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
     return 0;
 }
 
@@ -2151,7 +2197,7 @@
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 {
 	register int i;
-    	for ( i = 0; i < n; ++i )
+	for ( i = 0; i < n; ++i )
 		s1[i] = s2[i];
 }
 #endif
@@ -2160,7 +2206,7 @@
 static int yy_flex_strlen (yyconst char * s )
 {
 	register int n;
-    	for ( n = 0; s[n]; ++n )
+	for ( n = 0; s[n]; ++n )
 		;
 
 	return n;
@@ -2191,19 +2237,6 @@
 
 #define YYTABLES_NAME "yytables"
 
-#undef YY_NEW_FILE
-#undef YY_FLUSH_BUFFER
-#undef yy_set_bol
-#undef yy_new_buffer
-#undef yy_set_interactive
-#undef yytext_ptr
-#undef YY_DO_BEFORE_ACTION
-
-#ifdef YY_DECL_IS_OURS
-#undef YY_DECL_IS_OURS
-#undef YY_DECL
-#endif
-
 void zconf_starthelp(void)
 {
 	new_string();
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 527f60c..2628023 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -40,6 +40,10 @@
 
 #define TF_COMMAND	0x0001
 #define TF_PARAM	0x0002
+#define TF_OPTION	0x0004
+
+#define T_OPT_MODULES		1
+#define T_OPT_DEFCONFIG_LIST	2
 
 struct kconf_id {
 	int name;
@@ -60,8 +64,6 @@
 char *zconf_curname(void);
 
 /* confdata.c */
-extern const char conf_def_filename[];
-
 char *conf_get_default_confname(void);
 
 /* kconfig_load.c */
@@ -78,6 +80,7 @@
 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
 void menu_finalize(struct menu *parent);
 void menu_set_type(int type);
 
@@ -99,6 +102,7 @@
 /* symbol.c */
 void sym_init(void);
 void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
 void sym_set_changed(struct symbol *sym);
 struct symbol *sym_check_deps(struct symbol *sym);
 struct property *prop_alloc(enum prop_type type, struct symbol *sym);
@@ -137,7 +141,7 @@
 
 static inline bool sym_has_value(struct symbol *sym)
 {
-	return sym->flags & SYMBOL_NEW ? false : true;
+	return sym->flags & SYMBOL_DEF_USER ? true : false;
 }
 
 #ifdef __cplusplus
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index b6a389c..a263746 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -2,8 +2,9 @@
 /* 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_read_simple,int,(const char *name, int));
 P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
 
 /* menu.c */
 P(rootmenu,struct menu,);
@@ -38,4 +39,4 @@
 
 /* expr.c */
 P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
-P(expr_print,void,(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 0fce20c..c86c27f 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -114,7 +114,7 @@
 		sym->type = type;
 		return;
 	}
-	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
+	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
 	    sym->name ? sym->name : "<choice>",
 	    sym_type_name(sym->type), sym_type_name(type));
 }
@@ -124,15 +124,20 @@
 	struct property *prop = prop_alloc(type, current_entry->sym);
 
 	prop->menu = current_entry;
-	prop->text = prompt;
 	prop->expr = expr;
 	prop->visible.expr = menu_check_dep(dep);
 
 	if (prompt) {
+		if (isspace(*prompt)) {
+			prop_warn(prop, "leading whitespace ignored");
+			while (isspace(*prompt))
+				prompt++;
+		}
 		if (current_entry->prompt)
-			menu_warn(current_entry, "prompt redefined\n");
+			prop_warn(prop, "prompt redefined");
 		current_entry->prompt = prop;
 	}
+	prop->text = prompt;
 
 	return prop;
 }
@@ -152,6 +157,24 @@
 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
 }
 
+void menu_add_option(int token, char *arg)
+{
+	struct property *prop;
+
+	switch (token) {
+	case T_OPT_MODULES:
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(current_entry->sym);
+		break;
+	case T_OPT_DEFCONFIG_LIST:
+		if (!sym_defconfig_list)
+			sym_defconfig_list = current_entry->sym;
+		else if (sym_defconfig_list != current_entry->sym)
+			zconf_error("trying to redefine defconfig symbol");
+		break;
+	}
+}
+
 static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
 {
 	return sym2->type == S_INT || sym2->type == S_HEX ||
@@ -325,11 +348,10 @@
 
 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
 		if (sym->type == S_UNKNOWN)
-			menu_warn(parent, "config symbol defined "
-			    "without type\n");
+			menu_warn(parent, "config symbol defined without type");
 
 		if (sym_is_choice(sym) && !parent->prompt)
-			menu_warn(parent, "choice must have a prompt\n");
+			menu_warn(parent, "choice must have a prompt");
 
 		/* Check properties connected to this symbol */
 		sym_check_prop(sym);
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 4590cd3..393f374 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -6,16 +6,20 @@
 #include <qapplication.h>
 #include <qmainwindow.h>
 #include <qtoolbar.h>
+#include <qlayout.h>
 #include <qvbox.h>
 #include <qsplitter.h>
 #include <qlistview.h>
-#include <qtextview.h>
+#include <qtextbrowser.h>
 #include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
 #include <qmenubar.h>
 #include <qmessagebox.h>
 #include <qaction.h>
 #include <qheader.h>
 #include <qfiledialog.h>
+#include <qdragobject.h>
 #include <qregexp.h>
 
 #include <stdlib.h>
@@ -32,32 +36,16 @@
 #endif
 
 static QApplication *configApp;
+static ConfigSettings *configSettings;
 
 static inline QString qgettext(const char* str)
 {
-  return QString::fromLocal8Bit(gettext(str));
+	return QString::fromLocal8Bit(gettext(str));
 }
 
 static inline QString qgettext(const QString& str)
 {
-  return QString::fromLocal8Bit(gettext(str.latin1()));
-}
-
-ConfigSettings::ConfigSettings()
-	: showAll(false), showName(false), showRange(false), showData(false)
-{
-}
-
-#if QT_VERSION >= 300
-/**
- * Reads the list column settings from the application settings.
- */
-void ConfigSettings::readListSettings()
-{
-	showAll = readBoolEntry("/kconfig/qconf/showAll", false);
-	showName = readBoolEntry("/kconfig/qconf/showName", false);
-	showRange = readBoolEntry("/kconfig/qconf/showRange", false);
-	showData = readBoolEntry("/kconfig/qconf/showData", false);
+	return QString::fromLocal8Bit(gettext(str.latin1()));
 }
 
 /**
@@ -88,77 +76,8 @@
 		stringList.push_back(QString::number(*it));
 	return writeEntry(key, stringList);
 }
-#endif
 
 
-/*
- * update all the children of a menu entry
- *   removes/adds the entries from the parent widget as necessary
- *
- * parent: either the menu list widget or a menu entry widget
- * menu: entry to be updated
- */
-template <class P>
-void ConfigList::updateMenuList(P* parent, struct menu* menu)
-{
-	struct menu* child;
-	ConfigItem* item;
-	ConfigItem* last;
-	bool visible;
-	enum prop_type type;
-
-	if (!menu) {
-		while ((item = parent->firstChild()))
-			delete item;
-		return;
-	}
-
-	last = parent->firstChild();
-	if (last && !last->goParent)
-		last = 0;
-	for (child = menu->list; child; child = child->next) {
-		item = last ? last->nextSibling() : parent->firstChild();
-		type = child->prompt ? child->prompt->type : P_UNKNOWN;
-
-		switch (mode) {
-		case menuMode:
-			if (!(child->flags & MENU_ROOT))
-				goto hide;
-			break;
-		case symbolMode:
-			if (child->flags & MENU_ROOT)
-				goto hide;
-			break;
-		default:
-			break;
-		}
-
-		visible = menu_is_visible(child);
-		if (showAll || visible) {
-			if (!item || item->menu != child)
-				item = new ConfigItem(parent, last, child, visible);
-			else
-				item->testUpdateMenu(visible);
-
-			if (mode == fullMode || mode == menuMode || type != P_MENU)
-				updateMenuList(item, child);
-			else
-				updateMenuList(item, 0);
-			last = item;
-			continue;
-		}
-	hide:
-		if (item && item->menu == child) {
-			last = parent->firstChild();
-			if (last == item)
-				last = 0;
-			else while (last->nextSibling() != item)
-				last = last->nextSibling();
-			delete item;
-		}
-	}
-}
-
 #if QT_VERSION >= 300
 /*
  * set the new data
@@ -355,6 +274,12 @@
 	}
 }
 
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+	: Parent(parent)
+{
+	connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+}
+
 void ConfigLineEdit::show(ConfigItem* i)
 {
 	item = i;
@@ -385,14 +310,14 @@
 	hide();
 }
 
-ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv, ConfigSettings* configSettings)
-	: Parent(p), cview(cv),
+ConfigList::ConfigList(ConfigView* p, const char *name)
+	: Parent(p, name),
 	  updateAll(false),
 	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
 	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
 	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
 	  showAll(false), showName(false), showRange(false), showData(false),
-	  rootEntry(0)
+	  rootEntry(0), headerPopup(0)
 {
 	int i;
 
@@ -406,11 +331,14 @@
 	connect(this, SIGNAL(selectionChanged(void)),
 		SLOT(updateSelection(void)));
 
-	if (configSettings) {
-		showAll = configSettings->showAll;
-		showName = configSettings->showName;
-		showRange = configSettings->showRange;
-		showData = configSettings->showData;
+	if (name) {
+		configSettings->beginGroup(name);
+		showAll = configSettings->readBoolEntry("/showAll", false);
+		showName = configSettings->readBoolEntry("/showName", false);
+		showRange = configSettings->readBoolEntry("/showRange", false);
+		showData = configSettings->readBoolEntry("/showData", false);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
 	}
 
 	for (i = 0; i < colNr; i++)
@@ -441,6 +369,30 @@
 	updateListAll();
 }
 
+void ConfigList::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/showName", showName);
+		configSettings->writeEntry("/showRange", showRange);
+		configSettings->writeEntry("/showData", showData);
+		configSettings->writeEntry("/showAll", showAll);
+		configSettings->endGroup();
+	}
+}
+
+ConfigItem* ConfigList::findConfigItem(struct menu *menu)
+{
+	ConfigItem* item = (ConfigItem*)menu->data;
+
+	for (; item; item = item->nextItem) {
+		if (this == item->listView())
+			break;
+	}
+
+	return item;
+}
+
 void ConfigList::updateSelection(void)
 {
 	struct menu *menu;
@@ -450,9 +402,8 @@
 	if (!item)
 		return;
 
-	cview->setHelp(item);
-
 	menu = item->menu;
+	emit menuChanged(menu);
 	if (!menu)
 		return;
 	type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
@@ -464,8 +415,20 @@
 {
 	ConfigItem* last = 0;
 
-	if (!rootEntry)
-		goto update;
+	if (!rootEntry) {
+		if (mode != listMode)
+			goto update;
+		QListViewItemIterator it(this);
+		ConfigItem* item;
+
+		for (; it.current(); ++it) {
+			item = (ConfigItem*)it.current();
+			if (!item->menu)
+				continue;
+			item->testUpdateMenu(menu_is_visible(item->menu));
+		}
+		return;
+	}
 
 	if (rootEntry != &rootmenu && (mode == singleMode ||
 	    (mode == symbolMode && rootEntry->parent != &rootmenu))) {
@@ -491,14 +454,6 @@
 	triggerUpdate();
 }
 
-void ConfigList::setAllOpen(bool open)
-{
-	QListViewItemIterator it(this);
-
-	for (; it.current(); it++)
-		it.current()->setOpen(open);
-}
-
 void ConfigList::setValue(ConfigItem* item, tristate val)
 {
 	struct symbol* sym;
@@ -581,6 +536,7 @@
 	rootEntry = menu;
 	updateListAll();
 	setSelected(currentItem(), hasFocus());
+	ensureItemVisible(currentItem());
 }
 
 void ConfigList::setParentMenu(void)
@@ -603,6 +559,74 @@
 	}
 }
 
+/*
+ * update all the children of a menu entry
+ *   removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+	struct menu* child;
+	ConfigItem* item;
+	ConfigItem* last;
+	bool visible;
+	enum prop_type type;
+
+	if (!menu) {
+		while ((item = parent->firstChild()))
+			delete item;
+		return;
+	}
+
+	last = parent->firstChild();
+	if (last && !last->goParent)
+		last = 0;
+	for (child = menu->list; child; child = child->next) {
+		item = last ? last->nextSibling() : parent->firstChild();
+		type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+		switch (mode) {
+		case menuMode:
+			if (!(child->flags & MENU_ROOT))
+				goto hide;
+			break;
+		case symbolMode:
+			if (child->flags & MENU_ROOT)
+				goto hide;
+			break;
+		default:
+			break;
+		}
+
+		visible = menu_is_visible(child);
+		if (showAll || visible) {
+			if (!item || item->menu != child)
+				item = new ConfigItem(parent, last, child, visible);
+			else
+				item->testUpdateMenu(visible);
+
+			if (mode == fullMode || mode == menuMode || type != P_MENU)
+				updateMenuList(item, child);
+			else
+				updateMenuList(item, 0);
+			last = item;
+			continue;
+		}
+	hide:
+		if (item && item->menu == child) {
+			last = parent->firstChild();
+			if (last == item)
+				last = 0;
+			else while (last->nextSibling() != item)
+				last = last->nextSibling();
+			delete item;
+		}
+	}
+}
+
 void ConfigList::keyPressEvent(QKeyEvent* ev)
 {
 	QListViewItem* i = currentItem();
@@ -610,7 +634,7 @@
 	struct menu *menu;
 	enum prop_type type;
 
-	if (ev->key() == Key_Escape && mode != fullMode) {
+	if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) {
 		emit parentSelected();
 		ev->accept();
 		return;
@@ -755,23 +779,62 @@
 
 void ConfigList::focusInEvent(QFocusEvent *e)
 {
+	struct menu *menu = NULL;
+
 	Parent::focusInEvent(e);
 
-	QListViewItem* item = currentItem();
-	if (!item)
-		return;
+	ConfigItem* item = (ConfigItem *)currentItem();
+	if (item) {
+		setSelected(item, TRUE);
+		menu = item->menu;
+	}
+	emit gotFocus(menu);
+}
 
-	setSelected(item, TRUE);
-	emit gotFocus();
+void ConfigList::contextMenuEvent(QContextMenuEvent *e)
+{
+	if (e->y() <= header()->geometry().bottom()) {
+		if (!headerPopup) {
+			QAction *action;
+
+			headerPopup = new QPopupMenu(this);
+			action = new QAction("Show Name", 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowName(bool)));
+			  connect(parent(), SIGNAL(showNameChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showName);
+			  action->addTo(headerPopup);
+			action = new QAction("Show Range", 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowRange(bool)));
+			  connect(parent(), SIGNAL(showRangeChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showRange);
+			  action->addTo(headerPopup);
+			action = new QAction("Show Data", 0, this);
+			  action->setToggleAction(TRUE);
+			  connect(action, SIGNAL(toggled(bool)),
+				  parent(), SLOT(setShowData(bool)));
+			  connect(parent(), SIGNAL(showDataChanged(bool)),
+				  action, SLOT(setOn(bool)));
+			  action->setOn(showData);
+			  action->addTo(headerPopup);
+		}
+		headerPopup->exec(e->globalPos());
+		e->accept();
+	} else
+		e->ignore();
 }
 
 ConfigView* ConfigView::viewList;
 
-ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview,
-		       ConfigSettings *configSettings)
-	: Parent(parent)
+ConfigView::ConfigView(QWidget* parent, const char *name)
+	: Parent(parent, name)
 {
-	list = new ConfigList(this, cview, configSettings);
+	list = new ConfigList(this, name);
 	lineEdit = new ConfigLineEdit(this);
 	lineEdit->hide();
 
@@ -791,6 +854,50 @@
 	}
 }
 
+void ConfigView::setShowAll(bool b)
+{
+	if (list->showAll != b) {
+		list->showAll = b;
+		list->updateListAll();
+		emit showAllChanged(b);
+	}
+}
+
+void ConfigView::setShowName(bool b)
+{
+	if (list->showName != b) {
+		list->showName = b;
+		list->reinit();
+		emit showNameChanged(b);
+	}
+}
+
+void ConfigView::setShowRange(bool b)
+{
+	if (list->showRange != b) {
+		list->showRange = b;
+		list->reinit();
+		emit showRangeChanged(b);
+	}
+}
+
+void ConfigView::setShowData(bool b)
+{
+	if (list->showData != b) {
+		list->showData = b;
+		list->reinit();
+		emit showDataChanged(b);
+	}
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+	QListViewItemIterator it(this);
+
+	for (; it.current(); it++)
+		it.current()->setOpen(open);
+}
+
 void ConfigView::updateList(ConfigItem* item)
 {
 	ConfigView* v;
@@ -807,177 +914,207 @@
 		v->list->updateListAll();
 }
 
-/*
- * Construct the complete config widget
- */
-ConfigMainWindow::ConfigMainWindow(void)
+ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
+	: Parent(parent, name), menu(0)
 {
-	QMenuBar* menu;
-	bool ok;
-	int x, y, width, height;
-
-	QWidget *d = configApp->desktop();
-
-	ConfigSettings* configSettings = new ConfigSettings();
-#if QT_VERSION >= 300
-	width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64);
-	height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64);
-	resize(width, height);
-	x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok);
-	if (ok)
-		y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok);
-	if (ok)
-		move(x, y);
-	showDebug = configSettings->readBoolEntry("/kconfig/qconf/showDebug", false);
-
-	// read list settings into configSettings, will be used later for ConfigList setup
-	configSettings->readListSettings();
-#else
-	width = d->width() - 64;
-	height = d->height() - 64;
-	resize(width, height);
-	showDebug = false;
-#endif
-
-	split1 = new QSplitter(this);
-	split1->setOrientation(QSplitter::Horizontal);
-	setCentralWidget(split1);
-
-	menuView = new ConfigView(split1, this, configSettings);
-	menuList = menuView->list;
-
-	split2 = new QSplitter(split1);
-	split2->setOrientation(QSplitter::Vertical);
-
-	// create config tree
-	configView = new ConfigView(split2, this, configSettings);
-	configList = configView->list;
-
-	helpText = new QTextView(split2);
-	helpText->setTextFormat(Qt::RichText);
-
-	setTabOrder(configList, helpText);
-	configList->setFocus();
-
-	menu = menuBar();
-	toolBar = new QToolBar("Tools", this);
-
-	backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
-	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
-	  backAction->setEnabled(FALSE);
-	QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
-	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
-	QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
-	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
-	QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
-	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
-	QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
-	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
-	QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
-	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
-	QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
-	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
-	QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
-	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
-
-	QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
-	  showNameAction->setToggleAction(TRUE);
-	  showNameAction->setOn(configList->showName);
-	  connect(showNameAction, SIGNAL(toggled(bool)), SLOT(setShowName(bool)));
-	QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
-	  showRangeAction->setToggleAction(TRUE);
-	  showRangeAction->setOn(configList->showRange);
-	  connect(showRangeAction, SIGNAL(toggled(bool)), SLOT(setShowRange(bool)));
-	QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
-	  showDataAction->setToggleAction(TRUE);
-	  showDataAction->setOn(configList->showData);
-	  connect(showDataAction, SIGNAL(toggled(bool)), SLOT(setShowData(bool)));
-	QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
-	  showAllAction->setToggleAction(TRUE);
-	  showAllAction->setOn(configList->showAll);
-	  connect(showAllAction, SIGNAL(toggled(bool)), SLOT(setShowAll(bool)));
-	QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
-	  showDebugAction->setToggleAction(TRUE);
-	  showDebugAction->setOn(showDebug);
-	  connect(showDebugAction, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
-
-	QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
-	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
-	QAction *showAboutAction = new QAction(NULL, "About", 0, this);
-	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
-
-	// init tool bar
-	backAction->addTo(toolBar);
-	toolBar->addSeparator();
-	loadAction->addTo(toolBar);
-	saveAction->addTo(toolBar);
-	toolBar->addSeparator();
-	singleViewAction->addTo(toolBar);
-	splitViewAction->addTo(toolBar);
-	fullViewAction->addTo(toolBar);
-
-	// create config menu
-	QPopupMenu* config = new QPopupMenu(this);
-	menu->insertItem("&File", config);
-	loadAction->addTo(config);
-	saveAction->addTo(config);
-	saveAsAction->addTo(config);
-	config->insertSeparator();
-	quitAction->addTo(config);
-
-	// create options menu
-	QPopupMenu* optionMenu = new QPopupMenu(this);
-	menu->insertItem("&Option", optionMenu);
-	showNameAction->addTo(optionMenu);
-	showRangeAction->addTo(optionMenu);
-	showDataAction->addTo(optionMenu);
-	optionMenu->insertSeparator();
-	showAllAction->addTo(optionMenu);
-	showDebugAction->addTo(optionMenu);
-
-	// create help menu
-	QPopupMenu* helpMenu = new QPopupMenu(this);
-	menu->insertSeparator();
-	menu->insertItem("&Help", helpMenu);
-	showIntroAction->addTo(helpMenu);
-	showAboutAction->addTo(helpMenu);
-
-	connect(configList, SIGNAL(menuSelected(struct menu *)),
-		SLOT(changeMenu(struct menu *)));
-	connect(configList, SIGNAL(parentSelected()),
-		SLOT(goBack()));
-	connect(menuList, SIGNAL(menuSelected(struct menu *)),
-		SLOT(changeMenu(struct menu *)));
-
-	connect(configList, SIGNAL(gotFocus(void)),
-		SLOT(listFocusChanged(void)));
-	connect(menuList, SIGNAL(gotFocus(void)),
-		SLOT(listFocusChanged(void)));
-
-#if QT_VERSION >= 300
-	QString listMode = configSettings->readEntry("/kconfig/qconf/listMode", "symbol");
-	if (listMode == "single")
-		showSingleView();
-	else if (listMode == "full")
-		showFullView();
-	else /*if (listMode == "split")*/
-		showSplitView();
-
-	// UI setup done, restore splitter positions
-	QValueList<int> sizes = configSettings->readSizes("/kconfig/qconf/split1", &ok);
-	if (ok)
-		split1->setSizes(sizes);
-
-	sizes = configSettings->readSizes("/kconfig/qconf/split2", &ok);
-	if (ok)
-		split2->setSizes(sizes);
-#else
-	showSplitView();
-#endif
-	delete configSettings;
+	if (name) {
+		configSettings->beginGroup(name);
+		_showDebug = configSettings->readBoolEntry("/showDebug", false);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
 }
 
-static QString print_filter(const QString &str)
+void ConfigInfoView::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/showDebug", showDebug());
+		configSettings->endGroup();
+	}
+}
+
+void ConfigInfoView::setShowDebug(bool b)
+{
+	if (_showDebug != b) {
+		_showDebug = b;
+		if (menu)
+			menuInfo();
+		else if (sym)
+			symbolInfo();
+		emit showDebugChanged(b);
+	}
+}
+
+void ConfigInfoView::setInfo(struct menu *m)
+{
+	if (menu == m)
+		return;
+	menu = m;
+	if (!menu)
+		clear();
+	else
+		menuInfo();
+}
+
+void ConfigInfoView::setSource(const QString& name)
+{
+	const char *p = name.latin1();
+
+	menu = NULL;
+	sym = NULL;
+
+	switch (p[0]) {
+	case 'm':
+		struct menu *m;
+
+		if (sscanf(p, "m%p", &m) == 1 && menu != m) {
+			menu = m;
+			menuInfo();
+			emit menuSelected(menu);
+		}
+		break;
+	case 's':
+		struct symbol *s;
+
+		if (sscanf(p, "s%p", &s) == 1 && sym != s) {
+			sym = s;
+			symbolInfo();
+		}
+		break;
+	}
+}
+
+void ConfigInfoView::symbolInfo(void)
+{
+	QString str;
+
+	str += "<big>Symbol: <b>";
+	str += print_filter(sym->name);
+	str += "</b></big><br><br>value: ";
+	str += print_filter(sym_get_string_value(sym));
+	str += "<br>visibility: ";
+	str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
+	str += "<br>";
+	str += debug_info(sym);
+
+	setText(str);
+}
+
+void ConfigInfoView::menuInfo(void)
+{
+	struct symbol* sym;
+	QString head, debug, help;
+
+	sym = menu->sym;
+	if (sym) {
+		if (menu->prompt) {
+			head += "<big><b>";
+			head += print_filter(_(menu->prompt->text));
+			head += "</b></big>";
+			if (sym->name) {
+				head += " (";
+				if (showDebug())
+					head += QString().sprintf("<a href=\"s%p\">", sym);
+				head += print_filter(sym->name);
+				if (showDebug())
+					head += "</a>";
+				head += ")";
+			}
+		} else if (sym->name) {
+			head += "<big><b>";
+			if (showDebug())
+				head += QString().sprintf("<a href=\"s%p\">", sym);
+			head += print_filter(sym->name);
+			if (showDebug())
+				head += "</a>";
+			head += "</b></big>";
+		}
+		head += "<br><br>";
+
+		if (showDebug())
+			debug = debug_info(sym);
+
+		help = print_filter(_(sym->help));
+	} else if (menu->prompt) {
+		head += "<big><b>";
+		head += print_filter(_(menu->prompt->text));
+		head += "</b></big><br><br>";
+		if (showDebug()) {
+			if (menu->prompt->visible.expr) {
+				debug += "&nbsp;&nbsp;dep: ";
+				expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+				debug += "<br><br>";
+			}
+		}
+	}
+	if (showDebug())
+		debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
+
+	setText(head + debug + help);
+}
+
+QString ConfigInfoView::debug_info(struct symbol *sym)
+{
+	QString debug;
+
+	debug += "type: ";
+	debug += print_filter(sym_type_name(sym->type));
+	if (sym_is_choice(sym))
+		debug += " (choice)";
+	debug += "<br>";
+	if (sym->rev_dep.expr) {
+		debug += "reverse dep: ";
+		expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+		debug += "<br>";
+	}
+	for (struct property *prop = sym->prop; prop; prop = prop->next) {
+		switch (prop->type) {
+		case P_PROMPT:
+		case P_MENU:
+			debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
+			debug += print_filter(_(prop->text));
+			debug += "</a><br>";
+			break;
+		case P_DEFAULT:
+			debug += "default: ";
+			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+			break;
+		case P_CHOICE:
+			if (sym_is_choice(sym)) {
+				debug += "choice: ";
+				expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+				debug += "<br>";
+			}
+			break;
+		case P_SELECT:
+			debug += "select: ";
+			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+			break;
+		case P_RANGE:
+			debug += "range: ";
+			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+			break;
+		default:
+			debug += "unknown property: ";
+			debug += prop_get_type_name(prop->type);
+			debug += "<br>";
+		}
+		if (prop->visible.expr) {
+			debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
+			expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+			debug += "<br>";
+		}
+	}
+	debug += "<br>";
+
+	return debug;
+}
+
+QString ConfigInfoView::print_filter(const QString &str)
 {
 	QRegExp re("[<>&\"\\n]");
 	QString res = str;
@@ -1008,118 +1145,284 @@
 	return res;
 }
 
-static void expr_print_help(void *data, const char *str)
+void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
 {
-	reinterpret_cast<QString*>(data)->append(print_filter(str));
+	QString* text = reinterpret_cast<QString*>(data);
+	QString str2 = print_filter(str);
+
+	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
+		*text += QString().sprintf("<a href=\"s%p\">", sym);
+		*text += str2;
+		*text += "</a>";
+	} else
+		*text += str2;
+}
+
+QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+{
+	QPopupMenu* popup = Parent::createPopupMenu(pos);
+	QAction* action = new QAction("Show Debug Info", 0, popup);
+	  action->setToggleAction(TRUE);
+	  connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+	  connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+	  action->setOn(showDebug());
+	popup->insertSeparator();
+	action->addTo(popup);
+	return popup;
+}
+
+void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+	Parent::contentsContextMenuEvent(e);
+}
+
+ConfigSearchWindow::ConfigSearchWindow(QWidget* parent, const char *name)
+	: Parent(parent, name), result(NULL)
+{
+	setCaption("Search Config");
+
+	QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
+	QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+	layout2->addWidget(new QLabel("Find:", this));
+	editField = new QLineEdit(this);
+	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
+	layout2->addWidget(editField);
+	searchButton = new QPushButton("Search", this);
+	searchButton->setAutoDefault(FALSE);
+	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
+	layout2->addWidget(searchButton);
+	layout1->addLayout(layout2);
+
+	split = new QSplitter(this);
+	split->setOrientation(QSplitter::Vertical);
+	list = new ConfigView(split, name);
+	list->list->mode = listMode;
+	info = new ConfigInfoView(split, name);
+	connect(list->list, SIGNAL(menuChanged(struct menu *)),
+		info, SLOT(setInfo(struct menu *)));
+	layout1->addWidget(split);
+
+	if (name) {
+		int x, y, width, height;
+		bool ok;
+
+		configSettings->beginGroup(name);
+		width = configSettings->readNumEntry("/window width", parent->width() / 2);
+		height = configSettings->readNumEntry("/window height", parent->height() / 2);
+		resize(width, height);
+		x = configSettings->readNumEntry("/window x", 0, &ok);
+		if (ok)
+			y = configSettings->readNumEntry("/window y", 0, &ok);
+		if (ok)
+			move(x, y);
+		QValueList<int> sizes = configSettings->readSizes("/split", &ok);
+		if (ok)
+			split->setSizes(sizes);
+		configSettings->endGroup();
+		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+	}
+}
+
+void ConfigSearchWindow::saveSettings(void)
+{
+	if (name()) {
+		configSettings->beginGroup(name());
+		configSettings->writeEntry("/window x", pos().x());
+		configSettings->writeEntry("/window y", pos().y());
+		configSettings->writeEntry("/window width", size().width());
+		configSettings->writeEntry("/window height", size().height());
+		configSettings->writeSizes("/split", split->sizes());
+		configSettings->endGroup();
+	}
+}
+
+void ConfigSearchWindow::search(void)
+{
+	struct symbol **p;
+	struct property *prop;
+	ConfigItem *lastItem = NULL;
+
+	free(result);
+	list->list->clear();
+
+	result = sym_re_search(editField->text().latin1());
+	if (!result)
+		return;
+	for (p = result; *p; p++) {
+		for_all_prompts((*p), prop)
+			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+						  menu_is_visible(prop->menu));
+	}
 }
 
 /*
- * display a new help entry as soon as a new menu entry is selected
+ * Construct the complete config widget
  */
-void ConfigMainWindow::setHelp(QListViewItem* item)
+ConfigMainWindow::ConfigMainWindow(void)
 {
-	struct symbol* sym;
-	struct menu* menu = 0;
+	QMenuBar* menu;
+	bool ok;
+	int x, y, width, height;
 
-	configList->parent()->lineEdit->hide();
-	if (item)
-		menu = ((ConfigItem*)item)->menu;
-	if (!menu) {
-		helpText->setText(QString::null);
-		return;
-	}
+	QWidget *d = configApp->desktop();
 
-	QString head, debug, help;
-	menu = ((ConfigItem*)item)->menu;
-	sym = menu->sym;
-	if (sym) {
-		if (menu->prompt) {
-			head += "<big><b>";
-			head += print_filter(_(menu->prompt->text));
-			head += "</b></big>";
-			if (sym->name) {
-				head += " (";
-				head += print_filter(_(sym->name));
-				head += ")";
-			}
-		} else if (sym->name) {
-			head += "<big><b>";
-			head += print_filter(_(sym->name));
-			head += "</b></big>";
-		}
-		head += "<br><br>";
+	width = configSettings->readNumEntry("/window width", d->width() - 64);
+	height = configSettings->readNumEntry("/window height", d->height() - 64);
+	resize(width, height);
+	x = configSettings->readNumEntry("/window x", 0, &ok);
+	if (ok)
+		y = configSettings->readNumEntry("/window y", 0, &ok);
+	if (ok)
+		move(x, y);
 
-		if (showDebug) {
-			debug += "type: ";
-			debug += print_filter(sym_type_name(sym->type));
-			if (sym_is_choice(sym))
-				debug += " (choice)";
-			debug += "<br>";
-			if (sym->rev_dep.expr) {
-				debug += "reverse dep: ";
-				expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
-				debug += "<br>";
-			}
-			for (struct property *prop = sym->prop; prop; prop = prop->next) {
-				switch (prop->type) {
-				case P_PROMPT:
-				case P_MENU:
-					debug += "prompt: ";
-					debug += print_filter(_(prop->text));
-					debug += "<br>";
-					break;
-				case P_DEFAULT:
-					debug += "default: ";
-					expr_print(prop->expr, expr_print_help, &debug, E_NONE);
-					debug += "<br>";
-					break;
-				case P_CHOICE:
-					if (sym_is_choice(sym)) {
-						debug += "choice: ";
-						expr_print(prop->expr, expr_print_help, &debug, E_NONE);
-						debug += "<br>";
-					}
-					break;
-				case P_SELECT:
-					debug += "select: ";
-					expr_print(prop->expr, expr_print_help, &debug, E_NONE);
-					debug += "<br>";
-					break;
-				case P_RANGE:
-					debug += "range: ";
-					expr_print(prop->expr, expr_print_help, &debug, E_NONE);
-					debug += "<br>";
-					break;
-				default:
-					debug += "unknown property: ";
-					debug += prop_get_type_name(prop->type);
-					debug += "<br>";
-				}
-				if (prop->visible.expr) {
-					debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
-					expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
-					debug += "<br>";
-				}
-			}
-			debug += "<br>";
-		}
+	split1 = new QSplitter(this);
+	split1->setOrientation(QSplitter::Horizontal);
+	setCentralWidget(split1);
 
-		help = print_filter(_(sym->help));
-	} else if (menu->prompt) {
-		head += "<big><b>";
-		head += print_filter(_(menu->prompt->text));
-		head += "</b></big><br><br>";
-		if (showDebug) {
-			if (menu->prompt->visible.expr) {
-				debug += "&nbsp;&nbsp;dep: ";
-				expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
-				debug += "<br><br>";
-			}
-		}
-	}
-	if (showDebug)
-		debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
-	helpText->setText(head + debug + help);
+	menuView = new ConfigView(split1, "menu");
+	menuList = menuView->list;
+
+	split2 = new QSplitter(split1);
+	split2->setOrientation(QSplitter::Vertical);
+
+	// create config tree
+	configView = new ConfigView(split2, "config");
+	configList = configView->list;
+
+	helpText = new ConfigInfoView(split2, "help");
+	helpText->setTextFormat(Qt::RichText);
+
+	setTabOrder(configList, helpText);
+	configList->setFocus();
+
+	menu = menuBar();
+	toolBar = new QToolBar("Tools", this);
+
+	backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
+	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+	  backAction->setEnabled(FALSE);
+	QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
+	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
+	QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
+	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+	QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
+	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+	QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
+	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+	QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this);
+	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
+	QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
+	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+	QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
+	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+	QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
+	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+	QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
+	  showNameAction->setToggleAction(TRUE);
+	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
+	  showNameAction->setOn(configView->showName());
+	QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
+	  showRangeAction->setToggleAction(TRUE);
+	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
+	  showRangeAction->setOn(configList->showRange);
+	QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
+	  showDataAction->setToggleAction(TRUE);
+	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
+	  showDataAction->setOn(configList->showData);
+	QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
+	  showAllAction->setToggleAction(TRUE);
+	  connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
+	  connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
+	  showAllAction->setOn(configList->showAll);
+	QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
+	  showDebugAction->setToggleAction(TRUE);
+	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
+	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
+	  showDebugAction->setOn(helpText->showDebug());
+
+	QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
+	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+	QAction *showAboutAction = new QAction(NULL, "About", 0, this);
+	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+	// init tool bar
+	backAction->addTo(toolBar);
+	toolBar->addSeparator();
+	loadAction->addTo(toolBar);
+	saveAction->addTo(toolBar);
+	toolBar->addSeparator();
+	singleViewAction->addTo(toolBar);
+	splitViewAction->addTo(toolBar);
+	fullViewAction->addTo(toolBar);
+
+	// create config menu
+	QPopupMenu* config = new QPopupMenu(this);
+	menu->insertItem("&File", config);
+	loadAction->addTo(config);
+	saveAction->addTo(config);
+	saveAsAction->addTo(config);
+	config->insertSeparator();
+	searchAction->addTo(config);
+	config->insertSeparator();
+	quitAction->addTo(config);
+
+	// create options menu
+	QPopupMenu* optionMenu = new QPopupMenu(this);
+	menu->insertItem("&Option", optionMenu);
+	showNameAction->addTo(optionMenu);
+	showRangeAction->addTo(optionMenu);
+	showDataAction->addTo(optionMenu);
+	optionMenu->insertSeparator();
+	showAllAction->addTo(optionMenu);
+	showDebugAction->addTo(optionMenu);
+
+	// create help menu
+	QPopupMenu* helpMenu = new QPopupMenu(this);
+	menu->insertSeparator();
+	menu->insertItem("&Help", helpMenu);
+	showIntroAction->addTo(helpMenu);
+	showAboutAction->addTo(helpMenu);
+
+	connect(configList, SIGNAL(menuChanged(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(configList, SIGNAL(menuSelected(struct menu *)),
+		SLOT(changeMenu(struct menu *)));
+	connect(configList, SIGNAL(parentSelected()),
+		SLOT(goBack()));
+	connect(menuList, SIGNAL(menuChanged(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(menuSelected(struct menu *)),
+		SLOT(changeMenu(struct menu *)));
+
+	connect(configList, SIGNAL(gotFocus(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(gotFocus(struct menu *)),
+		helpText, SLOT(setInfo(struct menu *)));
+	connect(menuList, SIGNAL(gotFocus(struct menu *)),
+		SLOT(listFocusChanged(void)));
+	connect(helpText, SIGNAL(menuSelected(struct menu *)),
+		SLOT(setMenuLink(struct menu *)));
+
+	QString listMode = configSettings->readEntry("/listMode", "symbol");
+	if (listMode == "single")
+		showSingleView();
+	else if (listMode == "full")
+		showFullView();
+	else /*if (listMode == "split")*/
+		showSplitView();
+
+	// UI setup done, restore splitter positions
+	QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+	if (ok)
+		split1->setSizes(sizes);
+
+	sizes = configSettings->readSizes("/split2", &ok);
+	if (ok)
+		split2->setSizes(sizes);
 }
 
 void ConfigMainWindow::loadConfig(void)
@@ -1147,21 +1450,73 @@
 		QMessageBox::information(this, "qconf", "Unable to save configuration!");
 }
 
+void ConfigMainWindow::searchConfig(void)
+{
+	if (!searchWindow)
+		searchWindow = new ConfigSearchWindow(this, "search");
+	searchWindow->show();
+}
+
 void ConfigMainWindow::changeMenu(struct menu *menu)
 {
 	configList->setRootMenu(menu);
 	backAction->setEnabled(TRUE);
 }
 
+void ConfigMainWindow::setMenuLink(struct menu *menu)
+{
+	struct menu *parent;
+	ConfigList* list = NULL;
+	ConfigItem* item;
+
+	if (!menu_is_visible(menu) && !configView->showAll())
+		return;
+
+	switch (configList->mode) {
+	case singleMode:
+		list = configList;
+		parent = menu_get_parent_menu(menu);
+		if (!parent)
+			return;
+		list->setRootMenu(parent);
+		break;
+	case symbolMode:
+		if (menu->flags & MENU_ROOT) {
+			configList->setRootMenu(menu);
+			configList->clearSelection();
+			list = menuList;
+		} else {
+			list = configList;
+			parent = menu_get_parent_menu(menu->parent);
+			if (!parent)
+				return;
+			item = menuList->findConfigItem(parent);
+			if (item) {
+				menuList->setSelected(item, TRUE);
+				menuList->ensureItemVisible(item);
+			}
+			list->setRootMenu(parent);
+		}
+		break;
+	case fullMode:
+		list = configList;
+		break;
+	}
+
+	if (list) {
+		item = list->findConfigItem(menu);
+		if (item) {
+			list->setSelected(item, TRUE);
+			list->ensureItemVisible(item);
+			list->setFocus();
+		}
+	}
+}
+
 void ConfigMainWindow::listFocusChanged(void)
 {
-	if (menuList->hasFocus()) {
-		if (menuList->mode == menuMode)
-			configList->clearSelection();
-		setHelp(menuList->selectedItem());
-	} else if (configList->hasFocus()) {
-		setHelp(configList->selectedItem());
-	}
+	if (menuList->mode == menuMode)
+		configList->clearSelection();
 }
 
 void ConfigMainWindow::goBack(void)
@@ -1223,53 +1578,6 @@
 	configList->setFocus();
 }
 
-void ConfigMainWindow::setShowAll(bool b)
-{
-	if (configList->showAll == b)
-		return;
-	configList->showAll = b;
-	configList->updateListAll();
-	menuList->showAll = b;
-	menuList->updateListAll();
-}
-
-void ConfigMainWindow::setShowDebug(bool b)
-{
-	if (showDebug == b)
-		return;
-	showDebug = b;
-}
-
-void ConfigMainWindow::setShowName(bool b)
-{
-	if (configList->showName == b)
-		return;
-	configList->showName = b;
-	configList->reinit();
-	menuList->showName = b;
-	menuList->reinit();
-}
-
-void ConfigMainWindow::setShowRange(bool b)
-{
-	if (configList->showRange == b)
-		return;
-	configList->showRange = b;
-	configList->reinit();
-	menuList->showRange = b;
-	menuList->reinit();
-}
-
-void ConfigMainWindow::setShowData(bool b)
-{
-	if (configList->showData == b)
-		return;
-	configList->showData = b;
-	configList->reinit();
-	menuList->showData = b;
-	menuList->reinit();
-}
-
 /*
  * ask for saving configuration before quitting
  * TODO ask only when something changed
@@ -1324,17 +1632,10 @@
 
 void ConfigMainWindow::saveSettings(void)
 {
-#if QT_VERSION >= 300
-	ConfigSettings *configSettings = new ConfigSettings;
-	configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
-	configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
-	configSettings->writeEntry("/kconfig/qconf/window width", size().width());
-	configSettings->writeEntry("/kconfig/qconf/window height", size().height());
-	configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
-	configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
-	configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
-	configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
-	configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
+	configSettings->writeEntry("/window x", pos().x());
+	configSettings->writeEntry("/window y", pos().y());
+	configSettings->writeEntry("/window width", size().width());
+	configSettings->writeEntry("/window height", size().height());
 
 	QString entry;
 	switch(configList->mode) {
@@ -1350,13 +1651,10 @@
 		entry = "full";
 		break;
 	}
-	configSettings->writeEntry("/kconfig/qconf/listMode", entry);
+	configSettings->writeEntry("/listMode", entry);
 
-	configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
-	configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
-
-	delete configSettings;
-#endif
+	configSettings->writeSizes("/split1", split1->sizes());
+	configSettings->writeSizes("/split2", split2->sizes());
 }
 
 void fixup_rootmenu(struct menu *menu)
@@ -1414,13 +1712,19 @@
 	conf_read(NULL);
 	//zconfdump(stdout);
 
+	configSettings = new ConfigSettings();
+	configSettings->beginGroup("/kconfig/qconf");
 	v = new ConfigMainWindow();
 
 	//zconfdump(stdout);
-	v->show();
+	configApp->setMainWidget(v);
 	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
 	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+	v->show();
 	configApp->exec();
 
+	configSettings->endGroup();
+	delete configSettings;
+
 	return 0;
 }
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index e52f3e9..6a9e3b1 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -7,9 +7,25 @@
 #if QT_VERSION >= 300
 #include <qsettings.h>
 #else
-class QSettings { };
+class QSettings {
+public:
+	void beginGroup(const QString& group) { }
+	void endGroup(void) { }
+	bool readBoolEntry(const QString& key, bool def = FALSE, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return def; }
+	int readNumEntry(const QString& key, int def = 0, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return def; }
+	QString readEntry(const QString& key, const QString& def = QString::null, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return def; }
+	QStringList readListEntry(const QString& key, bool* ok = 0) const
+	{ if (ok) *ok = FALSE; return QStringList(); }
+	template <class t>
+	bool writeEntry(const QString& key, t value)
+	{ return TRUE; }
+};
 #endif
 
+class ConfigView;
 class ConfigList;
 class ConfigItem;
 class ConfigLineEdit;
@@ -18,64 +34,38 @@
 
 class ConfigSettings : public QSettings {
 public:
-	ConfigSettings();
-
-#if QT_VERSION >= 300
-	void readListSettings();
 	QValueList<int> readSizes(const QString& key, bool *ok);
 	bool writeSizes(const QString& key, const QValueList<int>& value);
-#endif
-
-	bool showAll;
-	bool showName;
-	bool showRange;
-	bool showData;
-};
-
-class ConfigView : public QVBox {
-	Q_OBJECT
-	typedef class QVBox Parent;
-public:
-	ConfigView(QWidget* parent, ConfigMainWindow* cview, ConfigSettings* configSettings);
-	~ConfigView(void);
-	static void updateList(ConfigItem* item);
-	static void updateListAll(void);
-
-public:
-	ConfigList* list;
-	ConfigLineEdit* lineEdit;
-
-	static ConfigView* viewList;
-	ConfigView* nextView;
 };
 
 enum colIdx {
 	promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
 };
 enum listMode {
-	singleMode, menuMode, symbolMode, fullMode
+	singleMode, menuMode, symbolMode, fullMode, listMode
 };
 
 class ConfigList : public QListView {
 	Q_OBJECT
 	typedef class QListView Parent;
 public:
-	ConfigList(ConfigView* p, ConfigMainWindow* cview, ConfigSettings *configSettings);
+	ConfigList(ConfigView* p, const char *name = 0);
 	void reinit(void);
 	ConfigView* parent(void) const
 	{
 		return (ConfigView*)Parent::parent();
 	}
+	ConfigItem* findConfigItem(struct menu *);
 
 protected:
-	ConfigMainWindow* cview;
-
 	void keyPressEvent(QKeyEvent *e);
 	void contentsMousePressEvent(QMouseEvent *e);
 	void contentsMouseReleaseEvent(QMouseEvent *e);
 	void contentsMouseMoveEvent(QMouseEvent *e);
 	void contentsMouseDoubleClickEvent(QMouseEvent *e);
 	void focusInEvent(QFocusEvent *e);
+	void contextMenuEvent(QContextMenuEvent *e);
+
 public slots:
 	void setRootMenu(struct menu *menu);
 
@@ -83,10 +73,12 @@
 	void setValue(ConfigItem* item, tristate val);
 	void changeValue(ConfigItem* item);
 	void updateSelection(void);
+	void saveSettings(void);
 signals:
+	void menuChanged(struct menu *menu);
 	void menuSelected(struct menu *menu);
 	void parentSelected(void);
-	void gotFocus(void);
+	void gotFocus(struct menu *);
 
 public:
 	void updateListAll(void)
@@ -137,6 +129,7 @@
 	struct menu *rootEntry;
 	QColorGroup disabledColorGroup;
 	QColorGroup inactivedColorGroup;
+	QPopupMenu* headerPopup;
 
 private:
 	int colMap[colNr];
@@ -208,9 +201,7 @@
 	Q_OBJECT
 	typedef class QLineEdit Parent;
 public:
-	ConfigLineEdit(ConfigView* parent)
-	: Parent(parent)
-	{ }
+	ConfigLineEdit(ConfigView* parent);
 	ConfigView* parent(void) const
 	{
 		return (ConfigView*)Parent::parent();
@@ -222,26 +213,104 @@
 	ConfigItem *item;
 };
 
+class ConfigView : public QVBox {
+	Q_OBJECT
+	typedef class QVBox Parent;
+public:
+	ConfigView(QWidget* parent, const char *name = 0);
+	~ConfigView(void);
+	static void updateList(ConfigItem* item);
+	static void updateListAll(void);
+
+	bool showAll(void) const { return list->showAll; }
+	bool showName(void) const { return list->showName; }
+	bool showRange(void) const { return list->showRange; }
+	bool showData(void) const { return list->showData; }
+public slots:
+	void setShowAll(bool);
+	void setShowName(bool);
+	void setShowRange(bool);
+	void setShowData(bool);
+signals:
+	void showAllChanged(bool);
+	void showNameChanged(bool);
+	void showRangeChanged(bool);
+	void showDataChanged(bool);
+public:
+	ConfigList* list;
+	ConfigLineEdit* lineEdit;
+
+	static ConfigView* viewList;
+	ConfigView* nextView;
+};
+
+class ConfigInfoView : public QTextBrowser {
+	Q_OBJECT
+	typedef class QTextBrowser Parent;
+public:
+	ConfigInfoView(QWidget* parent, const char *name = 0);
+	bool showDebug(void) const { return _showDebug; }
+
+public slots:
+	void setInfo(struct menu *menu);
+	void saveSettings(void);
+	void setSource(const QString& name);
+	void setShowDebug(bool);
+
+signals:
+	void showDebugChanged(bool);
+	void menuSelected(struct menu *);
+
+protected:
+	void symbolInfo(void);
+	void menuInfo(void);
+	QString debug_info(struct symbol *sym);
+	static QString print_filter(const QString &str);
+	static void expr_print_help(void *data, struct symbol *sym, const char *str);
+	QPopupMenu* createPopupMenu(const QPoint& pos);
+	void contentsContextMenuEvent(QContextMenuEvent *e);
+
+	struct symbol *sym;
+	struct menu *menu;
+	bool _showDebug;
+};
+
+class ConfigSearchWindow : public QDialog {
+	Q_OBJECT
+	typedef class QDialog Parent;
+public:
+	ConfigSearchWindow(QWidget* parent, const char *name = 0);
+
+public slots:
+	void saveSettings(void);
+	void search(void);
+
+protected:
+	QLineEdit* editField;
+	QPushButton* searchButton;
+	QSplitter* split;
+	ConfigView* list;
+	ConfigInfoView* info;
+
+	struct symbol **result;
+};
+
 class ConfigMainWindow : public QMainWindow {
 	Q_OBJECT
 public:
 	ConfigMainWindow(void);
 public slots:
-	void setHelp(QListViewItem* item);
 	void changeMenu(struct menu *);
+	void setMenuLink(struct menu *);
 	void listFocusChanged(void);
 	void goBack(void);
 	void loadConfig(void);
 	void saveConfig(void);
 	void saveConfigAs(void);
+	void searchConfig(void);
 	void showSingleView(void);
 	void showSplitView(void);
 	void showFullView(void);
-	void setShowAll(bool);
-	void setShowDebug(bool);
-	void setShowRange(bool);
-	void setShowName(bool);
-	void setShowData(bool);
 	void showIntro(void);
 	void showAbout(void);
 	void saveSettings(void);
@@ -249,15 +318,14 @@
 protected:
 	void closeEvent(QCloseEvent *e);
 
+	ConfigSearchWindow *searchWindow;
 	ConfigView *menuView;
 	ConfigList *menuList;
 	ConfigView *configView;
 	ConfigList *configList;
-	QTextView *helpText;
+	ConfigInfoView *helpText;
 	QToolBar *toolBar;
 	QAction *backAction;
 	QSplitter* split1;
 	QSplitter* split2;
-
-	bool showDebug;
 };
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 3d7877a..ee225ce 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -15,15 +15,15 @@
 struct symbol symbol_yes = {
 	.name = "y",
 	.curr = { "y", yes },
-	.flags = SYMBOL_YES|SYMBOL_VALID,
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
 }, symbol_mod = {
 	.name = "m",
 	.curr = { "m", mod },
-	.flags = SYMBOL_MOD|SYMBOL_VALID,
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
 }, symbol_no = {
 	.name = "n",
 	.curr = { "n", no },
-	.flags = SYMBOL_NO|SYMBOL_VALID,
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
 }, symbol_empty = {
 	.name = "",
 	.curr = { "", no },
@@ -31,6 +31,7 @@
 };
 
 int sym_change_count;
+struct symbol *sym_defconfig_list;
 struct symbol *modules_sym;
 tristate modules_val;
 
@@ -227,7 +228,7 @@
 	struct expr *e;
 
 	/* is the user choice visible? */
-	def_sym = sym->user.val;
+	def_sym = sym->def[S_DEF_USER].val;
 	if (def_sym) {
 		sym_calc_visibility(def_sym);
 		if (def_sym->visible != no)
@@ -306,7 +307,7 @@
 		} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
 			sym->flags |= SYMBOL_WRITE;
 			if (sym_has_value(sym))
-				newval.tri = sym->user.tri;
+				newval.tri = sym->def[S_DEF_USER].tri;
 			else if (!sym_is_choice(sym)) {
 				prop = sym_get_default_prop(sym);
 				if (prop)
@@ -329,7 +330,7 @@
 		if (sym->visible != no) {
 			sym->flags |= SYMBOL_WRITE;
 			if (sym_has_value(sym)) {
-				newval.val = sym->user.val;
+				newval.val = sym->def[S_DEF_USER].val;
 				break;
 			}
 		}
@@ -352,10 +353,13 @@
 		sym->curr.val = sym_calc_choice(sym);
 	sym_validate_range(sym);
 
-	if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
+	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
 		sym_set_changed(sym);
-	if (modules_sym == sym)
-		modules_val = modules_sym->curr.tri;
+		if (modules_sym == sym) {
+			sym_set_all_changed();
+			modules_val = modules_sym->curr.tri;
+		}
+	}
 
 	if (sym_is_choice(sym)) {
 		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
@@ -426,8 +430,8 @@
 	if (oldval != val && !sym_tristate_within_range(sym, val))
 		return false;
 
-	if (sym->flags & SYMBOL_NEW) {
-		sym->flags &= ~SYMBOL_NEW;
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
 		sym_set_changed(sym);
 	}
 	/*
@@ -439,21 +443,18 @@
 		struct property *prop;
 		struct expr *e;
 
-		cs->user.val = sym;
-		cs->flags &= ~SYMBOL_NEW;
+		cs->def[S_DEF_USER].val = sym;
+		cs->flags |= SYMBOL_DEF_USER;
 		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;
+				e->right.sym->flags |= SYMBOL_DEF_USER;
 		}
 	}
 
-	sym->user.tri = val;
-	if (oldval != val) {
+	sym->def[S_DEF_USER].tri = val;
+	if (oldval != val)
 		sym_clear_all_valid();
-		if (sym == modules_sym)
-			sym_set_all_changed();
-	}
 
 	return true;
 }
@@ -591,20 +592,20 @@
 	if (!sym_string_within_range(sym, newval))
 		return false;
 
-	if (sym->flags & SYMBOL_NEW) {
-		sym->flags &= ~SYMBOL_NEW;
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
 		sym_set_changed(sym);
 	}
 
-	oldval = sym->user.val;
+	oldval = sym->def[S_DEF_USER].val;
 	size = strlen(newval) + 1;
 	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 		size += 2;
-		sym->user.val = val = malloc(size);
+		sym->def[S_DEF_USER].val = val = malloc(size);
 		*val++ = '0';
 		*val++ = 'x';
 	} else if (!oldval || strcmp(oldval, newval))
-		sym->user.val = val = malloc(size);
+		sym->def[S_DEF_USER].val = val = malloc(size);
 	else
 		return true;
 
@@ -679,7 +680,6 @@
 	memset(symbol, 0, sizeof(*symbol));
 	symbol->name = new_name;
 	symbol->type = S_UNKNOWN;
-	symbol->flags = SYMBOL_NEW;
 	if (isconst)
 		symbol->flags |= SYMBOL_CONST;
 
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
index 656d2c8..e3f28b9 100644
--- a/scripts/kconfig/util.c
+++ b/scripts/kconfig/util.c
@@ -44,7 +44,9 @@
 		else
 			fprintf(out, "\t%s\n", file->name);
 	}
-	fprintf(out, "\n.config include/linux/autoconf.h: $(deps_config)\n\n$(deps_config):\n");
+	fprintf(out, "\ninclude/config/auto.conf: \\\n"
+		     "\t$(deps_config)\n\n"
+		     "$(deps_config): ;\n");
 	fclose(out);
 	rename("..config.tmp", name);
 	return 0;
diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf
index b032206..9b44c80 100644
--- a/scripts/kconfig/zconf.gperf
+++ b/scripts/kconfig/zconf.gperf
@@ -39,5 +39,8 @@
 select,		T_SELECT,	TF_COMMAND
 enable,		T_SELECT,	TF_COMMAND
 range,		T_RANGE,	TF_COMMAND
+option,		T_OPTION,	TF_COMMAND
 on,		T_ON,		TF_PARAM
+modules,	T_OPT_MODULES,	TF_OPTION
+defconfig_list,	T_OPT_DEFCONFIG_LIST,TF_OPTION
 %%
diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped
index 345f0fc..47c8b5b 100644
--- a/scripts/kconfig/zconf.hash.c_shipped
+++ b/scripts/kconfig/zconf.hash.c_shipped
@@ -53,10 +53,10 @@
       47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
       47, 47, 47, 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, 25, 30, 15,
+       0, 15,  0, 47,  5, 15, 47, 47, 30, 20,
+       5,  0, 25, 15,  0,  0, 10, 35, 47, 47,
+       5, 47, 47, 47, 47, 47, 47, 47, 47, 47,
       47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
       47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
       47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
@@ -88,69 +88,75 @@
 
 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_str2[sizeof("on")];
+    char kconf_id_strings_str6[sizeof("string")];
+    char kconf_id_strings_str7[sizeof("default")];
+    char kconf_id_strings_str8[sizeof("def_bool")];
     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_str11[sizeof("def_boolean")];
+    char kconf_id_strings_str12[sizeof("def_tristate")];
+    char kconf_id_strings_str13[sizeof("hex")];
+    char kconf_id_strings_str14[sizeof("defconfig_list")];
+    char kconf_id_strings_str16[sizeof("option")];
+    char kconf_id_strings_str17[sizeof("if")];
+    char kconf_id_strings_str18[sizeof("optional")];
+    char kconf_id_strings_str20[sizeof("endif")];
+    char kconf_id_strings_str21[sizeof("choice")];
+    char kconf_id_strings_str22[sizeof("endmenu")];
+    char kconf_id_strings_str23[sizeof("requires")];
+    char kconf_id_strings_str24[sizeof("endchoice")];
+    char kconf_id_strings_str26[sizeof("config")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("int")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str31[sizeof("prompt")];
+    char kconf_id_strings_str32[sizeof("depends")];
+    char kconf_id_strings_str33[sizeof("tristate")];
     char kconf_id_strings_str34[sizeof("bool")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("select")];
     char kconf_id_strings_str37[sizeof("boolean")];
-    char kconf_id_strings_str41[sizeof("choice")];
-    char kconf_id_strings_str46[sizeof("prompt")];
+    char kconf_id_strings_str39[sizeof("help")];
+    char kconf_id_strings_str41[sizeof("source")];
+    char kconf_id_strings_str42[sizeof("comment")];
+    char kconf_id_strings_str43[sizeof("mainmenu")];
+    char kconf_id_strings_str46[sizeof("enable")];
   };
 static struct kconf_id_strings_t kconf_id_strings_contents =
   {
-    "if",
-    "int",
-    "help",
-    "endif",
-    "select",
-    "endmenu",
-    "tristate",
-    "endchoice",
-    "range",
+    "on",
     "string",
     "default",
     "def_bool",
-    "menu",
+    "range",
     "def_boolean",
     "def_tristate",
-    "mainmenu",
-    "menuconfig",
-    "config",
-    "on",
     "hex",
-    "source",
-    "depends",
+    "defconfig_list",
+    "option",
+    "if",
     "optional",
-    "enable",
-    "comment",
-    "requires",
-    "bool",
-    "boolean",
+    "endif",
     "choice",
-    "prompt"
+    "endmenu",
+    "requires",
+    "endchoice",
+    "config",
+    "modules",
+    "int",
+    "menu",
+    "prompt",
+    "depends",
+    "tristate",
+    "bool",
+    "menuconfig",
+    "select",
+    "boolean",
+    "help",
+    "source",
+    "comment",
+    "mainmenu",
+    "enable"
   };
 #define kconf_id_strings ((const char *) &kconf_id_strings_contents)
 #ifdef __GNUC__
@@ -161,9 +167,9 @@
 {
   enum
     {
-      TOTAL_KEYWORDS = 30,
+      TOTAL_KEYWORDS = 33,
       MIN_WORD_LENGTH = 2,
-      MAX_WORD_LENGTH = 12,
+      MAX_WORD_LENGTH = 14,
       MIN_HASH_VALUE = 2,
       MAX_HASH_VALUE = 46
     };
@@ -171,43 +177,48 @@
   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},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
       {-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}
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {-1},
+      {(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_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,		T_TYPE,		TF_COMMAND, S_HEX},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_OPTION,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_OPTIONAL,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_CHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,	T_ENDMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,	T_REQUIRES,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str24,	T_ENDCHOICE,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,		T_TYPE,		TF_COMMAND, S_INT},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_DEPENDS,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39,		T_HELP,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_SOURCE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_COMMENT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43,	T_MAINMENU,	TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,		T_SELECT,	TF_COMMAND}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index ea7755d..2fb0a4f 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 2.0.  */
+/* A Bison parser, made by GNU Bison 2.1.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 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
@@ -15,8 +15,8 @@
 
    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.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, 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.
@@ -36,6 +36,9 @@
 /* Identify Bison output.  */
 #define YYBISON 1
 
+/* Bison version.  */
+#define YYBISON_VERSION "2.1"
+
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
 
@@ -82,19 +85,21 @@
      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
+     T_OPTION = 279,
+     T_ON = 280,
+     T_WORD = 281,
+     T_WORD_QUOTE = 282,
+     T_UNEQUAL = 283,
+     T_CLOSE_PAREN = 284,
+     T_OPEN_PAREN = 285,
+     T_EOL = 286,
+     T_OR = 287,
+     T_AND = 288,
+     T_EQUAL = 289,
+     T_NOT = 290
    };
 #endif
+/* Tokens.  */
 #define T_MAINMENU 258
 #define T_MENU 259
 #define T_ENDMENU 260
@@ -116,17 +121,18 @@
 #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
+#define T_OPTION 279
+#define T_ON 280
+#define T_WORD 281
+#define T_WORD_QUOTE 282
+#define T_UNEQUAL 283
+#define T_CLOSE_PAREN 284
+#define T_OPEN_PAREN 285
+#define T_EOL 286
+#define T_OR 287
+#define T_AND 288
+#define T_EQUAL 289
+#define T_NOT 290
 
 
 
@@ -187,6 +193,11 @@
 # define YYERROR_VERBOSE 0
 #endif
 
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
 
 typedef union YYSTYPE {
@@ -197,7 +208,7 @@
 	struct menu *menu;
 	struct kconf_id *id;
 } YYSTYPE;
-/* Line 190 of yacc.c.  */
+/* Line 196 of yacc.c.  */
 
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -209,18 +220,37 @@
 /* Copy the second part of user declarations.  */
 
 
-/* Line 213 of yacc.c.  */
+/* Line 219 of yacc.c.  */
 
 
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
 #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.  */
 
 # ifdef YYSTACK_USE_ALLOCA
@@ -229,6 +259,10 @@
 #    define YYSTACK_ALLOC __builtin_alloca
 #   else
 #    define YYSTACK_ALLOC alloca
+#    if defined (__STDC__) || defined (__cplusplus)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     define YYINCLUDED_STDLIB_H
+#    endif
 #   endif
 #  endif
 # endif
@@ -236,13 +270,39 @@
 # ifdef YYSTACK_ALLOC
    /* Pacify GCC's `empty if-body' warning. */
 #  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-# else
-#  if defined (__STDC__) || defined (__cplusplus)
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   define YYSIZE_T size_t
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
 #  endif
+# else
 #  define YYSTACK_ALLOC YYMALLOC
 #  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+#  endif
+#  ifdef __cplusplus
+extern "C" {
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+	&& (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+	&& (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifdef __cplusplus
+}
+#  endif
 # endif
 #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
 
@@ -277,7 +337,7 @@
 #   define YYCOPY(To, From, Count)		\
       do					\
 	{					\
-	  register YYSIZE_T yyi;		\
+	  YYSIZE_T yyi;				\
 	  for (yyi = 0; yyi < (Count); yyi++)	\
 	    (To)[yyi] = (From)[yyi];		\
 	}					\
@@ -312,22 +372,22 @@
 /* YYFINAL -- State number of the termination state. */
 #define YYFINAL  3
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   264
+#define YYLAST   275
 
 /* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS  35
+#define YYNTOKENS  36
 /* YYNNTS -- Number of nonterminals. */
-#define YYNNTS  42
+#define YYNNTS  45
 /* YYNRULES -- Number of rules. */
-#define YYNRULES  104
+#define YYNRULES  110
 /* YYNRULES -- Number of states. */
-#define YYNSTATES  175
+#define YYNSTATES  183
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   289
+#define YYMAXUTOK   290
 
-#define YYTRANSLATE(YYX) 						\
+#define YYTRANSLATE(YYX)						\
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
 /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
@@ -361,7 +421,8 @@
        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
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35
 };
 
 #if YYDEBUG
@@ -372,72 +433,75 @@
        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
+      81,    84,    85,    88,    91,    94,    97,   100,   103,   107,
+     112,   117,   122,   128,   132,   133,   137,   138,   141,   144,
+     147,   149,   153,   154,   157,   160,   163,   166,   169,   174,
+     178,   181,   186,   187,   190,   194,   196,   200,   201,   204,
+     207,   210,   214,   217,   219,   223,   224,   227,   230,   233,
+     237,   241,   244,   247,   250,   251,   254,   257,   260,   265,
+     269,   273,   274,   277,   279,   281,   284,   287,   290,   292,
+     295,   296,   299,   301,   305,   309,   313,   316,   320,   324,
+     326
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS. */
 static const yysigned_char yyrhs[] =
 {
-      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,
+      37,     0,    -1,    38,    -1,    -1,    38,    40,    -1,    38,
+      54,    -1,    38,    65,    -1,    38,     3,    75,    77,    -1,
+      38,    76,    -1,    38,    26,     1,    31,    -1,    38,    39,
+       1,    31,    -1,    38,     1,    31,    -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
+      -1,    31,    -1,    60,    -1,    69,    -1,    43,    -1,    45,
+      -1,    67,    -1,    26,     1,    31,    -1,     1,    31,    -1,
+      10,    26,    31,    -1,    42,    46,    -1,    11,    26,    31,
+      -1,    44,    46,    -1,    -1,    46,    47,    -1,    46,    48,
+      -1,    46,    73,    -1,    46,    71,    -1,    46,    41,    -1,
+      46,    31,    -1,    20,    74,    31,    -1,    19,    75,    78,
+      31,    -1,    21,    79,    78,    31,    -1,    22,    26,    78,
+      31,    -1,    23,    80,    80,    78,    31,    -1,    24,    49,
+      31,    -1,    -1,    49,    26,    50,    -1,    -1,    34,    75,
+      -1,     7,    31,    -1,    51,    55,    -1,    76,    -1,    52,
+      57,    53,    -1,    -1,    55,    56,    -1,    55,    73,    -1,
+      55,    71,    -1,    55,    31,    -1,    55,    41,    -1,    19,
+      75,    78,    31,    -1,    20,    74,    31,    -1,    18,    31,
+      -1,    21,    26,    78,    31,    -1,    -1,    57,    40,    -1,
+      14,    79,    77,    -1,    76,    -1,    58,    61,    59,    -1,
+      -1,    61,    40,    -1,    61,    65,    -1,    61,    54,    -1,
+       4,    75,    31,    -1,    62,    72,    -1,    76,    -1,    63,
+      66,    64,    -1,    -1,    66,    40,    -1,    66,    65,    -1,
+      66,    54,    -1,     6,    75,    31,    -1,     9,    75,    31,
+      -1,    68,    72,    -1,    12,    31,    -1,    70,    13,    -1,
+      -1,    72,    73,    -1,    72,    31,    -1,    72,    41,    -1,
+      16,    25,    79,    31,    -1,    16,    79,    31,    -1,    17,
+      79,    31,    -1,    -1,    75,    78,    -1,    26,    -1,    27,
+      -1,     5,    31,    -1,     8,    31,    -1,    15,    31,    -1,
+      31,    -1,    77,    31,    -1,    -1,    14,    79,    -1,    80,
+      -1,    80,    34,    80,    -1,    80,    28,    80,    -1,    30,
+      79,    29,    -1,    35,    79,    -1,    79,    32,    79,    -1,
+      79,    33,    79,    -1,    26,    -1,    27,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const unsigned short int yyrline[] =
 {
-       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
+       0,   105,   105,   107,   109,   110,   111,   112,   113,   114,
+     115,   119,   123,   123,   123,   123,   123,   123,   123,   127,
+     128,   129,   130,   131,   132,   136,   137,   143,   151,   157,
+     165,   175,   177,   178,   179,   180,   181,   182,   185,   193,
+     199,   209,   215,   221,   224,   226,   237,   238,   243,   252,
+     257,   265,   268,   270,   271,   272,   273,   274,   277,   283,
+     294,   300,   310,   312,   317,   325,   333,   336,   338,   339,
+     340,   345,   352,   357,   365,   368,   370,   371,   372,   375,
+     383,   390,   397,   403,   410,   412,   413,   414,   417,   422,
+     427,   435,   437,   442,   443,   446,   447,   448,   452,   453,
+     456,   457,   460,   461,   462,   463,   464,   465,   466,   469,
+     470
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE
-/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals. */
 static const char *const yytname[] =
 {
@@ -445,17 +509,18 @@
   "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",
+  "T_SELECT", "T_RANGE", "T_OPTION", "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
+  "config_option", "symbol_option", "symbol_option_list",
+  "symbol_option_arg", "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
 
@@ -467,24 +532,25 @@
        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
+     285,   286,   287,   288,   289,   290
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const unsigned char yyr1[] =
 {
-       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
+       0,    36,    37,    38,    38,    38,    38,    38,    38,    38,
+      38,    38,    39,    39,    39,    39,    39,    39,    39,    40,
+      40,    40,    40,    40,    40,    41,    41,    42,    43,    44,
+      45,    46,    46,    46,    46,    46,    46,    46,    47,    47,
+      47,    47,    47,    48,    49,    49,    50,    50,    51,    52,
+      53,    54,    55,    55,    55,    55,    55,    55,    56,    56,
+      56,    56,    57,    57,    58,    59,    60,    61,    61,    61,
+      61,    62,    63,    64,    65,    66,    66,    66,    66,    67,
+      68,    69,    70,    71,    72,    72,    72,    72,    73,    73,
+      73,    74,    74,    75,    75,    76,    76,    76,    77,    77,
+      78,    78,    79,    79,    79,    79,    79,    79,    79,    80,
+      80
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -493,14 +559,15 @@
        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,     2,     0,     2,     1,     3,     3,     3,
-       2,     3,     3,     1,     1
+       2,     0,     2,     2,     2,     2,     2,     2,     3,     4,
+       4,     4,     5,     3,     0,     3,     0,     2,     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,     2,
+       0,     2,     1,     3,     3,     3,     2,     3,     3,     1,
+       1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -511,175 +578,164 @@
        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
+      23,    52,    62,     5,    67,    20,    84,    75,     6,    24,
+      84,    21,     8,    11,    93,    94,     0,     0,    95,     0,
+      48,    96,     0,     0,     0,   109,   110,     0,     0,     0,
+     102,    97,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    98,     7,    71,    79,    80,    27,    29,     0,
+     106,     0,     0,    64,     0,     0,     9,    10,     0,     0,
+       0,     0,     0,    91,     0,     0,     0,    44,     0,    37,
+      36,    32,    33,     0,    35,    34,     0,     0,    91,     0,
+      56,    57,    53,    55,    54,    63,    51,    50,    68,    70,
+      66,    69,    65,    86,    87,    85,    76,    78,    74,    77,
+      73,    99,   105,   107,   108,   104,   103,    26,    82,     0,
+       0,     0,   100,     0,   100,   100,   100,     0,     0,     0,
+      83,    60,   100,     0,   100,     0,    89,    90,     0,     0,
+      38,    92,     0,     0,   100,    46,    43,    25,     0,    59,
+       0,    88,   101,    39,    40,    41,     0,     0,    45,    58,
+      61,    42,    47
 };
 
 /* YYDEFGOTO[NTERM-NUM]. */
 static const short int yydefgoto[] =
 {
-      -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
+      -1,     1,     2,    25,    26,   100,    27,    28,    29,    30,
+      64,   101,   102,   148,   178,    31,    32,   116,    33,    66,
+     112,    67,    34,   120,    35,    68,    36,    37,   128,    38,
+      70,    39,    40,    41,   103,   104,    69,   105,   143,   144,
+      42,    73,   159,    59,    60
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -78
+#define YYPACT_NINF -135
 static const short int yypact[] =
 {
-     -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
+    -135,     2,   170,  -135,   -14,    56,    56,    -8,    56,    24,
+      67,    56,     7,    14,    62,    97,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,   156,  -135,   166,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,   138,   151,  -135,   152,
+    -135,  -135,   163,   167,   176,  -135,  -135,    62,    62,   185,
+     -19,  -135,   188,   190,    42,   103,   194,    85,    70,   222,
+      70,   132,  -135,   191,  -135,  -135,  -135,  -135,  -135,   127,
+    -135,    62,    62,   191,   104,   104,  -135,  -135,   193,   203,
+       9,    62,    56,    56,    62,   161,   104,  -135,   196,  -135,
+    -135,  -135,  -135,   233,  -135,  -135,   204,    56,    56,   221,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,   219,  -135,  -135,  -135,  -135,  -135,    62,
+     209,   212,   240,   224,   240,    -1,   240,   104,    41,   225,
+    -135,  -135,   240,   226,   240,   218,  -135,  -135,    62,   227,
+    -135,  -135,   228,   229,   240,   230,  -135,  -135,   231,  -135,
+     232,  -135,   112,  -135,  -135,  -135,   234,    56,  -135,  -135,
+    -135,  -135,  -135
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const short int yypgoto[] =
 {
-     -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
+    -135,  -135,  -135,  -135,    94,   -45,  -135,  -135,  -135,  -135,
+     237,  -135,  -135,  -135,  -135,  -135,  -135,  -135,   -54,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,     1,
+    -135,  -135,  -135,  -135,  -135,   195,   235,   -44,   159,    -5,
+      98,   210,  -134,   -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 -76
+#define YYTABLE_NINF -82
 static const short int yytable[] =
 {
-      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
+      46,    47,     3,    49,    79,    80,    52,   135,   136,    84,
+     161,   162,   163,   158,   119,    85,   127,    43,   168,   147,
+     170,   111,   114,    48,   124,   125,   124,   125,   133,   134,
+     176,    81,    82,    53,   139,    55,    56,   140,   141,    57,
+      54,   145,   -28,    88,    58,   -28,   -28,   -28,   -28,   -28,
+     -28,   -28,   -28,   -28,    89,    50,   -28,   -28,    90,    91,
+     -28,    92,    93,    94,    95,    96,    97,   165,    98,   121,
+     164,   129,   166,    99,     6,     7,     8,     9,    10,    11,
+      12,    13,    44,    45,    14,    15,   155,   142,    55,    56,
+       7,     8,    57,    10,    11,    12,    13,    58,    51,    14,
+      15,    24,   152,   -30,    88,   172,   -30,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,    89,    24,   -30,   -30,    90,
+      91,   -30,    92,    93,    94,    95,    96,    97,    61,    98,
+      55,    56,   -81,    88,    99,   -81,   -81,   -81,   -81,   -81,
+     -81,   -81,   -81,   -81,    81,    82,   -81,   -81,    90,    91,
+     -81,   -81,   -81,   -81,   -81,   -81,   132,    62,    98,    81,
+      82,   115,   118,   123,   126,   117,   122,    63,   130,    72,
+      -2,     4,   182,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    74,    75,    14,    15,    16,   146,    17,    18,
+      19,    20,    21,    22,    76,    88,    23,   149,    77,   -49,
+     -49,    24,   -49,   -49,   -49,   -49,    89,    78,   -49,   -49,
+      90,    91,   106,   107,   108,   109,    72,    81,    82,    86,
+      98,    87,   131,    88,   137,   110,   -72,   -72,   -72,   -72,
+     -72,   -72,   -72,   -72,   138,   151,   -72,   -72,    90,    91,
+     156,    81,    82,   157,    81,    82,   150,   154,    98,   171,
+      81,    82,    82,   123,   158,   160,   167,   169,   173,   174,
+     175,   113,   179,   180,   177,   181,    65,   153,     0,    83,
+       0,     0,     0,     0,     0,    71
 };
 
 static const short int yycheck[] =
 {
-       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
+       5,     6,     0,     8,    57,    58,    11,    84,    85,    28,
+     144,   145,   146,    14,    68,    34,    70,    31,   152,    96,
+     154,    66,    66,    31,    69,    69,    71,    71,    81,    82,
+     164,    32,    33,    26,    25,    26,    27,    90,    91,    30,
+      26,    94,     0,     1,    35,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    31,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    26,    26,    68,
+     147,    70,    31,    31,     4,     5,     6,     7,     8,     9,
+      10,    11,    26,    27,    14,    15,   139,    92,    26,    27,
+       5,     6,    30,     8,     9,    10,    11,    35,    31,    14,
+      15,    31,   107,     0,     1,   158,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    31,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    31,    26,
+      26,    27,     0,     1,    31,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    32,    33,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    29,     1,    26,    32,
+      33,    67,    68,    31,    70,    67,    68,     1,    70,    31,
+       0,     1,   177,     3,     4,     5,     6,     7,     8,     9,
+      10,    11,    31,    31,    14,    15,    16,    26,    18,    19,
+      20,    21,    22,    23,    31,     1,    26,     1,    31,     5,
+       6,    31,     8,     9,    10,    11,    12,    31,    14,    15,
+      16,    17,    18,    19,    20,    21,    31,    32,    33,    31,
+      26,    31,    31,     1,    31,    31,     4,     5,     6,     7,
+       8,     9,    10,    11,    31,    31,    14,    15,    16,    17,
+      31,    32,    33,    31,    32,    33,    13,    26,    26,    31,
+      32,    33,    33,    31,    14,    31,    31,    31,    31,    31,
+      31,    66,    31,    31,    34,    31,    29,   108,    -1,    59,
+      -1,    -1,    -1,    -1,    -1,    40
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const unsigned char yystos[] =
 {
-       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       0,    37,    38,     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
+      21,    22,    23,    26,    31,    39,    40,    42,    43,    44,
+      45,    51,    52,    54,    58,    60,    62,    63,    65,    67,
+      68,    69,    76,    31,    26,    27,    75,    75,    31,    75,
+      31,    31,    75,    26,    26,    26,    27,    30,    35,    79,
+      80,    31,     1,     1,    46,    46,    55,    57,    61,    72,
+      66,    72,    31,    77,    31,    31,    31,    31,    31,    79,
+      79,    32,    33,    77,    28,    34,    31,    31,     1,    12,
+      16,    17,    19,    20,    21,    22,    23,    24,    26,    31,
+      41,    47,    48,    70,    71,    73,    18,    19,    20,    21,
+      31,    41,    56,    71,    73,    40,    53,    76,    40,    54,
+      59,    65,    76,    31,    41,    73,    40,    54,    64,    65,
+      76,    31,    29,    79,    79,    80,    80,    31,    31,    25,
+      79,    79,    75,    74,    75,    79,    26,    80,    49,     1,
+      13,    31,    75,    74,    26,    79,    31,    31,    14,    78,
+      31,    78,    78,    78,    80,    26,    31,    31,    78,    31,
+      78,    31,    79,    31,    31,    31,    78,    34,    50,    31,
+      31,    31,    75
 };
 
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
 #define yyerrok		(yyerrstatus = 0)
 #define yyclearin	(yychar = YYEMPTY)
 #define YYEMPTY		(-2)
@@ -709,8 +765,8 @@
       goto yybackup;						\
     }								\
   else								\
-    { 								\
-      yyerror ("syntax error: cannot back up");\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
       YYERROR;							\
     }								\
 while (0)
@@ -789,7 +845,7 @@
   if (yydebug)							\
     {								\
       YYFPRINTF (stderr, "%s ", Title);				\
-      yysymprint (stderr, 					\
+      yysymprint (stderr,					\
                   Type, Value);	\
       YYFPRINTF (stderr, "\n");					\
     }								\
@@ -837,13 +893,13 @@
 #endif
 {
   int yyi;
-  unsigned int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
              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]]);
-  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+    YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
 }
 
 # define YY_REDUCE_PRINT(Rule)		\
@@ -872,7 +928,7 @@
    if the built-in stack extension method is used).
 
    Do not make this value too large; the results are undefined if
-   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
    evaluated with infinite-precision integer arithmetic.  */
 
 #ifndef YYMAXDEPTH
@@ -896,7 +952,7 @@
      const char *yystr;
 #   endif
 {
-  register const char *yys = yystr;
+  const char *yys = yystr;
 
   while (*yys++ != '\0')
     continue;
@@ -921,8 +977,8 @@
      const char *yysrc;
 #   endif
 {
-  register char *yyd = yydest;
-  register const char *yys = yysrc;
+  char *yyd = yydest;
+  const char *yys = yysrc;
 
   while ((*yyd++ = *yys++) != '\0')
     continue;
@@ -932,7 +988,55 @@
 #  endif
 # endif
 
-#endif /* !YYERROR_VERBOSE */
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      size_t yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
 
 
 
@@ -998,7 +1102,7 @@
 
   switch (yytype)
     {
-      case 48: /* choice_entry */
+      case 52: /* "choice_entry" */
 
         {
 	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
@@ -1008,7 +1112,7 @@
 };
 
         break;
-      case 54: /* if_entry */
+      case 58: /* "if_entry" */
 
         {
 	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
@@ -1018,7 +1122,7 @@
 };
 
         break;
-      case 59: /* menu_entry */
+      case 63: /* "menu_entry" */
 
         {
 	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
@@ -1082,13 +1186,13 @@
 #else
 int
 yyparse ()
-
+    ;
 #endif
 #endif
 {
   
-  register int yystate;
-  register int yyn;
+  int yystate;
+  int yyn;
   int yyresult;
   /* Number of tokens to shift before error messages enabled.  */
   int yyerrstatus;
@@ -1106,12 +1210,12 @@
   /* The state stack.  */
   short int yyssa[YYINITDEPTH];
   short int *yyss = yyssa;
-  register short int *yyssp;
+  short int *yyssp;
 
   /* The semantic value stack.  */
   YYSTYPE yyvsa[YYINITDEPTH];
   YYSTYPE *yyvs = yyvsa;
-  register YYSTYPE *yyvsp;
+  YYSTYPE *yyvsp;
 
 
 
@@ -1143,9 +1247,6 @@
   yyssp = yyss;
   yyvsp = yyvs;
 
-
-  yyvsp[0] = yylval;
-
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -1178,7 +1279,7 @@
 	   data in use in that stack, in bytes.  This used to be a
 	   conditional around just the two extra args, but that might
 	   be undefined if yyoverflow is a macro.  */
-	yyoverflow ("parser stack overflow",
+	yyoverflow (YY_("memory exhausted"),
 		    &yyss1, yysize * sizeof (*yyssp),
 		    &yyvs1, yysize * sizeof (*yyvsp),
 
@@ -1189,11 +1290,11 @@
       }
 #else /* no yyoverflow */
 # ifndef YYSTACK_RELOCATE
-      goto yyoverflowlab;
+      goto yyexhaustedlab;
 # else
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-	goto yyoverflowlab;
+	goto yyexhaustedlab;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
 	yystacksize = YYMAXDEPTH;
@@ -1203,7 +1304,7 @@
 	union yyalloc *yyptr =
 	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
 	if (! yyptr)
-	  goto yyoverflowlab;
+	  goto yyexhaustedlab;
 	YYSTACK_RELOCATE (yyss);
 	YYSTACK_RELOCATE (yyvs);
 
@@ -1403,7 +1504,7 @@
 ;}
     break;
 
-  case 37:
+  case 38:
 
     {
 	menu_set_type((yyvsp[-2].id)->stype);
@@ -1413,7 +1514,7 @@
 ;}
     break;
 
-  case 38:
+  case 39:
 
     {
 	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
@@ -1421,7 +1522,7 @@
 ;}
     break;
 
-  case 39:
+  case 40:
 
     {
 	menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
@@ -1433,7 +1534,7 @@
 ;}
     break;
 
-  case 40:
+  case 41:
 
     {
 	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
@@ -1441,7 +1542,7 @@
 ;}
     break;
 
-  case 41:
+  case 42:
 
     {
 	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
@@ -1449,7 +1550,29 @@
 ;}
     break;
 
-  case 42:
+  case 45:
+
+    {
+	struct kconf_id *id = kconf_id_lookup((yyvsp[-1].string), strlen((yyvsp[-1].string)));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, (yyvsp[0].string));
+	else
+		zconfprint("warning: ignoring unknown option %s", (yyvsp[-1].string));
+	free((yyvsp[-1].string));
+;}
+    break;
+
+  case 46:
+
+    { (yyval.string) = NULL; ;}
+    break;
+
+  case 47:
+
+    { (yyval.string) = (yyvsp[0].string); ;}
+    break;
+
+  case 48:
 
     {
 	struct symbol *sym = sym_lookup(NULL, 0);
@@ -1460,14 +1583,14 @@
 ;}
     break;
 
-  case 43:
+  case 49:
 
     {
 	(yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 44:
+  case 50:
 
     {
 	if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
@@ -1477,7 +1600,7 @@
 ;}
     break;
 
-  case 52:
+  case 58:
 
     {
 	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
@@ -1485,7 +1608,7 @@
 ;}
     break;
 
-  case 53:
+  case 59:
 
     {
 	if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
@@ -1498,7 +1621,7 @@
 ;}
     break;
 
-  case 54:
+  case 60:
 
     {
 	current_entry->sym->flags |= SYMBOL_OPTIONAL;
@@ -1506,7 +1629,7 @@
 ;}
     break;
 
-  case 55:
+  case 61:
 
     {
 	if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
@@ -1518,7 +1641,7 @@
 ;}
     break;
 
-  case 58:
+  case 64:
 
     {
 	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
@@ -1528,7 +1651,7 @@
 ;}
     break;
 
-  case 59:
+  case 65:
 
     {
 	if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
@@ -1538,7 +1661,7 @@
 ;}
     break;
 
-  case 65:
+  case 71:
 
     {
 	menu_add_entry(NULL);
@@ -1547,14 +1670,14 @@
 ;}
     break;
 
-  case 66:
+  case 72:
 
     {
 	(yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 67:
+  case 73:
 
     {
 	if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
@@ -1564,7 +1687,7 @@
 ;}
     break;
 
-  case 73:
+  case 79:
 
     {
 	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
@@ -1572,7 +1695,7 @@
 ;}
     break;
 
-  case 74:
+  case 80:
 
     {
 	menu_add_entry(NULL);
@@ -1581,14 +1704,14 @@
 ;}
     break;
 
-  case 75:
+  case 81:
 
     {
 	menu_end_entry();
 ;}
     break;
 
-  case 76:
+  case 82:
 
     {
 	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
@@ -1596,14 +1719,14 @@
 ;}
     break;
 
-  case 77:
+  case 83:
 
     {
 	current_entry->sym->help = (yyvsp[0].string);
 ;}
     break;
 
-  case 82:
+  case 88:
 
     {
 	menu_add_dep((yyvsp[-1].expr));
@@ -1611,7 +1734,7 @@
 ;}
     break;
 
-  case 83:
+  case 89:
 
     {
 	menu_add_dep((yyvsp[-1].expr));
@@ -1619,7 +1742,7 @@
 ;}
     break;
 
-  case 84:
+  case 90:
 
     {
 	menu_add_dep((yyvsp[-1].expr));
@@ -1627,87 +1750,88 @@
 ;}
     break;
 
-  case 86:
+  case 92:
 
     {
 	menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
 ;}
     break;
 
-  case 89:
-
-    { (yyval.id) = (yyvsp[-1].id); ;}
-    break;
-
-  case 90:
-
-    { (yyval.id) = (yyvsp[-1].id); ;}
-    break;
-
-  case 91:
-
-    { (yyval.id) = (yyvsp[-1].id); ;}
-    break;
-
-  case 94:
-
-    { (yyval.expr) = NULL; ;}
-    break;
-
   case 95:
 
-    { (yyval.expr) = (yyvsp[0].expr); ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 96:
 
-    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 97:
 
-    { (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)); ;}
-    break;
-
-  case 99:
-
-    { (yyval.expr) = (yyvsp[-1].expr); ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 100:
 
-    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;}
+    { (yyval.expr) = NULL; ;}
     break;
 
   case 101:
 
-    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    { (yyval.expr) = (yyvsp[0].expr); ;}
     break;
 
   case 102:
 
-    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;}
     break;
 
   case 103:
 
-    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;}
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
     break;
 
   case 104:
 
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
+    break;
+
+  case 105:
+
+    { (yyval.expr) = (yyvsp[-1].expr); ;}
+    break;
+
+  case 106:
+
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;}
+    break;
+
+  case 107:
+
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    break;
+
+  case 108:
+
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
+    break;
+
+  case 109:
+
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;}
+    break;
+
+  case 110:
+
     { (yyval.symbol) = sym_lookup((yyvsp[0].string), 1); free((yyvsp[0].string)); ;}
     break;
 
 
+      default: break;
     }
 
-/* Line 1037 of yacc.c.  */
+/* Line 1126 of yacc.c.  */
 
 
   yyvsp -= yylen;
@@ -1747,12 +1871,36 @@
 
       if (YYPACT_NINF < yyn && yyn < YYLAST)
 	{
-	  YYSIZE_T yysize = 0;
 	  int yytype = YYTRANSLATE (yychar);
-	  const char* yyprefix;
-	  char *yymsg;
+	  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+	  YYSIZE_T yysize = yysize0;
+	  YYSIZE_T yysize1;
+	  int yysize_overflow = 0;
+	  char *yymsg = 0;
+#	  define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+	  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
 	  int yyx;
 
+#if 0
+	  /* This is so xgettext sees the translatable formats that are
+	     constructed on the fly.  */
+	  YY_("syntax error, unexpected %s");
+	  YY_("syntax error, unexpected %s, expecting %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+	  YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+	  char *yyfmt;
+	  char const *yyf;
+	  static char const yyunexpected[] = "syntax error, unexpected %s";
+	  static char const yyexpecting[] = ", expecting %s";
+	  static char const yyor[] = " or %s";
+	  char yyformat[sizeof yyunexpected
+			+ sizeof yyexpecting - 1
+			+ ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+			   * (sizeof yyor - 1))];
+	  char const *yyprefix = yyexpecting;
+
 	  /* Start YYX at -YYN if negative to avoid negative indexes in
 	     YYCHECK.  */
 	  int yyxbegin = yyn < 0 ? -yyn : 0;
@@ -1760,48 +1908,68 @@
 	  /* Stay within bounds of both yycheck and yytname.  */
 	  int yychecklim = YYLAST - yyn;
 	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-	  int yycount = 0;
+	  int yycount = 1;
 
-	  yyprefix = ", expecting ";
+	  yyarg[0] = yytname[yytype];
+	  yyfmt = yystpcpy (yyformat, yyunexpected);
+
 	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
 	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
 	      {
-		yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
-		yycount += 1;
-		if (yycount == 5)
+		if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
 		  {
-		    yysize = 0;
+		    yycount = 1;
+		    yysize = yysize0;
+		    yyformat[sizeof yyunexpected - 1] = '\0';
 		    break;
 		  }
+		yyarg[yycount++] = yytname[yyx];
+		yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+		yysize_overflow |= yysize1 < yysize;
+		yysize = yysize1;
+		yyfmt = yystpcpy (yyfmt, yyprefix);
+		yyprefix = yyor;
 	      }
-	  yysize += (sizeof ("syntax error, unexpected ")
-		     + yystrlen (yytname[yytype]));
-	  yymsg = (char *) YYSTACK_ALLOC (yysize);
-	  if (yymsg != 0)
-	    {
-	      char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
-	      yyp = yystpcpy (yyp, yytname[yytype]);
 
-	      if (yycount < 5)
+	  yyf = YY_(yyformat);
+	  yysize1 = yysize + yystrlen (yyf);
+	  yysize_overflow |= yysize1 < yysize;
+	  yysize = yysize1;
+
+	  if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+	    yymsg = (char *) YYSTACK_ALLOC (yysize);
+	  if (yymsg)
+	    {
+	      /* Avoid sprintf, as that infringes on the user's name space.
+		 Don't have undefined behavior even if the translation
+		 produced a string with the wrong number of "%s"s.  */
+	      char *yyp = yymsg;
+	      int yyi = 0;
+	      while ((*yyp = *yyf))
 		{
-		  yyprefix = ", expecting ";
-		  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-		    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-		      {
-			yyp = yystpcpy (yyp, yyprefix);
-			yyp = yystpcpy (yyp, yytname[yyx]);
-			yyprefix = " or ";
-		      }
+		  if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+		    {
+		      yyp += yytnamerr (yyp, yyarg[yyi++]);
+		      yyf += 2;
+		    }
+		  else
+		    {
+		      yyp++;
+		      yyf++;
+		    }
 		}
 	      yyerror (yymsg);
 	      YYSTACK_FREE (yymsg);
 	    }
 	  else
-	    yyerror ("syntax error; also virtual memory exhausted");
+	    {
+	      yyerror (YY_("syntax error"));
+	      goto yyexhaustedlab;
+	    }
 	}
       else
 #endif /* YYERROR_VERBOSE */
-	yyerror ("syntax error");
+	yyerror (YY_("syntax error"));
     }
 
 
@@ -1813,18 +1981,9 @@
 
       if (yychar <= YYEOF)
         {
-          /* If at end of input, pop the error token,
-	     then the rest of the stack, then return failure.  */
+	  /* Return failure if at end of input.  */
 	  if (yychar == YYEOF)
-	     for (;;)
-	       {
-
-		 YYPOPSTACK;
-		 if (yyssp == yyss)
-		   YYABORT;
-		 yydestruct ("Error: popping",
-                             yystos[*yyssp], yyvsp);
-	       }
+	    YYABORT;
         }
       else
 	{
@@ -1843,12 +2002,11 @@
 `---------------------------------------------------*/
 yyerrorlab:
 
-#ifdef __GNUC__
-  /* Pacify GCC when the user code never invokes YYERROR and the label
-     yyerrorlab therefore never appears in user code.  */
+  /* Pacify compilers like 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;
@@ -1911,23 +2069,29 @@
 | yyabortlab -- YYABORT comes here.  |
 `-----------------------------------*/
 yyabortlab:
-  yydestruct ("Error: discarding lookahead",
-              yytoken, &yylval);
-  yychar = YYEMPTY;
   yyresult = 1;
   goto yyreturn;
 
 #ifndef yyoverflow
-/*----------------------------------------------.
-| yyoverflowlab -- parser overflow comes here.  |
-`----------------------------------------------*/
-yyoverflowlab:
-  yyerror ("parser stack overflow");
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
   yyresult = 2;
   /* Fall through.  */
 #endif
 
 yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+		 yytoken, &yylval);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK;
+    }
 #ifndef yyoverflow
   if (yyss != yyssa)
     YYSTACK_FREE (yyss);
@@ -1948,7 +2112,9 @@
 
 	sym_init();
 	menu_init();
-	modules_sym = sym_lookup("MODULES", 0);
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
 	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
 #if YYDEBUG
@@ -1958,6 +2124,12 @@
 	zconfparse();
 	if (zconfnerrs)
 		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
 		sym_check_deps(sym);
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 1f61fba..ab44feb 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -71,6 +71,7 @@
 %token <id>T_DEFAULT
 %token <id>T_SELECT
 %token <id>T_RANGE
+%token <id>T_OPTION
 %token <id>T_ON
 %token <string> T_WORD
 %token <string> T_WORD_QUOTE
@@ -91,6 +92,7 @@
 %type <id> end
 %type <id> option_name
 %type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg
 
 %destructor {
 	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
@@ -173,6 +175,7 @@
 config_option_list:
 	  /* empty */
 	| config_option_list config_option
+	| config_option_list symbol_option
 	| config_option_list depends
 	| config_option_list help
 	| config_option_list option_error
@@ -215,6 +218,26 @@
 	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
 };
 
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+	  /* empty */
+	| symbol_option_list T_WORD symbol_option_arg
+{
+	struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, $3);
+	else
+		zconfprint("warning: ignoring unknown option %s", $2);
+	free($2);
+};
+
+symbol_option_arg:
+	  /* empty */		{ $$ = NULL; }
+	| T_EQUAL prompt	{ $$ = $2; }
+;
+
 /* choice entry */
 
 choice: T_CHOICE T_EOL
@@ -458,7 +481,9 @@
 
 	sym_init();
 	menu_init();
-	modules_sym = sym_lookup("MODULES", 0);
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
 	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
 #if YYDEBUG
@@ -468,6 +493,12 @@
 	zconfparse();
 	if (zconfnerrs)
 		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
 		sym_check_deps(sym);
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 99fe4b7..00e2129 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -253,6 +253,7 @@
 # 3 - scanning prototype.
 # 4 - documentation block
 my $state;
+my $in_doc_sect;
 
 #declaration types: can be
 # 'function', 'struct', 'union', 'enum', 'typedef'
@@ -1064,7 +1065,7 @@
     }
     print "};\n.br\n";
 
-    print ".SH Arguments\n";
+    print ".SH Members\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
 	($parameter =~ /^#/) && next;
 
@@ -1673,6 +1674,9 @@
 # replace <, >, and &
 sub xml_escape($) {
 	my $text = shift;
+	if (($output_mode eq "text") || ($output_mode eq "man")) {
+		return $text;
+	}
 	$text =~ s/\&/\\\\\\amp;/g;
 	$text =~ s/\</\\\\\\lt;/g;
 	$text =~ s/\>/\\\\\\gt;/g;
@@ -1706,6 +1710,7 @@
 	if ($state == 0) {
 	    if (/$doc_start/o) {
 		$state = 1;		# next line is always the function name
+		$in_doc_sect = 0;
 	    }
 	} elsif ($state == 1) {	# this line is the function name (always)
 	    if (/$doc_block/o) {
@@ -1756,12 +1761,20 @@
 		$newcontents = $2;
 
 		if ($contents ne "") {
+		    if (!$in_doc_sect && $verbose) {
+			print STDERR "Warning(${file}:$.): contents before sections\n";
+			++$warnings;
+		    }
 		    dump_section($section, xml_escape($contents));
 		    $section = $section_default;
 		}
 
+		$in_doc_sect = 1;
 		$contents = $newcontents;
 		if ($contents ne "") {
+		    if (substr($contents, 0, 1) eq " ") {
+			$contents = substr($contents, 1);
+		    }
 		    $contents .= "\n";
 		}
 		$section = $newsection;
@@ -1776,7 +1789,7 @@
 		$prototype = "";
 		$state = 3;
 		$brcount = 0;
-#	    print STDERR "end of doc comment, looking for prototype\n";
+#		print STDERR "end of doc comment, looking for prototype\n";
 	    } elsif (/$doc_content/) {
 		# miguel-style comment kludge, look for blank lines after
 		# @parameter line to signify start of description
@@ -1793,7 +1806,7 @@
 		print STDERR "Warning(${file}:$.): bad line: $_";
 		++$warnings;
 	    }
-	} elsif ($state == 3) {	# scanning for function { (end of prototype)
+	} elsif ($state == 3) {	# scanning for function '{' (end of prototype)
 	    if ($decl_type eq 'function') {
 	        process_state3_function($_, $file);
 	    } else {
diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c
index 3c92c83..725d61c 100644
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -28,7 +28,7 @@
 		printf("#define KERNEL_ELFCLASS ELFCLASS64\n");
 		break;
 	default:
-		abort();
+		exit(1);
 	}
 	switch (ei[EI_DATA]) {
 	case ELFDATA2LSB:
@@ -38,7 +38,7 @@
 		printf("#define KERNEL_ELFDATA ELFDATA2MSB\n");
 		break;
 	default:
-		abort();
+		exit(1);
 	}
 
 	if (sizeof(unsigned long) == 4) {
@@ -53,7 +53,7 @@
 	else if (memcmp(endian_test.c, "\x02\x01", 2) == 0)
 		printf("#define HOST_ELFDATA ELFDATA2LSB\n");
 	else
-		abort();
+		exit(1);
 
 	if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0))
 		printf("#define MODULE_SYMBOL_PREFIX \"_\"\n");
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index d0f86ed..0dd1617 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -13,6 +13,7 @@
 
 #include <ctype.h>
 #include "modpost.h"
+#include "../../include/linux/license.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
 int modversions = 0;
@@ -22,6 +23,8 @@
 static int all_versions = 0;
 /* If we are modposting external module set to 1 */
 static int external_module = 0;
+/* How a symbol is exported */
+enum export {export_plain, export_gpl, export_gpl_future, export_unknown};
 
 void fatal(const char *fmt, ...)
 {
@@ -97,6 +100,7 @@
 
 	/* add to list */
 	mod->name = p;
+	mod->gpl_compatible = -1;
 	mod->next = modules;
 	modules = mod;
 
@@ -118,6 +122,7 @@
 	unsigned int kernel:1;     /* 1 if symbol is from kernel
 				    *  (only for external modules) **/
 	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers */
+	enum export  export;       /* Type of export */
 	char name[0];
 };
 
@@ -153,7 +158,8 @@
 }
 
 /* For the hash of exported symbols */
-static struct symbol *new_symbol(const char *name, struct module *module)
+static struct symbol *new_symbol(const char *name, struct module *module,
+				 enum export export)
 {
 	unsigned int hash;
 	struct symbol *new;
@@ -161,6 +167,7 @@
 	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
 	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
 	new->module = module;
+	new->export = export;
 	return new;
 }
 
@@ -179,16 +186,55 @@
 	return NULL;
 }
 
+static struct {
+	const char *str;
+	enum export export;
+} export_list[] = {
+	{ .str = "EXPORT_SYMBOL",            .export = export_plain },
+	{ .str = "EXPORT_SYMBOL_GPL",        .export = export_gpl },
+	{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
+	{ .str = "(unknown)",                .export = export_unknown },
+};
+
+
+static const char *export_str(enum export ex)
+{
+	return export_list[ex].str;
+}
+
+static enum export export_no(const char * s)
+{
+	int i;
+	for (i = 0; export_list[i].export != export_unknown; i++) {
+		if (strcmp(export_list[i].str, s) == 0)
+			return export_list[i].export;
+	}
+	return export_unknown;
+}
+
+static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
+{
+	if (sec == elf->export_sec)
+		return export_plain;
+	else if (sec == elf->export_gpl_sec)
+		return export_gpl;
+	else if (sec == elf->export_gpl_future_sec)
+		return export_gpl_future;
+	else
+		return export_unknown;
+}
+
 /**
  * Add an exported symbol - it may have already been added without a
  * CRC, in this case just update the CRC
  **/
-static struct symbol *sym_add_exported(const char *name, struct module *mod)
+static struct symbol *sym_add_exported(const char *name, struct module *mod,
+				       enum export export)
 {
 	struct symbol *s = find_symbol(name);
 
 	if (!s) {
-		s = new_symbol(name, mod);
+		s = new_symbol(name, mod, export);
 	} else {
 		if (!s->preloaded) {
 			warn("%s: '%s' exported twice. Previous export "
@@ -200,16 +246,17 @@
 	s->preloaded = 0;
 	s->vmlinux   = is_vmlinux(mod->name);
 	s->kernel    = 0;
+	s->export    = export;
 	return s;
 }
 
 static void sym_update_crc(const char *name, struct module *mod,
-			   unsigned int crc)
+			   unsigned int crc, enum export export)
 {
 	struct symbol *s = find_symbol(name);
 
 	if (!s)
-		s = new_symbol(name, mod);
+		s = new_symbol(name, mod, export);
 	s->crc = crc;
 	s->crc_valid = 1;
 }
@@ -283,7 +330,7 @@
 	hdr = grab_file(filename, &info->size);
 	if (!hdr) {
 		perror(filename);
-		abort();
+		exit(1);
 	}
 	info->hdr = hdr;
 	if (info->size < sizeof(*hdr))
@@ -309,13 +356,21 @@
 	for (i = 1; i < hdr->e_shnum; i++) {
 		const char *secstrings
 			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+		const char *secname;
 
 		if (sechdrs[i].sh_offset > info->size)
 			goto truncated;
-		if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
+		secname = secstrings + sechdrs[i].sh_name;
+		if (strcmp(secname, ".modinfo") == 0) {
 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
 			info->modinfo_len = sechdrs[i].sh_size;
-		}
+		} else if (strcmp(secname, "__ksymtab") == 0)
+			info->export_sec = i;
+		else if (strcmp(secname, "__ksymtab_gpl") == 0)
+			info->export_gpl_sec = i;
+		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
+			info->export_gpl_future_sec = i;
+
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
 
@@ -353,6 +408,7 @@
 			       Elf_Sym *sym, const char *symname)
 {
 	unsigned int crc;
+	enum export export = export_from_sec(info, sym->st_shndx);
 
 	switch (sym->st_shndx) {
 	case SHN_COMMON:
@@ -362,7 +418,8 @@
 		/* CRC'd symbol */
 		if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
 			crc = (unsigned int) sym->st_value;
-			sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
+			sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
+					export);
 		}
 		break;
 	case SHN_UNDEF:
@@ -406,7 +463,8 @@
 	default:
 		/* All exported symbols */
 		if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
-			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
+			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,
+					export);
 		}
 		if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
 			mod->has_init = 1;
@@ -437,13 +495,18 @@
 	return string;
 }
 
-static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
-			 const char *tag)
+static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len,
+			      const char *tag, char *info)
 {
 	char *p;
 	unsigned int taglen = strlen(tag);
 	unsigned long size = modinfo_len;
 
+	if (info) {
+		size -= info - (char *)modinfo;
+		modinfo = next_string(info, &size);
+	}
+
 	for (p = modinfo; p; p = next_string(p, &size)) {
 		if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
 			return p + taglen + 1;
@@ -451,6 +514,13 @@
 	return NULL;
 }
 
+static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
+			 const char *tag)
+
+{
+	return get_next_modinfo(modinfo, modinfo_len, tag, NULL);
+}
+
 /**
  * Test if string s ends in string sub
  * return 0 if match
@@ -821,6 +891,10 @@
 		".pci_fixup_final",
 		".pdr",
 		"__param",
+		"__ex_table",
+		".fixup",
+		".smp_locks",
+		".plt",  /* seen on ARCH=um build on x86_64. Harmless */
 		NULL
 	};
 	/* Start of section names */
@@ -846,6 +920,8 @@
 	for (s = namelist3; *s; s++)
 		if (strstr(name, *s) != NULL)
 			return 1;
+	if (strrcmp(name, ".init") == 0)
+		return 1;
 	return 0;
 }
 
@@ -892,6 +968,10 @@
 		".exitcall.exit",
 		".eh_frame",
 		".stab",
+		"__ex_table",
+		".fixup",
+		".smp_locks",
+		".plt",  /* seen on ARCH=um build on x86_64. Harmless */
 		NULL
 	};
 	/* Start of section names */
@@ -921,6 +1001,7 @@
 {
 	const char *symname;
 	char *version;
+	char *license;
 	struct module *mod;
 	struct elf_info info = { };
 	Elf_Sym *sym;
@@ -936,6 +1017,18 @@
 		mod->skip = 1;
 	}
 
+	license = get_modinfo(info.modinfo, info.modinfo_len, "license");
+	while (license) {
+		if (license_is_gpl_compatible(license))
+			mod->gpl_compatible = 1;
+		else {
+			mod->gpl_compatible = 0;
+			break;
+		}
+		license = get_next_modinfo(info.modinfo, info.modinfo_len,
+					   "license", license);
+	}
+
 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
 		symname = info.strtab + sym->st_name;
 
@@ -992,6 +1085,41 @@
 	buf->pos += len;
 }
 
+void check_license(struct module *mod)
+{
+	struct symbol *s, *exp;
+
+	for (s = mod->unres; s; s = s->next) {
+		const char *basename;
+		if (mod->gpl_compatible == 1) {
+			/* GPL-compatible modules may use all symbols */
+			continue;
+		}
+		exp = find_symbol(s->name);
+		if (!exp || exp->module == mod)
+			continue;
+		basename = strrchr(mod->name, '/');
+		if (basename)
+			basename++;
+		switch (exp->export) {
+			case export_gpl:
+				fatal("modpost: GPL-incompatible module %s "
+				      "uses GPL-only symbol '%s'\n",
+				 basename ? basename : mod->name,
+				exp->name);
+				break;
+			case export_gpl_future:
+				warn("modpost: GPL-incompatible module %s "
+				      "uses future GPL-only symbol '%s'\n",
+				      basename ? basename : mod->name,
+				      exp->name);
+				break;
+			case export_plain: /* ignore */ break;
+			case export_unknown: /* ignore */ break;
+		}
+        }
+}
+
 /**
  * Header for the generated file
  **/
@@ -1142,6 +1270,9 @@
 	fclose(file);
 }
 
+/* parse Module.symvers file. line format:
+ * 0x12345678<tab>symbol<tab>module[<tab>export]
+ **/
 static void read_dump(const char *fname, unsigned int kernel)
 {
 	unsigned long size, pos = 0;
@@ -1153,7 +1284,7 @@
 		return;
 
 	while ((line = get_next_line(&pos, file, size))) {
-		char *symname, *modname, *d;
+		char *symname, *modname, *d, *export;
 		unsigned int crc;
 		struct module *mod;
 		struct symbol *s;
@@ -1164,8 +1295,9 @@
 		if (!(modname = strchr(symname, '\t')))
 			goto fail;
 		*modname++ = '\0';
-		if (strchr(modname, '\t'))
-			goto fail;
+		if ((export = strchr(modname, '\t')) != NULL)
+			*export++ = '\0';
+
 		crc = strtoul(line, &d, 16);
 		if (*symname == '\0' || *modname == '\0' || *d != '\0')
 			goto fail;
@@ -1177,10 +1309,10 @@
 			mod = new_module(NOFAIL(strdup(modname)));
 			mod->skip = 1;
 		}
-		s = sym_add_exported(symname, mod);
+		s = sym_add_exported(symname, mod, export_no(export));
 		s->kernel    = kernel;
 		s->preloaded = 1;
-		sym_update_crc(symname, mod, crc);
+		sym_update_crc(symname, mod, crc, export_no(export));
 	}
 	return;
 fail:
@@ -1210,9 +1342,10 @@
 		symbol = symbolhash[n];
 		while (symbol) {
 			if (dump_sym(symbol))
-				buf_printf(&buf, "0x%08x\t%s\t%s\n",
+				buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n",
 					symbol->crc, symbol->name,
-					symbol->module->name);
+					symbol->module->name,
+					export_str(symbol->export));
 			symbol = symbol->next;
 		}
 	}
@@ -1263,6 +1396,12 @@
 	for (mod = modules; mod; mod = mod->next) {
 		if (mod->skip)
 			continue;
+		check_license(mod);
+	}
+
+	for (mod = modules; mod; mod = mod->next) {
+		if (mod->skip)
+			continue;
 
 		buf.pos = 0;
 
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 861d866..2b00c60 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -100,6 +100,7 @@
 struct module {
 	struct module *next;
 	const char *name;
+	int gpl_compatible;
 	struct symbol *unres;
 	int seen;
 	int skip;
@@ -115,6 +116,9 @@
 	Elf_Shdr     *sechdrs;
 	Elf_Sym      *symtab_start;
 	Elf_Sym      *symtab_stop;
+	Elf_Section  export_sec;
+	Elf_Section  export_gpl_sec;
+	Elf_Section  export_gpl_future_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index 0b10387..df89284 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -73,8 +73,13 @@
 echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
 echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
 echo "%else"
+echo "%ifarch ppc64"
+echo "cp vmlinux arch/powerpc/boot"
+echo "cp arch/powerpc/boot/"'$KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
+echo "%else"
 echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
 echo "%endif"
+echo "%endif"
 
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
 
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 9a23825..82e4993 100644
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -11,12 +11,12 @@
 # Check for git and a git repo.
 if head=`git rev-parse --verify HEAD 2>/dev/null`; then
 	# Do we have an untagged version?
-	if  [ "`git name-rev --tags HEAD`" = "HEAD undefined" ]; then
+	if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then
 		printf '%s%s' -g `echo "$head" | cut -c1-8`
 	fi
 
 	# Are there uncommitted changes?
-	if git diff-files | read dummy; then
+	if git diff-index HEAD | read dummy; then
 		printf '%s' -dirty
 	fi
 fi
diff --git a/security/Kconfig b/security/Kconfig
index 34f5934..67785df 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -22,16 +22,22 @@
 	  If you are unsure as to whether this is required, answer N.
 
 config KEYS_DEBUG_PROC_KEYS
-	bool "Enable the /proc/keys file by which all keys may be viewed"
+	bool "Enable the /proc/keys file by which keys may be viewed"
 	depends on KEYS
 	help
-	  This option turns on support for the /proc/keys file through which
-	  all the keys on the system can be listed.
+	  This option turns on support for the /proc/keys file - through which
+	  can be listed all the keys on the system that are viewable by the
+	  reading process.
 
-	  This option is a slight security risk in that it makes it possible
-	  for anyone to see all the keys on the system. Normally the manager
-	  pretends keys that are inaccessible to a process don't exist as far
-	  as that process is concerned.
+	  The only keys included in the list are those that grant View
+	  permission to the reading process whether or not it possesses them.
+	  Note that LSM security checks are still performed, and may further
+	  filter out keys that the current process is not authorised to view.
+
+	  Only key attributes are listed here; key payloads are not included in
+	  the resulting table.
+
+	  If you are unsure as to whether this is required, answer N.
 
 config SECURITY
 	bool "Enable different security models"
diff --git a/security/dummy.c b/security/dummy.c
index c3c5493..310fcdf7 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -870,7 +870,8 @@
 }
 
 #ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx)
+static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
+				  unsigned long flags)
 {
 	return 0;
 }
diff --git a/security/inode.c b/security/inode.c
index e6fc29a..98a0df5 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -224,7 +224,7 @@
 
 	pr_debug("securityfs: creating file '%s'\n",name);
 
-	error = simple_pin_fs("securityfs", &mount, &mount_count);
+	error = simple_pin_fs(&fs_type, &mount, &mount_count);
 	if (error) {
 		dentry = ERR_PTR(error);
 		goto exit;
diff --git a/security/keys/internal.h b/security/keys/internal.h
index e066e60..3c2877f 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -99,7 +99,8 @@
 extern struct key *request_key_and_link(struct key_type *type,
 					const char *description,
 					const char *callout_info,
-					struct key *dest_keyring);
+					struct key *dest_keyring,
+					unsigned long flags);
 
 /*
  * request_key authorisation
diff --git a/security/keys/key.c b/security/keys/key.c
index 51f8515..43295ca 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -15,11 +15,11 @@
 #include <linux/slab.h>
 #include <linux/security.h>
 #include <linux/workqueue.h>
+#include <linux/random.h>
 #include <linux/err.h>
 #include "internal.h"
 
 static kmem_cache_t	*key_jar;
-static key_serial_t	key_serial_next = 3;
 struct rb_root		key_serial_tree; /* tree of keys indexed by serial */
 DEFINE_SPINLOCK(key_serial_lock);
 
@@ -169,22 +169,23 @@
 /*****************************************************************************/
 /*
  * assign a key the next unique serial number
- * - we work through all the serial numbers between 2 and 2^31-1 in turn and
- *   then wrap
+ * - these are assigned randomly to avoid security issues through covert
+ *   channel problems
  */
 static inline void key_alloc_serial(struct key *key)
 {
 	struct rb_node *parent, **p;
 	struct key *xkey;
 
-	spin_lock(&key_serial_lock);
-
-	/* propose a likely serial number and look for a hole for it in the
+	/* propose a random serial number and look for a hole for it in the
 	 * serial number tree */
-	key->serial = key_serial_next;
-	if (key->serial < 3)
-		key->serial = 3;
-	key_serial_next = key->serial + 1;
+	do {
+		get_random_bytes(&key->serial, sizeof(key->serial));
+
+		key->serial >>= 1; /* negative numbers are not permitted */
+	} while (key->serial < 3);
+
+	spin_lock(&key_serial_lock);
 
 	parent = NULL;
 	p = &key_serial_tree.rb_node;
@@ -204,12 +205,11 @@
 
 	/* we found a key with the proposed serial number - walk the tree from
 	 * that point looking for the next unused serial number */
- serial_exists:
+serial_exists:
 	for (;;) {
-		key->serial = key_serial_next;
+		key->serial++;
 		if (key->serial < 2)
 			key->serial = 2;
-		key_serial_next = key->serial + 1;
 
 		if (!rb_parent(parent))
 			p = &key_serial_tree.rb_node;
@@ -228,7 +228,7 @@
 	}
 
 	/* we've found a suitable hole - arrange for this key to occupy it */
- insert_here:
+insert_here:
 	rb_link_node(&key->serial_node, parent, p);
 	rb_insert_color(&key->serial_node, &key_serial_tree);
 
@@ -248,7 +248,7 @@
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
 		      uid_t uid, gid_t gid, struct task_struct *ctx,
-		      key_perm_t perm, int not_in_quota)
+		      key_perm_t perm, unsigned long flags)
 {
 	struct key_user *user = NULL;
 	struct key *key;
@@ -269,12 +269,14 @@
 
 	/* check that the user's quota permits allocation of another key and
 	 * its description */
-	if (!not_in_quota) {
+	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
 		spin_lock(&user->lock);
-		if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
-		    user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
-		    )
-			goto no_quota;
+		if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
+			if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+			    user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
+			    )
+				goto no_quota;
+		}
 
 		user->qnkeys++;
 		user->qnbytes += quotalen;
@@ -308,7 +310,7 @@
 	key->payload.data = NULL;
 	key->security = NULL;
 
-	if (!not_in_quota)
+	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
 		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
 
 	memset(&key->type_data, 0, sizeof(key->type_data));
@@ -318,7 +320,7 @@
 #endif
 
 	/* let the security module know about the key */
-	ret = security_key_alloc(key, ctx);
+	ret = security_key_alloc(key, ctx, flags);
 	if (ret < 0)
 		goto security_error;
 
@@ -332,7 +334,7 @@
 security_error:
 	kfree(key->description);
 	kmem_cache_free(key_jar, key);
-	if (!not_in_quota) {
+	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
 		spin_lock(&user->lock);
 		user->qnkeys--;
 		user->qnbytes -= quotalen;
@@ -345,7 +347,7 @@
 no_memory_3:
 	kmem_cache_free(key_jar, key);
 no_memory_2:
-	if (!not_in_quota) {
+	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
 		spin_lock(&user->lock);
 		user->qnkeys--;
 		user->qnbytes -= quotalen;
@@ -761,7 +763,7 @@
 			       const char *description,
 			       const void *payload,
 			       size_t plen,
-			       int not_in_quota)
+			       unsigned long flags)
 {
 	struct key_type *ktype;
 	struct key *keyring, *key = NULL;
@@ -822,7 +824,7 @@
 
 	/* allocate a new key */
 	key = key_alloc(ktype, description, current->fsuid, current->fsgid,
-			current, perm, not_in_quota);
+			current, perm, flags);
 	if (IS_ERR(key)) {
 		key_ref = ERR_PTR(PTR_ERR(key));
 		goto error_3;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ed71d86..329411c 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -102,7 +102,7 @@
 	/* create or update the requested key and add it to the target
 	 * keyring */
 	key_ref = key_create_or_update(keyring_ref, type, description,
-				       payload, plen, 0);
+				       payload, plen, KEY_ALLOC_IN_QUOTA);
 	if (!IS_ERR(key_ref)) {
 		ret = key_ref_to_ptr(key_ref)->serial;
 		key_ref_put(key_ref);
@@ -184,7 +184,8 @@
 
 	/* do the search */
 	key = request_key_and_link(ktype, description, callout_info,
-				   key_ref_to_ptr(dest_ref));
+				   key_ref_to_ptr(dest_ref),
+				   KEY_ALLOC_IN_QUOTA);
 	if (IS_ERR(key)) {
 		ret = PTR_ERR(key);
 		goto error5;
@@ -672,6 +673,7 @@
  */
 long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 {
+	struct key_user *newowner, *zapowner = NULL;
 	struct key *key;
 	key_ref_t key_ref;
 	long ret;
@@ -695,19 +697,50 @@
 	if (!capable(CAP_SYS_ADMIN)) {
 		/* only the sysadmin can chown a key to some other UID */
 		if (uid != (uid_t) -1 && key->uid != uid)
-			goto no_access;
+			goto error_put;
 
 		/* only the sysadmin can set the key's GID to a group other
 		 * than one of those that the current process subscribes to */
 		if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
-			goto no_access;
+			goto error_put;
 	}
 
-	/* change the UID (have to update the quotas) */
+	/* change the UID */
 	if (uid != (uid_t) -1 && uid != key->uid) {
-		/* don't support UID changing yet */
-		ret = -EOPNOTSUPP;
-		goto no_access;
+		ret = -ENOMEM;
+		newowner = key_user_lookup(uid);
+		if (!newowner)
+			goto error_put;
+
+		/* transfer the quota burden to the new user */
+		if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+			spin_lock(&newowner->lock);
+			if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+			    newowner->qnbytes + key->quotalen >=
+			    KEYQUOTA_MAX_BYTES)
+				goto quota_overrun;
+
+			newowner->qnkeys++;
+			newowner->qnbytes += key->quotalen;
+			spin_unlock(&newowner->lock);
+
+			spin_lock(&key->user->lock);
+			key->user->qnkeys--;
+			key->user->qnbytes -= key->quotalen;
+			spin_unlock(&key->user->lock);
+		}
+
+		atomic_dec(&key->user->nkeys);
+		atomic_inc(&newowner->nkeys);
+
+		if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+			atomic_dec(&key->user->nikeys);
+			atomic_inc(&newowner->nikeys);
+		}
+
+		zapowner = key->user;
+		key->user = newowner;
+		key->uid = uid;
 	}
 
 	/* change the GID */
@@ -716,12 +749,20 @@
 
 	ret = 0;
 
- no_access:
+error_put:
 	up_write(&key->sem);
 	key_put(key);
- error:
+	if (zapowner)
+		key_user_put(zapowner);
+error:
 	return ret;
 
+quota_overrun:
+	spin_unlock(&newowner->lock);
+	zapowner = newowner;
+	ret = -EDQUOT;
+	goto error_put;
+
 } /* end keyctl_chown_key() */
 
 /*****************************************************************************/
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 1357207..e8d02ac 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -49,6 +49,7 @@
 static int keyring_instantiate(struct key *keyring,
 			       const void *data, size_t datalen);
 static int keyring_match(const struct key *keyring, const void *criterion);
+static void keyring_revoke(struct key *keyring);
 static void keyring_destroy(struct key *keyring);
 static void keyring_describe(const struct key *keyring, struct seq_file *m);
 static long keyring_read(const struct key *keyring,
@@ -59,6 +60,7 @@
 	.def_datalen	= sizeof(struct keyring_list),
 	.instantiate	= keyring_instantiate,
 	.match		= keyring_match,
+	.revoke		= keyring_revoke,
 	.destroy	= keyring_destroy,
 	.describe	= keyring_describe,
 	.read		= keyring_read,
@@ -240,7 +242,7 @@
  * allocate a keyring and link into the destination keyring
  */
 struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
-			  struct task_struct *ctx, int not_in_quota,
+			  struct task_struct *ctx, unsigned long flags,
 			  struct key *dest)
 {
 	struct key *keyring;
@@ -249,7 +251,7 @@
 	keyring = key_alloc(&key_type_keyring, description,
 			    uid, gid, ctx,
 			    (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
-			    not_in_quota);
+			    flags);
 
 	if (!IS_ERR(keyring)) {
 		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -953,3 +955,22 @@
 } /* end keyring_clear() */
 
 EXPORT_SYMBOL(keyring_clear);
+
+/*****************************************************************************/
+/*
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+static void keyring_revoke(struct key *keyring)
+{
+	struct keyring_list *klist = keyring->payload.subscriptions;
+
+	/* adjust the quota */
+	key_payload_reserve(keyring, 0);
+
+	if (klist) {
+		rcu_assign_pointer(keyring->payload.subscriptions, NULL);
+		call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
+	}
+
+} /* end keyring_revoke() */
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 12b750e..686a9ee 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -137,6 +137,13 @@
 	struct timespec now;
 	unsigned long timo;
 	char xbuf[12];
+	int rc;
+
+	/* check whether the current task is allowed to view the key (assuming
+	 * non-possession) */
+	rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW);
+	if (rc < 0)
+		return 0;
 
 	now = current_kernel_time();
 
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 4d9825f..32150cf 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -77,7 +77,8 @@
 	/* concoct a default session keyring */
 	sprintf(buf, "_uid_ses.%u", user->uid);
 
-	session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL);
+	session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+					KEY_ALLOC_IN_QUOTA, NULL);
 	if (IS_ERR(session_keyring)) {
 		ret = PTR_ERR(session_keyring);
 		goto error;
@@ -87,8 +88,8 @@
 	 * keyring */
 	sprintf(buf, "_uid.%u", user->uid);
 
-	uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0,
-				    session_keyring);
+	uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+				    KEY_ALLOC_IN_QUOTA, session_keyring);
 	if (IS_ERR(uid_keyring)) {
 		key_put(session_keyring);
 		ret = PTR_ERR(uid_keyring);
@@ -144,7 +145,8 @@
 
 	sprintf(buf, "_tid.%u", tsk->pid);
 
-	keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
+	keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+				KEY_ALLOC_QUOTA_OVERRUN, NULL);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto error;
@@ -178,7 +180,8 @@
 	if (!tsk->signal->process_keyring) {
 		sprintf(buf, "_pid.%u", tsk->tgid);
 
-		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
+		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+					KEY_ALLOC_QUOTA_OVERRUN, NULL);
 		if (IS_ERR(keyring)) {
 			ret = PTR_ERR(keyring);
 			goto error;
@@ -209,6 +212,7 @@
 static int install_session_keyring(struct task_struct *tsk,
 				   struct key *keyring)
 {
+	unsigned long flags;
 	struct key *old;
 	char buf[20];
 
@@ -218,7 +222,12 @@
 	if (!keyring) {
 		sprintf(buf, "_ses.%u", tsk->tgid);
 
-		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
+		flags = KEY_ALLOC_QUOTA_OVERRUN;
+		if (tsk->signal->session_keyring)
+			flags = KEY_ALLOC_IN_QUOTA;
+
+		keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+					flags, NULL);
 		if (IS_ERR(keyring))
 			return PTR_ERR(keyring);
 	}
@@ -728,7 +737,8 @@
 	keyring = find_keyring_by_name(name, 0);
 	if (PTR_ERR(keyring) == -ENOKEY) {
 		/* not found - try and create a new one */
-		keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL);
+		keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
+					KEY_ALLOC_IN_QUOTA, NULL);
 		if (IS_ERR(keyring)) {
 			ret = PTR_ERR(keyring);
 			goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index eab66a0..58d1efd 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -48,8 +48,8 @@
 	/* allocate a new session keyring */
 	sprintf(desc, "_req.%u", key->serial);
 
-	keyring = keyring_alloc(desc, current->fsuid, current->fsgid,
-				current, 1, NULL);
+	keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+				KEY_ALLOC_QUOTA_OVERRUN, NULL);
 	if (IS_ERR(keyring)) {
 		ret = PTR_ERR(keyring);
 		goto error_alloc;
@@ -126,7 +126,8 @@
  */
 static struct key *__request_key_construction(struct key_type *type,
 					      const char *description,
-					      const char *callout_info)
+					      const char *callout_info,
+					      unsigned long flags)
 {
 	request_key_actor_t actor;
 	struct key_construction cons;
@@ -134,12 +135,12 @@
 	struct key *key, *authkey;
 	int ret, negated;
 
-	kenter("%s,%s,%s", type->name, description, callout_info);
+	kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
 
 	/* create a key and add it to the queue */
 	key = key_alloc(type, description,
-			current->fsuid, current->fsgid,
-			current, KEY_POS_ALL, 0);
+			current->fsuid, current->fsgid, current, KEY_POS_ALL,
+			flags);
 	if (IS_ERR(key))
 		goto alloc_failed;
 
@@ -258,15 +259,16 @@
 static struct key *request_key_construction(struct key_type *type,
 					    const char *description,
 					    struct key_user *user,
-					    const char *callout_info)
+					    const char *callout_info,
+					    unsigned long flags)
 {
 	struct key_construction *pcons;
 	struct key *key, *ckey;
 
 	DECLARE_WAITQUEUE(myself, current);
 
-	kenter("%s,%s,{%d},%s",
-	       type->name, description, user->uid, callout_info);
+	kenter("%s,%s,{%d},%s,%lx",
+	       type->name, description, user->uid, callout_info, flags);
 
 	/* see if there's such a key under construction already */
 	down_write(&key_construction_sem);
@@ -282,7 +284,8 @@
 	}
 
 	/* see about getting userspace to construct the key */
-	key = __request_key_construction(type, description, callout_info);
+	key = __request_key_construction(type, description, callout_info,
+					 flags);
  error:
 	kleave(" = %p", key);
 	return key;
@@ -389,14 +392,15 @@
 struct key *request_key_and_link(struct key_type *type,
 				 const char *description,
 				 const char *callout_info,
-				 struct key *dest_keyring)
+				 struct key *dest_keyring,
+				 unsigned long flags)
 {
 	struct key_user *user;
 	struct key *key;
 	key_ref_t key_ref;
 
-	kenter("%s,%s,%s,%p",
-	       type->name, description, callout_info, dest_keyring);
+	kenter("%s,%s,%s,%p,%lx",
+	       type->name, description, callout_info, dest_keyring, flags);
 
 	/* search all the process keyrings for a key */
 	key_ref = search_process_keyrings(type, description, type->match,
@@ -429,7 +433,8 @@
 			/* ask userspace (returns NULL if it waited on a key
 			 * being constructed) */
 			key = request_key_construction(type, description,
-						       user, callout_info);
+						       user, callout_info,
+						       flags);
 			if (key)
 				break;
 
@@ -485,7 +490,8 @@
 			const char *description,
 			const char *callout_info)
 {
-	return request_key_and_link(type, description, callout_info, NULL);
+	return request_key_and_link(type, description, callout_info, NULL,
+				    KEY_ALLOC_IN_QUOTA);
 
 } /* end request_key() */
 
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index cb9817c..cbf58a9 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -187,7 +187,7 @@
 	authkey = key_alloc(&key_type_request_key_auth, desc,
 			    current->fsuid, current->fsgid, current,
 			    KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
-			    KEY_USR_VIEW, 1);
+			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
 	if (IS_ERR(authkey)) {
 		ret = PTR_ERR(authkey);
 		goto error_alloc;
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 8e71895..5bbfdeb 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -28,6 +28,7 @@
 	.instantiate	= user_instantiate,
 	.update		= user_update,
 	.match		= user_match,
+	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.describe	= user_describe,
 	.read		= user_read,
@@ -67,6 +68,7 @@
 	return ret;
 
 } /* end user_instantiate() */
+
 EXPORT_SYMBOL_GPL(user_instantiate);
 
 /*****************************************************************************/
@@ -141,7 +143,28 @@
 
 /*****************************************************************************/
 /*
- * dispose of the data dangling from the corpse of a user
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+void user_revoke(struct key *key)
+{
+	struct user_key_payload *upayload = key->payload.data;
+
+	/* clear the quota */
+	key_payload_reserve(key, 0);
+
+	if (upayload) {
+		rcu_assign_pointer(key->payload.data, NULL);
+		call_rcu(&upayload->rcu, user_update_rcu_disposal);
+	}
+
+} /* end user_revoke() */
+
+EXPORT_SYMBOL(user_revoke);
+
+/*****************************************************************************/
+/*
+ * dispose of the data dangling from the corpse of a user key
  */
 void user_destroy(struct key *key)
 {
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 79c16e3..ac7f2b2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1099,6 +1099,17 @@
 			    FILESYSTEM__ASSOCIATE, &ad);
 }
 
+/* Check whether a task can create a key. */
+static int may_create_key(u32 ksid,
+			  struct task_struct *ctx)
+{
+	struct task_security_struct *tsec;
+
+	tsec = ctx->security;
+
+	return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+}
+
 #define MAY_LINK   0
 #define MAY_UNLINK 1
 #define MAY_RMDIR  2
@@ -1521,8 +1532,9 @@
 	/* Default to the current task SID. */
 	bsec->sid = tsec->sid;
 
-	/* Reset create SID on execve. */
+	/* Reset create and sockcreate SID on execve. */
 	tsec->create_sid = 0;
+	tsec->sockcreate_sid = 0;
 
 	if (tsec->exec_sid) {
 		newsid = tsec->exec_sid;
@@ -2574,9 +2586,10 @@
 	tsec2->osid = tsec1->osid;
 	tsec2->sid = tsec1->sid;
 
-	/* Retain the exec and create SIDs across fork */
+	/* Retain the exec, create, and sock SIDs across fork */
 	tsec2->exec_sid = tsec1->exec_sid;
 	tsec2->create_sid = tsec1->create_sid;
+	tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
 	/* Retain ptracer SID across fork, if any.
 	   This will be reset by the ptrace hook upon any
@@ -2926,12 +2939,14 @@
 {
 	int err = 0;
 	struct task_security_struct *tsec;
+	u32 newsid;
 
 	if (kern)
 		goto out;
 
 	tsec = current->security;
-	err = avc_has_perm(tsec->sid, tsec->sid,
+	newsid = tsec->sockcreate_sid ? : tsec->sid;
+	err = avc_has_perm(tsec->sid, newsid,
 			   socket_type_to_security_class(family, type,
 			   protocol), SOCKET__CREATE, NULL);
 
@@ -2944,12 +2959,14 @@
 {
 	struct inode_security_struct *isec;
 	struct task_security_struct *tsec;
+	u32 newsid;
 
 	isec = SOCK_INODE(sock)->i_security;
 
 	tsec = current->security;
+	newsid = tsec->sockcreate_sid ? : tsec->sid;
 	isec->sclass = socket_type_to_security_class(family, type, protocol);
-	isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
+	isec->sid = kern ? SECINITSID_KERNEL : newsid;
 	isec->initialized = 1;
 
 	return;
@@ -4150,6 +4167,10 @@
 		sid = tsec->exec_sid;
 	else if (!strcmp(name, "fscreate"))
 		sid = tsec->create_sid;
+	else if (!strcmp(name, "keycreate"))
+		sid = tsec->keycreate_sid;
+	else if (!strcmp(name, "sockcreate"))
+		sid = tsec->sockcreate_sid;
 	else
 		return -EINVAL;
 
@@ -4182,6 +4203,10 @@
 		error = task_has_perm(current, p, PROCESS__SETEXEC);
 	else if (!strcmp(name, "fscreate"))
 		error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+	else if (!strcmp(name, "keycreate"))
+		error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+	else if (!strcmp(name, "sockcreate"))
+		error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
 	else if (!strcmp(name, "current"))
 		error = task_has_perm(current, p, PROCESS__SETCURRENT);
 	else
@@ -4211,6 +4236,13 @@
 		tsec->exec_sid = sid;
 	else if (!strcmp(name, "fscreate"))
 		tsec->create_sid = sid;
+	else if (!strcmp(name, "keycreate")) {
+		error = may_create_key(sid, p);
+		if (error)
+			return error;
+		tsec->keycreate_sid = sid;
+	} else if (!strcmp(name, "sockcreate"))
+		tsec->sockcreate_sid = sid;
 	else if (!strcmp(name, "current")) {
 		struct av_decision avd;
 
@@ -4264,7 +4296,8 @@
 
 #ifdef CONFIG_KEYS
 
-static int selinux_key_alloc(struct key *k, struct task_struct *tsk)
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+			     unsigned long flags)
 {
 	struct task_security_struct *tsec = tsk->security;
 	struct key_security_struct *ksec;
@@ -4274,7 +4307,10 @@
 		return -ENOMEM;
 
 	ksec->obj = k;
-	ksec->sid = tsec->sid;
+	if (tsec->keycreate_sid)
+		ksec->sid = tsec->keycreate_sid;
+	else
+		ksec->sid = tsec->sid;
 	k->security = ksec;
 
 	return 0;
@@ -4513,8 +4549,10 @@
 
 #ifdef CONFIG_KEYS
 	/* Add security information to initial keyrings */
-	security_key_alloc(&root_user_keyring, current);
-	security_key_alloc(&root_session_keyring, current);
+	selinux_key_alloc(&root_user_keyring, current,
+			  KEY_ALLOC_NOT_IN_QUOTA);
+	selinux_key_alloc(&root_session_keyring, current,
+			  KEY_ALLOC_NOT_IN_QUOTA);
 #endif
 
 	return 0;
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index bc020bd..7c9b583 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -72,6 +72,8 @@
    S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
    S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
    S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
+   S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
+   S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate")
    S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
    S_(SECCLASS_MSG, MSG__SEND, "send")
    S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
@@ -248,3 +250,4 @@
    S_(SECCLASS_KEY, KEY__SEARCH, "search")
    S_(SECCLASS_KEY, KEY__LINK, "link")
    S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
+   S_(SECCLASS_KEY, KEY__CREATE, "create")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 1205227..69fd4b4 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -467,6 +467,8 @@
 #define PROCESS__EXECMEM                          0x02000000UL
 #define PROCESS__EXECSTACK                        0x04000000UL
 #define PROCESS__EXECHEAP                         0x08000000UL
+#define PROCESS__SETKEYCREATE                     0x10000000UL
+#define PROCESS__SETSOCKCREATE                    0x20000000UL
 
 #define IPC__CREATE                               0x00000001UL
 #define IPC__DESTROY                              0x00000002UL
@@ -966,4 +968,4 @@
 #define KEY__SEARCH                               0x00000008UL
 #define KEY__LINK                                 0x00000010UL
 #define KEY__SETATTR                              0x00000020UL
-
+#define KEY__CREATE                               0x00000040UL
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 8f5547a..cf54a30 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -32,6 +32,8 @@
 	u32 sid;             /* current SID */
 	u32 exec_sid;        /* exec SID */
 	u32 create_sid;      /* fscreate SID */
+	u32 keycreate_sid;   /* keycreate SID */
+	u32 sockcreate_sid;  /* fscreate SID */
 	u32 ptrace_sid;      /* SID of ptrace parent */
 };
 
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 39c60d9..63e9143 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -31,7 +31,7 @@
 	struct snd_seq_event_cell *next;	/* next cell */
 };
 
-/* design note: the pool is a contigious block of memory, if we dynamicly
+/* design note: the pool is a contiguous block of memory, if we dynamicly
    want to add additional cells to the pool be better store this in another
    pool as we need to know the base address of the pool when releasing
    memory. */
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 080ab03..3b8cdbc 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -114,8 +114,9 @@
 	  with the AC97 codec.
 
 config SOUND_AU1550_AC97
-	tristate "Au1550 AC97 Sound"
-	depends on SOUND_PRIME && SOC_AU1550
+	tristate "Au1550/Au1200 AC97 Sound"
+	select SND_AC97_CODEC
+	depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200)
 
 config SOUND_TRIDENT
 	tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
@@ -838,6 +839,6 @@
 	depends on SOUND_PRIME && CPU_SH3
 
 config SOUND_SH_DAC_AUDIO_CHANNEL
-	int "    DAC channel"
+	int "DAC channel"
 	default "1"
 	depends on SOUND_SH_DAC_AUDIO
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index 9011abe..4cdb862 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -213,7 +213,8 @@
 	}
 	if (i == POLL_COUNT) {
 		err("rdcodec: read poll expired!");
-		return 0;
+		data = 0;
+		goto out;
 	}
 
 	/* wait for command done?
@@ -226,7 +227,8 @@
 	}
 	if (i == POLL_COUNT) {
 		err("rdcodec: read cmdwait expired!");
-		return 0;
+		data = 0;
+		goto out;
 	}
 
 	data = au_readl(PSC_AC97CDC) & 0xffff;
@@ -237,6 +239,7 @@
 	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
 	au_sync();
 
+ out:
 	spin_unlock_irqrestore(&s->lock, flags);
 
 	return data;
@@ -1892,6 +1895,8 @@
 
 MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
 MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
+MODULE_LICENSE("GPL");
+
 
 static int __devinit
 au1550_probe(void)
diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c
index 25ae8e4..8ac77df 100644
--- a/sound/oss/emu10k1/midi.c
+++ b/sound/oss/emu10k1/midi.c
@@ -45,7 +45,7 @@
 #include "../sound_config.h"
 #endif
 
-static DEFINE_SPINLOCK(midi_spinlock __attribute((unused)));
+static DEFINE_SPINLOCK(midi_spinlock);
 
 static void init_midi_hdr(struct midi_hdr *midihdr)
 {
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index 5dbfc0f..ba38d62 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -47,7 +47,7 @@
 static multisound_dev_t		*devs[MSND_MAX_DEVS];
 static int			num_devs;
 
-int __init msnd_register(multisound_dev_t *dev)
+int msnd_register(multisound_dev_t *dev)
 {
 	int i;
 
diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c
index fae05fe..180e95c 100644
--- a/sound/oss/sb_ess.c
+++ b/sound/oss/sb_ess.c
@@ -97,19 +97,19 @@
  *
  * The documentation is an adventure: it's close but not fully accurate. I
  * found out that after a reset some registers are *NOT* reset, though the
- * docs say the would be. Interresting ones are 0x7f, 0x7d and 0x7a. They are
- * related to the Audio 2 channel. I also was suprised about the consequenses
+ * docs say the would be. Interesting ones are 0x7f, 0x7d and 0x7a. They are
+ * related to the Audio 2 channel. I also was surprised about the consequences
  * of writing 0x00 to 0x7f (which should be done by reset): The ES1887 moves
  * into ES1888 mode. This means that it claims IRQ 11, which happens to be my
  * ISDN adapter. Needless to say it no longer worked. I now understand why
  * after rebooting 0x7f already was 0x05, the value of my choice: the BIOS
  * did it.
  *
- * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is decribed
- * as if it's exactly the same as register 0xa1. This is *NOT* true. The
- * description of 0x70 in ES1869 docs is accurate however.
+ * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is
+ * described as if it's exactly the same as register 0xa1. This is *NOT* true.
+ * The description of 0x70 in ES1869 docs is accurate however.
  * Well, the assumption about ES1869 was wrong: register 0x70 is very much
- * like register 0xa1, except that bit 7 is allways 1, whatever you want
+ * like register 0xa1, except that bit 7 is always 1, whatever you want
  * it to be.
  *
  * When using audio 2 mixer register 0x72 seems te be meaningless. Only 0xa2
@@ -117,10 +117,10 @@
  *
  * Software reset not being able to reset all registers is great! Especially
  * the fact that register 0x78 isn't reset is great when you wanna change back
- * to single dma operation (simplex): audio 2 is still operation, and uses the
- * same dma as audio 1: your ess changes into a funny echo machine.
+ * to single dma operation (simplex): audio 2 is still operational, and uses
+ * the same dma as audio 1: your ess changes into a funny echo machine.
  *
- * Received the new that ES1688 is detected as a ES1788. Did some thinking:
+ * Received the news that ES1688 is detected as a ES1788. Did some thinking:
  * the ES1887 detection scheme suggests in step 2 to try if bit 3 of register
  * 0x64 can be changed. This is inaccurate, first I inverted the * check: "If
  * can be modified, it's a 1688", which lead to a correct detection
@@ -135,7 +135,7 @@
  * About recognition of ESS chips
  *
  * The distinction of ES688, ES1688, ES1788, ES1887 and ES1888 is described in
- * a (preliminary ??) datasheet on ES1887. It's aim is to identify ES1887, but
+ * a (preliminary ??) datasheet on ES1887. Its aim is to identify ES1887, but
  * during detection the text claims that "this chip may be ..." when a step
  * fails. This scheme is used to distinct between the above chips.
  * It appears however that some PnP chips like ES1868 are recognized as ES1788
@@ -156,9 +156,9 @@
  *
  * The existing ES1688 support didn't take care of the ES1688+ recording
  * levels very well. Whenever a device was selected (recmask) for recording
- * it's recording level was loud, and it couldn't be changed. The fact that
+ * its recording level was loud, and it couldn't be changed. The fact that
  * internal register 0xb4 could take care of RECLEV, didn't work meaning until
- * it's value was restored every time the chip was reset; this reset the
+ * its value was restored every time the chip was reset; this reset the
  * value of 0xb4 too. I guess that's what 4front also had (have?) trouble with.
  *
  * About ES1887 support:
@@ -169,9 +169,9 @@
  * the latter case the recording volumes are 0.
  * Now recording levels of inputs can be controlled, by changing the playback
  * levels. Futhermore several devices can be recorded together (which is not
- * possible with the ES1688.
+ * possible with the ES1688).
  * Besides the separate recording level control for each input, the common
- * recordig level can also be controlled by RECLEV as described above.
+ * recording level can also be controlled by RECLEV as described above.
  *
  * Not only ES1887 have this recording mixer. I know the following from the
  * documentation:
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index f0a4869..5450a9e 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -143,7 +143,7 @@
 	if (dma->periods == periods && dma->period_bytes == period_bytes)
 		return 0;
 
-	/* the u32 cast is okay because in snd*create we succesfully told
+	/* the u32 cast is okay because in snd*create we successfully told
    	   pci alloc that we're only 32 bit capable so the uppper will be 0 */
 	addr = (u32) substream->runtime->dma_addr;
 	desc_addr = (u32) dma->desc_buf.addr;
diff --git a/usr/Makefile b/usr/Makefile
index 19d74e6..e938242 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -21,8 +21,7 @@
                     $(CONFIG_INITRAMFS_SOURCE),-d)
 ramfs-args  := \
         $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
-        $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) \
-        $(ramfs-input)
+        $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
 
 # .initramfs_data.cpio.gz.d is used to identify all files included
 # in initramfs and to detect if any files are added/removed.