Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  xen: fix address truncation in pte mfn<->pfn conversion
  arch/x86/mm/init_64.c: early_memtest(): fix types
  x86: fix Intel Mac booting with EFI
diff --git a/.gitignore b/.gitignore
index 9bb1cb6..869e1a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,10 @@
 # subdirectories here. Add them in the ".gitignore" file
 # in that subdirectory instead.
 #
+# NOTE! Please use 'git-ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
 # Normal rules
 #
 .*
@@ -18,19 +22,21 @@
 *.lst
 *.symtypes
 *.order
+*.elf
+*.bin
+*.gz
 
 #
 # Top-level generic files
 #
 tags
 TAGS
-vmlinux*
-!vmlinux.lds.S
-!vmlinux.lds.h
+vmlinux
 System.map
 Module.markers
 Module.symvers
 !.gitignore
+!.mailmap
 
 #
 # Generated include files
diff --git a/CREDITS b/CREDITS
index 8fec7b3..e97bea0 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2611,8 +2611,9 @@
 S: Australia
 
 N: Miguel Ojeda Sandonis
-E: maxextreme@gmail.com
-W: http://maxextreme.googlepages.com/
+E: miguel.ojeda.sandonis@gmail.com
+W: http://miguelojeda.es
+W: http://jair.lab.fi.uva.es/~migojed/
 D: Author of the ks0108, cfag12864b and cfag12864bfb auxiliary display drivers.
 D: Maintainer of the auxiliary display drivers tree (drivers/auxdisplay/*)
 S: C/ Mieses 20, 9-B
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index 028a844..e8acd1f 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -84,10 +84,9 @@
     runs an instance of gdb against the vmlinux file which contains
     the symbols (not boot image such as bzImage, zImage, uImage...).
     In gdb the developer specifies the connection parameters and
-    connects to kgdb.  Depending on which kgdb I/O modules exist in
-    the kernel for a given architecture, it may be possible to debug
-    the test machine's kernel with the development machine using a
-    rs232 or ethernet connection.
+    connects to kgdb.  The type of connection a developer makes with
+    gdb depends on the availability of kgdb I/O modules compiled as
+    builtin's or kernel modules in the test machine's kernel.
     </para>
   </chapter>
   <chapter id="CompilingAKernel">
@@ -223,7 +222,7 @@
   </para>
   <para>
   IMPORTANT NOTE: Using this option with kgdb over the console
-  (kgdboc) or kgdb over ethernet (kgdboe) is not supported.
+  (kgdboc) is not supported.
   </para>
   </sect1>
   </chapter>
@@ -249,18 +248,11 @@
     (gdb) target remote /dev/ttyS0
     </programlisting>
     <para>
-    Example (kgdb to a terminal server):
+    Example (kgdb to a terminal server on tcp port 2012):
     </para>
     <programlisting>
     % gdb ./vmlinux
-    (gdb) target remote udp:192.168.2.2:6443
-    </programlisting>
-    <para>
-    Example (kgdb over ethernet):
-    </para>
-    <programlisting>
-    % gdb ./vmlinux
-    (gdb) target remote udp:192.168.2.2:6443
+    (gdb) target remote 192.168.2.2:2012
     </programlisting>
     <para>
     Once connected, you can debug a kernel the way you would debug an
diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt
index 8aa7529..cd784f4 100644
--- a/Documentation/accounting/taskstats-struct.txt
+++ b/Documentation/accounting/taskstats-struct.txt
@@ -24,6 +24,8 @@
 
 4) Per-task and per-thread context switch count statistics
 
+5) Time accounting for SMT machines
+
 Future extension should add fields to the end of the taskstats struct, and
 should not change the relative position of each field within the struct.
 
@@ -164,4 +166,8 @@
 	__u64	nvcsw;			/* Context voluntary switch counter */
 	__u64	nivcsw;			/* Context involuntary switch counter */
 
+5) Time accounting for SMT machines
+	__u64	ac_utimescaled;		/* utime scaled on frequency etc */
+	__u64	ac_stimescaled;		/* stime scaled on frequency etc */
+	__u64	cpu_scaled_run_real_total; /* scaled cpu_run_real_total */
 }
diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b
index b714183..eb7be39 100644
--- a/Documentation/auxdisplay/cfag12864b
+++ b/Documentation/auxdisplay/cfag12864b
@@ -3,7 +3,7 @@
 	===================================
 
 License:		GPLv2
-Author & Maintainer:	Miguel Ojeda Sandonis <maxextreme@gmail.com>
+Author & Maintainer:	Miguel Ojeda Sandonis
 Date:			2006-10-27
 
 
@@ -22,7 +22,7 @@
 1. DRIVER INFORMATION
 ---------------------
 
-This driver support one cfag12864b display at time.
+This driver supports a cfag12864b LCD.
 
 
 ---------------------
diff --git a/Documentation/auxdisplay/cfag12864b-example.c b/Documentation/auxdisplay/cfag12864b-example.c
index 7bfac35..2caeea5 100644
--- a/Documentation/auxdisplay/cfag12864b-example.c
+++ b/Documentation/auxdisplay/cfag12864b-example.c
@@ -4,7 +4,7 @@
  * Description: cfag12864b LCD userspace example program
  *     License: GPLv2
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/Documentation/auxdisplay/ks0108 b/Documentation/auxdisplay/ks0108
index 92b03b6..8ddda0c 100644
--- a/Documentation/auxdisplay/ks0108
+++ b/Documentation/auxdisplay/ks0108
@@ -3,7 +3,7 @@
 	==========================================
 
 License:		GPLv2
-Author & Maintainer:	Miguel Ojeda Sandonis <maxextreme@gmail.com>
+Author & Maintainer:	Miguel Ojeda Sandonis
 Date:			2006-10-27
 
 
@@ -21,7 +21,7 @@
 1. DRIVER INFORMATION
 ---------------------
 
-This driver support the ks0108 LCD controller.
+This driver supports the ks0108 LCD controller.
 
 
 ---------------------
diff --git a/Documentation/cgroups.txt b/Documentation/cgroups.txt
index 824fc02..d9014aa 100644
--- a/Documentation/cgroups.txt
+++ b/Documentation/cgroups.txt
@@ -390,6 +390,10 @@
 	...
 # /bin/echo PIDn > tasks
 
+You can attach the current shell task by echoing 0:
+
+# echo 0 > tasks
+
 3. Kernel API
 =============
 
diff --git a/Documentation/controllers/devices.txt b/Documentation/controllers/devices.txt
index 4dcea42..7cc6e6a 100644
--- a/Documentation/controllers/devices.txt
+++ b/Documentation/controllers/devices.txt
@@ -13,7 +13,7 @@
 The root device cgroup starts with rwm to 'all'.  A child device
 cgroup gets a copy of the parent.  Administrators can then remove
 devices from the whitelist or add new entries.  A child cgroup can
-never receive a device access which is denied its parent.  However
+never receive a device access which is denied by its parent.  However
 when a device access is removed from a parent it will not also be
 removed from the child(ren).
 
@@ -29,7 +29,11 @@
 
 	echo a > /cgroups/1/devices.deny
 
-will remove the default 'a *:* mrw' entry.
+will remove the default 'a *:* rwm' entry. Doing
+
+	echo a > /cgroups/1/devices.allow
+
+will add the 'a *:* rwm' entry to the whitelist.
 
 3. Security
 
diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
index d803c5c..1f5a924 100644
--- a/Documentation/cpusets.txt
+++ b/Documentation/cpusets.txt
@@ -154,13 +154,15 @@
 new system calls are added for cpusets - all support for querying and
 modifying cpusets is via this cpuset file system.
 
-The /proc/<pid>/status file for each task has two added lines,
+The /proc/<pid>/status file for each task has four added lines,
 displaying the tasks cpus_allowed (on which CPUs it may be scheduled)
 and mems_allowed (on which Memory Nodes it may obtain memory),
-in the format seen in the following example:
+in the two formats seen in the following example:
 
   Cpus_allowed:   ffffffff,ffffffff,ffffffff,ffffffff
+  Cpus_allowed_list:      0-127
   Mems_allowed:   ffffffff,ffffffff
+  Mems_allowed_list:      0-63
 
 Each cpuset is represented by a directory in the cgroup file system
 containing (on top of the standard cgroup files) the following
@@ -542,7 +544,10 @@
    2  : search cores in a package.
    3  : search cpus in a node [= system wide on non-NUMA system]
  ( 4  : search nodes in a chunk of node [on NUMA system] )
- ( 5~ : search system wide [on NUMA system])
+ ( 5  : search system wide [on NUMA system] )
+
+The system default is architecture dependent.  The system default
+can be changed using the relax_domain_level= boot parameter.
 
 This file is per-cpuset and affect the sched domain where the cpuset
 belongs to.  Therefore if the flag 'sched_load_balance' of a cpuset
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 5b3f31f..46ece3f 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -312,3 +312,12 @@
 Why:	Implementation became generic; users should now include
 	linux/semaphore.h instead.
 Who:	Matthew Wilcox <willy@linux.intel.com>
+
+---------------------------
+
+What:	CONFIG_THERMAL_HWMON
+When:	January 2009
+Why:	This option was introduced just to allow older lm-sensors userspace
+	to keep working over the upgrade to 2.6.26. At the scheduled time of
+	removal fixed lm-sensors (2.x or 3.x) should be readily available.
+Who:	Rene Herman <rene.herman@gmail.com>
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index f4a8ebc..2d84573 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -2,17 +2,12 @@
 ------------------------------------------------
 
 The libsensors library offers an interface to the raw sensors data
-through the sysfs interface. See libsensors documentation and source for
-further information. As of writing this document, libsensors
-(from lm_sensors 2.8.3) is heavily chip-dependent. Adding or updating
-support for any given chip requires modifying the library's code.
-This is because libsensors was written for the procfs interface
-older kernel modules were using, which wasn't standardized enough.
-Recent versions of libsensors (from lm_sensors 2.8.2 and later) have
-support for the sysfs interface, though.
-
-The new sysfs interface was designed to be as chip-independent as
-possible.
+through the sysfs interface. Since lm-sensors 3.0.0, libsensors is
+completely chip-independent. It assumes that all the kernel drivers
+implement the standard sysfs interface described in this document.
+This makes adding or updating support for any given chip very easy, as
+libsensors, and applications using it, do not need to be modified.
+This is a major improvement compared to lm-sensors 2.
 
 Note that motherboards vary widely in the connections to sensor chips.
 There is no standard that ensures, for example, that the second
@@ -35,19 +30,17 @@
 will have to implement conversion, labeling and hiding of inputs. For
 this reason, it is still not recommended to bypass the library.
 
-If you are developing a userspace application please send us feedback on
-this standard.
-
-Note that this standard isn't completely established yet, so it is subject
-to changes. If you are writing a new hardware monitoring driver those
-features can't seem to fit in this interface, please contact us with your
-extension proposal. Keep in mind that backward compatibility must be
-preserved.
-
 Each chip gets its own directory in the sysfs /sys/devices tree.  To
 find all sensor chips, it is easier to follow the device symlinks from
 /sys/class/hwmon/hwmon*.
 
+Up to lm-sensors 3.0.0, libsensors looks for hardware monitoring attributes
+in the "physical" device directory. Since lm-sensors 3.0.1, attributes found
+in the hwmon "class" device directory are also supported. Complex drivers
+(e.g. drivers for multifunction chips) may want to use this possibility to
+avoid namespace pollution. The only drawback will be that older versions of
+libsensors won't support the driver in question.
+
 All sysfs values are fixed point numbers.
 
 There is only one value per file, unlike the older /proc specification.
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index ee75cba..d4cd412 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -25,12 +25,23 @@
 provide.  A client structure holds device-specific information like the
 driver model device node, and its I2C address.
 
+/* iff driver uses driver model ("new style") binding model: */
+
+static struct i2c_device_id foo_idtable[] = {
+	{ "foo", my_id_for_foo },
+	{ "bar", my_id_for_bar },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, foo_idtable);
+
 static struct i2c_driver foo_driver = {
 	.driver = {
 		.name	= "foo",
 	},
 
 	/* iff driver uses driver model ("new style") binding model: */
+	.id_table	= foo_ids,
 	.probe		= foo_probe,
 	.remove		= foo_remove,
 
@@ -173,10 +184,9 @@
 (zero not a negative status code) it may save the handle and use it until
 foo_remove() returns.  That binding model is used by most Linux drivers.
 
-Drivers match devices when i2c_client.driver_name and the driver name are
-the same; this approach is used in several other busses that don't have
-device typing support in the hardware.  The driver and module name should
-match, so hotplug/coldplug mechanisms will modprobe the driver.
+The probe function is called when an entry in the id_table name field
+matches the device's name. It is passed the entry that was matched so
+the driver knows which one in the table matched.
 
 
 Device Creation (Standard driver model)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e07c432..b52f47d 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -295,7 +295,7 @@
 			when initialising the APIC and IO-APIC components.
 
 	apm=		[APM] Advanced Power Management
-			See header of arch/i386/kernel/apm.c.
+			See header of arch/x86/kernel/apm_32.c.
 
 	arcrimi=	[HW,NET] ARCnet - "RIM I" (entirely mem-mapped) cards
 			Format: <io>,<irq>,<nodeID>
@@ -638,7 +638,7 @@
 
 	elanfreq=	[X86-32]
 			See comment before function elanfreq_setup() in
-			arch/i386/kernel/cpu/cpufreq/elanfreq.c.
+			arch/x86/kernel/cpu/cpufreq/elanfreq.c.
 
 	elevator=	[IOSCHED]
 			Format: {"anticipatory" | "cfq" | "deadline" | "noop"}
@@ -1679,6 +1679,10 @@
 			Format: <reboot_mode>[,<reboot_mode2>[,...]]
 			See arch/*/kernel/reboot.c or arch/*/kernel/process.c			
 
+	relax_domain_level=
+			[KNL, SMP] Set scheduler's default relax_domain_level.
+			See Documentation/cpusets.txt.
+
 	reserve=	[KNL,BUGS] Force the kernel to ignore some iomem area
 
 	reservetop=	[X86-32]
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 17a6e46..17f1f91 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -81,23 +81,23 @@
 	Minimum time-to-live of entries.  Should be enough to cover fragment
 	time-to-live on the reassembling side.  This minimum time-to-live  is
 	guaranteed if the pool size is less than inet_peer_threshold.
-	Measured in jiffies(1).
+	Measured in seconds.
 
 inet_peer_maxttl - INTEGER
 	Maximum time-to-live of entries.  Unused entries will expire after
 	this period of time if there is no memory pressure on the pool (i.e.
 	when the number of entries in the pool is very small).
-	Measured in jiffies(1).
+	Measured in seconds.
 
 inet_peer_gc_mintime - INTEGER
 	Minimum interval between garbage collection passes.  This interval is
 	in effect under high memory pressure on the pool.
-	Measured in jiffies(1).
+	Measured in seconds.
 
 inet_peer_gc_maxtime - INTEGER
 	Minimum interval between garbage collection passes.  This interval is
 	in effect under low (or absent) memory pressure on the pool.
-	Measured in jiffies(1).
+	Measured in seconds.
 
 TCP variables: 
 
@@ -794,10 +794,6 @@
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
 
-(1) Jiffie: internal timeunit for the kernel. On the i386 1/100s, on the
-Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact
-value on your system. 
-
 Alexey Kuznetsov.
 kuznet@ms2.inr.ac.ru
 
diff --git a/Documentation/networking/s2io.txt b/Documentation/networking/s2io.txt
index 4bde53e..1e28e2d 100644
--- a/Documentation/networking/s2io.txt
+++ b/Documentation/networking/s2io.txt
@@ -83,9 +83,9 @@
 Default: 30 
 
 e. intr_type
-Specifies interrupt type. Possible values 1(INTA), 2(MSI), 3(MSI-X)
-Valid range: 1-3
-Default: 1 
+Specifies interrupt type. Possible values 0(INTA), 2(MSI-X)
+Valid values: 0, 2
+Default: 2
 
 5.  Performance suggestions
 General:
diff --git a/Documentation/video4linux/CARDLIST.au0828 b/Documentation/video4linux/CARDLIST.au0828
index aaae360..86d1c8e 100644
--- a/Documentation/video4linux/CARDLIST.au0828
+++ b/Documentation/video4linux/CARDLIST.au0828
@@ -1,4 +1,4 @@
   0 -> Unknown board                            (au0828)
-  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200]
+  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200,2040:7210,2040:7217,2040:721b,2040:721f,2040:7280,0fd9:0008]
   2 -> Hauppauge HVR850                         (au0828)        [2040:7240]
   3 -> DViCO FusionHDTV USB                     (au0828)        [0fe9:d620]
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c
index e4230ed..df32276 100644
--- a/Documentation/vm/slabinfo.c
+++ b/Documentation/vm/slabinfo.c
@@ -1,7 +1,7 @@
 /*
  * Slabinfo: Tool to get reports about slabs
  *
- * (C) 2007 sgi, Christoph Lameter <clameter@sgi.com>
+ * (C) 2007 sgi, Christoph Lameter
  *
  * Compile by:
  *
@@ -99,7 +99,7 @@
 
 void usage(void)
 {
-	printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
+	printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
 		"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
 		"-a|--aliases           Show aliases\n"
 		"-A|--activity          Most active slabs first\n"
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index 7c13f22..bb1f5c6 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -266,4 +266,4 @@
 
 	slub_debug=FZ,dentry
 
-Christoph Lameter, <clameter@sgi.com>, May 30, 2007
+Christoph Lameter, May 30, 2007
diff --git a/MAINTAINERS b/MAINTAINERS
index cd587ee..6476125 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -763,9 +763,10 @@
 
 AUXILIARY DISPLAY DRIVERS
 P:	Miguel Ojeda Sandonis
-M:	maxextreme@gmail.com
+M:	miguel.ojeda.sandonis@gmail.com
 L:	linux-kernel@vger.kernel.org
-W:	http://auxdisplay.googlepages.com/
+W:	http://miguelojeda.es/auxdisplay.htm
+W:	http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:	Maintained
 
 AVR32 ARCHITECTURE
@@ -1055,16 +1056,18 @@
 
 CFAG12864B LCD DRIVER
 P:	Miguel Ojeda Sandonis
-M:	maxextreme@gmail.com
+M:	miguel.ojeda.sandonis@gmail.com
 L:	linux-kernel@vger.kernel.org
-W:	http://auxdisplay.googlepages.com/
+W:	http://miguelojeda.es/auxdisplay.htm
+W:	http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:	Maintained
 
 CFAG12864BFB LCD FRAMEBUFFER DRIVER
 P:	Miguel Ojeda Sandonis
-M:	maxextreme@gmail.com
+M:	miguel.ojeda.sandonis@gmail.com
 L:	linux-kernel@vger.kernel.org
-W:	http://auxdisplay.googlepages.com/
+W:	http://miguelojeda.es/auxdisplay.htm
+W:	http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:	Maintained
 
 CFG80211 and NL80211
@@ -1420,6 +1423,14 @@
 L:	linux-acpi@vger.kernel.org
 S:	Supported
 
+DOCUMENTATION (/Documentation directory)
+P:     Michael Kerrisk
+M:     mtk.manpages@gmail.com
+P:     Randy Dunlap
+M:     rdunlap@xenotime.net
+L:     linux-doc@vger.kernel.org
+S:     Maintained
+
 DOUBLETALK DRIVER
 P:	James R. Van Zandt
 M:	jrv@vanzandt.mv.com
@@ -1626,13 +1637,13 @@
 
 EXT3 FILE SYSTEM
 P:	Stephen Tweedie, Andrew Morton
-M:	sct@redhat.com, akpm@linux-foundation.org, adilger@clusterfs.com
+M:	sct@redhat.com, akpm@linux-foundation.org, adilger@sun.com
 L:	linux-ext4@vger.kernel.org
 S:	Maintained
 
 EXT4 FILE SYSTEM
 P:	Stephen Tweedie, Andrew Morton
-M:	sct@redhat.com, akpm@linux-foundation.org, adilger@clusterfs.com
+M:	sct@redhat.com, akpm@linux-foundation.org, adilger@sun.com
 L:	linux-ext4@vger.kernel.org
 S:	Maintained
 
@@ -2428,9 +2439,10 @@
 
 KS0108 LCD CONTROLLER DRIVER
 P:	Miguel Ojeda Sandonis
-M:	maxextreme@gmail.com
+M:	miguel.ojeda.sandonis@gmail.com
 L:	linux-kernel@vger.kernel.org
-W:	http://auxdisplay.googlepages.com/
+W:	http://miguelojeda.es/auxdisplay.htm
+W:	http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:	Maintained
 
 LAPB module
@@ -2474,9 +2486,11 @@
 W:	http://www.hansenpartnership.com/voyager
 S:	Maintained
 
-LINUX FOR POWERPC
+LINUX FOR POWERPC (32-BIT AND 64-BIT)
 P:	Paul Mackerras
 M:	paulus@samba.org
+P:	Benjamin Herrenschmidt
+M:	benh@kernel.crashing.org
 W:	http://www.penguinppc.org/
 L:	linuxppc-dev@ozlabs.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc.git
@@ -2516,13 +2530,6 @@
 L:	linuxppc-dev@ozlabs.org
 S:	Maintained
 
-LINUX FOR POWERPC BOOT CODE
-P:	Tom Rini
-M:	trini@kernel.crashing.org
-W:	http://www.penguinppc.org/
-L:	linuxppc-dev@ozlabs.org
-S:	Maintained
-
 LINUX FOR POWERPC EMBEDDED PPC8XX
 P:	Vitaly Bordug
 M:	vitb@kernel.crashing.org
@@ -2551,17 +2558,6 @@
 M:	acme@ghostprotocols.net
 S:	Maintained
 
-LINUX FOR 64BIT POWERPC
-P:	Paul Mackerras
-M:	paulus@samba.org
-M:	paulus@au.ibm.com
-P:	Anton Blanchard
-M:	anton@samba.org
-M:	anton@au.ibm.com
-W:	http://www.penguinppc.org/ppc64/
-L:	linuxppc-dev@ozlabs.org
-S:	Supported
-
 LINUX SECURITY MODULE (LSM) FRAMEWORK
 P:	Chris Wright
 M:	chrisw@sous-sol.org
@@ -2680,8 +2676,8 @@
 MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
 P:	Michael Kerrisk
 M:	mtk.manpages@gmail.com
-W:	ftp://ftp.kernel.org/pub/linux/docs/manpages
-S:	Maintained
+W:     http://www.kernel.org/doc/man-pages
+S:     Supported
 
 MARVELL LIBERTAS WIRELESS DRIVER
 P:	Dan Williams
@@ -2814,6 +2810,12 @@
 W:	http://0pointer.de/lennart/tchibo.html
 S:	Maintained
 
+MULTIFUNCTION DEVICES (MFD)
+P:	Samuel Ortiz
+M:	sameo@openedhand.com
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 P:	Pierre Ossman
 M:	drzeus-mmc@drzeus.cx
@@ -3195,8 +3197,8 @@
 S:	Maintained
 
 PER-TASK DELAY ACCOUNTING
-P:	Shailabh Nagar
-M:	nagar@watson.ibm.com
+P:	Balbir Singh
+M:	balbir@linux.vnet.ibm.com
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
@@ -3688,7 +3690,7 @@
 
 SLAB ALLOCATOR
 P:	Christoph Lameter
-M:	clameter@sgi.com
+M:	cl@linux-foundation.org
 P:	Pekka Enberg
 M:	penberg@cs.helsinki.fi
 P:	Matt Mackall
@@ -3898,8 +3900,8 @@
 S:	Maintained
 
 TASKSTATS STATISTICS INTERFACE
-P:	Shailabh Nagar
-M:	nagar@watson.ibm.com
+P:	Balbir Singh
+M:	balbir@linux.vnet.ibm.com
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
@@ -3995,7 +3997,8 @@
 S:	Maintained
 
 TPM DEVICE DRIVER
-P:	Kylene Hall
+P:     Debora Velarde
+P:     Rajiv Andrade
 M:	tpmdd-devel@lists.sourceforge.net
 W:	http://tpmdd.sourceforge.net
 P:	Marcel Selhorst
@@ -4314,6 +4317,14 @@
 W:	http://www.linux-usb.org/usbnet
 S:	Maintained
 
+USB VIDEO CLASS
+P:	Laurent Pinchart
+M:	laurent.pinchart@skynet.be
+L:	linx-uvc-devel@berlios.de
+L:	video4linux-list@redhat.com
+W:	http://linux-uvc.berlios.de
+S:	Maintained
+
 USB W996[87]CF DRIVER
 P:	Luca Risolia
 M:	luca.risolia@studio.unibo.it
@@ -4431,10 +4442,10 @@
 S:	Maintained
 
 W83791D HARDWARE MONITORING DRIVER
-P:	Charles Spirakis
-M:	bezaur@gmail.com
+P:	Marc Hulsman
+M:	m.hulsman@tudelft.nl
 L:	lm-sensors@lm-sensors.org
-S:	Odd Fixes
+S:	Maintained
 
 W83793 HARDWARE MONITORING DRIVER
 P:	Rudolf Marek
diff --git a/Makefile b/Makefile
index 6923d66..6aff5f4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 26
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc8
 NAME = Rotary Wombat
 
 # *DOCUMENTATION*
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 4e1a8e2..4759fe7 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -13,6 +13,7 @@
 LDFLAGS_vmlinux	:= -static -N #-relax
 CHECKFLAGS	+= -D__alpha__ -m64
 cflags-y	:= -pipe -mno-fp-regs -ffixed-8 -msmall-data
+cflags-y	+= $(call cc-option, -fno-jump-tables)
 
 cpuflags-$(CONFIG_ALPHA_EV4)		:= -mcpu=ev4
 cpuflags-$(CONFIG_ALPHA_EV5)		:= -mcpu=ev5
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
index c075029..d9980d4 100644
--- a/arch/alpha/kernel/core_t2.c
+++ b/arch/alpha/kernel/core_t2.c
@@ -74,6 +74,8 @@
 # define DBG(args)
 #endif
 
+DEFINE_SPINLOCK(t2_hae_lock);
+
 static volatile unsigned int t2_mcheck_any_expected;
 static volatile unsigned int t2_mcheck_last_taken;
 
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 36ab22a..5cf45fc 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -71,6 +71,23 @@
 static void __init
 quirk_cypress(struct pci_dev *dev)
 {
+	/* The Notorious Cy82C693 chip.  */
+
+	/* The generic legacy mode IDE fixup in drivers/pci/probe.c
+	   doesn't work correctly with the Cypress IDE controller as
+	   it has non-standard register layout.  Fix that.  */
+	if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) {
+		dev->resource[2].start = dev->resource[3].start = 0;
+		dev->resource[2].end = dev->resource[3].end = 0;
+		dev->resource[2].flags = dev->resource[3].flags = 0;
+		if (PCI_FUNC(dev->devfn) == 2) {
+			dev->resource[0].start = 0x170;
+			dev->resource[0].end = 0x177;
+			dev->resource[1].start = 0x376;
+			dev->resource[1].end = 0x376;
+		}
+	}
+
 	/* The Cypress bridge responds on the PCI bus in the address range
 	   0xffff0000-0xffffffff (conventional x86 BIOS ROM).  There is no
 	   way to turn this off.  The bridge also supports several extended
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index dc57790..c778779 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -447,7 +447,7 @@
 
 
 /* Macro for exception fixup code to access integer registers.  */
-#define una_reg(r)  (regs->regs[(r) >= 16 && (r) <= 18 ? (r)+19 : (r)])
+#define una_reg(r)  (_regs[(r) >= 16 && (r) <= 18 ? (r)+19 : (r)])
 
 
 asmlinkage void
@@ -456,6 +456,7 @@
 {
 	long error, tmp1, tmp2, tmp3, tmp4;
 	unsigned long pc = regs->pc - 4;
+	unsigned long *_regs = regs->regs;
 	const struct exception_table_entry *fixup;
 
 	unaligned[0].count++;
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index f13249b..ef37fc1 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -25,6 +25,13 @@
 	} :kernel
 	_etext = .;	/* End of text section */
 
+	NOTES :kernel :note
+	.dummy : {
+		*(.dummy)
+	} :kernel
+
+	RODATA
+
 	/* Exception table */
 	. = ALIGN(16);
 	__ex_table : {
@@ -33,13 +40,6 @@
 		__stop___ex_table = .;
 	}
 
-	NOTES :kernel :note
-	.dummy : {
-		*(.dummy)
-	} :kernel
-
-	RODATA
-
 	/* Will be freed after init */
 	. = ALIGN(PAGE_SIZE);
 	/* Init code and data */
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 52fc6a8..2744673 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -650,7 +650,8 @@
 EXPORT_SYMBOL(dma_unmap_sg);
 EXPORT_SYMBOL(dma_sync_single_for_cpu);
 EXPORT_SYMBOL(dma_sync_single_for_device);
-EXPORT_SYMBOL(dma_sync_sg);
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+EXPORT_SYMBOL(dma_sync_sg_for_device);
 EXPORT_SYMBOL(dmabounce_register_dev);
 EXPORT_SYMBOL(dmabounce_unregister_dev);
 
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 02cede2..dbf68dc 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -42,7 +42,7 @@
 #define GPMC_STATUS		0x54
 #define GPMC_PREFETCH_CONFIG1	0x1e0
 #define GPMC_PREFETCH_CONFIG2	0x1e4
-#define GPMC_PREFETCH_CONTROL	0x1e8
+#define GPMC_PREFETCH_CONTROL	0x1ec
 #define GPMC_PREFETCH_STATUS	0x1f0
 #define GPMC_ECC_CONFIG		0x1f4
 #define GPMC_ECC_CONTROL	0x1f8
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 3e57428..8e813ed 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -74,6 +74,8 @@
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
+	trace_hardirqs_off();
+
 	/*
 	 * the primary core may have used a "cross call" soft interrupt
 	 * to get this processor out of WFI in the BootMonitor - make
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c00eda5..39c637b 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -501,8 +501,6 @@
 
 	/* Enable some nice interrupts. */
 	OMAP_DMA_CICR_REG(lch) = dma_chan[lch].enabled_irqs;
-
-	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
 }
 
 static void omap_disable_channel_irq(int lch)
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
index 917325b..6be0c50 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
@@ -254,7 +254,8 @@
 }
 
 /* helper function */
-static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+static void __init
+__fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
 {
 	if (cplb_data[i].psize) {
 		fill_cplbtab(t,
@@ -291,7 +292,8 @@
 	}
 }
 
-static void __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+static void __init
+__fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
 {
 	if (cplb_data[i].psize) {
 		fill_cplbtab(t,
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 73647c1..07402f5 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -60,9 +60,14 @@
 };
 
 static struct irq_desc bad_irq_desc = {
+	.status = IRQ_DISABLED,
 	.chip = &bad_chip,
 	.handle_irq = handle_bad_irq,
 	.depth = 1,
+	.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
+#ifdef CONFIG_SMP
+	.affinity = CPU_MASK_ALL
+#endif
 };
 
 int show_interrupts(struct seq_file *p, void *v)
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 082c31d..39752cd 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -558,8 +558,6 @@
 	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
 		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
 				    NR_PREALLOCATE_RTE_ENTRIES);
-		if (!rte)
-			return NULL;
 		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
 			list_add(&rte->rte_list, &free_rte_list);
 	}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index f48a809..632cda8 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -547,7 +547,8 @@
 # ifdef CONFIG_ACPI_NUMA
 	acpi_numa_init();
 	per_cpu_scan_finalize((cpus_weight(early_cpu_possible_map) == 0 ?
-		32 : cpus_weight(early_cpu_possible_map)), additional_cpus);
+		32 : cpus_weight(early_cpu_possible_map)),
+		additional_cpus > 0 ? additional_cpus : 0);
 # endif
 #else
 # ifdef CONFIG_SMP
@@ -578,8 +579,6 @@
 	cpu_init();	/* initialize the bootstrap CPU */
 	mmu_context_init();	/* initialize context_id bitmap */
 
-	check_sal_cache_flush();
-
 #ifdef CONFIG_ACPI
 	acpi_boot_init();
 #endif
@@ -607,6 +606,7 @@
 		ia64_mca_init();
 
 	platform_setup(cmdline_p);
+	check_sal_cache_flush();
 	paging_init();
 }
 
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 8c73643..aad1b7b 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -117,6 +117,7 @@
 
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(account_system_vtime);
 
 /*
  * Called from the timer interrupt handler to charge accumulated user time
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index 49d3120..e585f9a 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -512,6 +512,8 @@
 	int cpu;
 	char optstr[64];
 
+	if (count == 0 || count > sizeof(optstr))
+		return -EINVAL;
 	if (copy_from_user(optstr, user, count))
 		return -EFAULT;
 	optstr[count - 1] = '\0';
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e5a7c5d..24c5dee 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1006,7 +1006,7 @@
 config MIPS_L1_CACHE_SHIFT
 	int
 	default "4" if MACH_DECSTATION
-	default "7" if SGI_IP27 || SGI_IP28 || SNI_RM
+	default "7" if SGI_IP22 || SGI_IP27 || SGI_IP28 || SNI_RM
 	default "4" if PMC_MSP4200_EVAL
 	default "5"
 
diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c
index 795cb8f..b5fc4eb 100644
--- a/arch/mips/kernel/cevt-txx9.c
+++ b/arch/mips/kernel/cevt-txx9.c
@@ -161,6 +161,9 @@
 	struct txx9_tmr_reg __iomem *tmrptr;
 
 	tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
+	/* Start once to make CounterResetEnable effective */
+	__raw_writel(TXx9_TMTCR_CRE | TXx9_TMTCR_TCE, &tmrptr->tcr);
+	/* Stop and reset the counter */
 	__raw_writel(TXx9_TMTCR_CRE, &tmrptr->tcr);
 	__raw_writel(0, &tmrptr->tisr);
 	__raw_writel(0xffffffff, &tmrptr->cpra);
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index b0ea0e4..0d6b666 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -425,6 +425,11 @@
 	BUILD_BUG_ON(MACEISA_SERIAL2_RDMAOR_IRQ - MACEISA_AUDIO_SW_IRQ != 31);
 
 	crime_int = crime->istat & crime_mask;
+
+	/* crime sometime delivers spurious interrupts, ignore them */
+	if (unlikely(crime_int == 0))
+		return;
+
 	irq = MACE_VID_IN1_IRQ + __ffs(crime_int);
 
 	if (crime_int & CRIME_MACEISA_INT_MASK) {
diff --git a/arch/mn10300/kernel/mn10300_ksyms.c b/arch/mn10300/kernel/mn10300_ksyms.c
index 6d19628..f9eb975 100644
--- a/arch/mn10300/kernel/mn10300_ksyms.c
+++ b/arch/mn10300/kernel/mn10300_ksyms.c
@@ -10,8 +10,11 @@
  */
 #include <linux/module.h>
 #include <asm/uaccess.h>
+#include <asm/pgtable.h>
 
 
+EXPORT_SYMBOL(empty_zero_page);
+
 EXPORT_SYMBOL(change_bit);
 EXPORT_SYMBOL(test_and_change_bit);
 
@@ -31,7 +34,9 @@
 extern u64 __ashldi3(u64, unsigned);
 extern u64 __lshrdi3(u64, unsigned);
 extern s64 __negdi2(s64);
+extern int __ucmpdi2(u64, u64);
 EXPORT_SYMBOL(__ashrdi3);
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__lshrdi3);
 EXPORT_SYMBOL(__negdi2);
+EXPORT_SYMBOL(__ucmpdi2);
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 9c623c8..b28c9a6 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -153,6 +153,7 @@
 	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,
 		       NULL, NULL);
 }
+EXPORT_SYMBOL(kernel_thread);
 
 /*
  * free current thread data structures etc..
diff --git a/arch/mn10300/lib/Makefile b/arch/mn10300/lib/Makefile
index fdfa9ec..0cd2346 100644
--- a/arch/mn10300/lib/Makefile
+++ b/arch/mn10300/lib/Makefile
@@ -4,4 +4,4 @@
 
 lib-y = delay.o usercopy.o checksum.o bitops.o memcpy.o memmove.o memset.o
 lib-y += do_csum.o
-lib-y += __ashldi3.o __ashrdi3.o __lshrdi3.o negdi2.o
+lib-y += __ashldi3.o __ashrdi3.o __lshrdi3.o negdi2.o __ucmpdi2.o
diff --git a/arch/mn10300/lib/__ucmpdi2.S b/arch/mn10300/lib/__ucmpdi2.S
new file mode 100644
index 0000000..60dcbdf
--- /dev/null
+++ b/arch/mn10300/lib/__ucmpdi2.S
@@ -0,0 +1,43 @@
+/* __ucmpdi2.S: 64-bit unsigned compare
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+        .text
+        .p2align	4
+
+###############################################################################
+#
+# int __ucmpdi2(unsigned long long a [D0:D1],
+#		unsigned long long b [(SP,12),(SP,16)])
+#
+# - returns 0, 1, or 2 as a <, =, > b respectively.
+#
+###############################################################################
+        .globl		__ucmpdi2
+        .type		__ucmpdi2,@function
+__ucmpdi2:
+	mov		(12,sp),a0		# b.lsw
+	mov		(16,sp),a1		# b.msw
+
+	sub		a0,d0
+	subc		a1,d1			# may clear Z, never sets it
+	bne		__ucmpdi2_differ	# a.msw != b.msw
+	mov		+1,d0
+	rets
+
+__ucmpdi2_differ:
+	# C flag is set if LE, clear if GE
+	subc		d0,d0			# -1 if LE, 0 if GE
+	add		+1,d0			#  0 if LE, 1 if GE
+	add		d0,d0			#  0 if LE, 2 if GE
+	rets
+
+	.size		__ucmpdi2, .-__ucmpdi2
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 1cee2f9..095e04d 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -273,7 +273,8 @@
 initrd-  := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
 initrd-y := $(patsubst zImage%, zImage.initrd%, \
 		$(patsubst dtbImage%, dtbImage.initrd%, \
-		$(patsubst treeImage%, treeImage.initrd%, $(image-y))))
+		$(patsubst simpleImage%, simpleImage.initrd%, \
+		$(patsubst treeImage%, treeImage.initrd%, $(image-y)))))
 initrd-y := $(filter-out $(image-y), $(initrd-y))
 targets	+= $(image-y) $(initrd-y)
 
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 61dd174..cf37f5c 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -136,6 +136,11 @@
 	if (of_get_property(np, "clock-frequency", NULL) == NULL)
 		return -1;
 
+	/* if reg-shift or offset, don't try to use it */
+	if ((of_get_property(np, "reg-shift", NULL) != NULL) ||
+		(of_get_property(np, "reg-offset", NULL) != NULL))
+		return -1;
+
 	/* if rtas uses this device, don't try to use it as well */
 	if (of_get_property(np, "used-by-rtas", NULL) != NULL)
 		return -1;
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index c21a626..ce245a8 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -142,7 +142,7 @@
 	printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT),
 	       page_count(pg),
 	       pg->flags);
-	if (upg/* && pg != upg*/) {
+	if (upg && !IS_ERR(upg) /* && pg != upg*/) {
 		printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg)
 						       << PAGE_SHIFT),
 		       page_count(upg),
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
index 41c7fd9..fe92e65 100644
--- a/arch/powerpc/platforms/52xx/lite5200_pm.c
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -14,6 +14,7 @@
 static struct mpc52xx_xlb __iomem *xlb;
 static struct mpc52xx_gpio __iomem *gps;
 static struct mpc52xx_gpio_wkup __iomem *gpw;
+static void __iomem *pci;
 static void __iomem *sram;
 static const int sram_size = 0x4000;	/* 16 kBytes */
 static void __iomem *mbar;
@@ -50,6 +51,8 @@
 		{ .type = "builtin", .compatible = "mpc5200", }, /* efika */
 		{}
 	};
+	u64 regaddr64 = 0;
+	const u32 *regaddr_p;
 
 	/* deep sleep? let mpc52xx code handle that */
 	if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)
@@ -60,8 +63,12 @@
 
 	/* map registers */
 	np = of_find_matching_node(NULL, immr_ids);
-	mbar = of_iomap(np, 0);
+	regaddr_p = of_get_address(np, 0, NULL, NULL);
+	if (regaddr_p)
+		regaddr64 = of_translate_address(np, regaddr_p);
 	of_node_put(np);
+
+	mbar = ioremap((u32) regaddr64, 0xC000);
 	if (!mbar) {
 		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
 		return -ENOSYS;
@@ -71,6 +78,7 @@
 	pic = mbar + 0x500;
 	gps = mbar + 0xb00;
 	gpw = mbar + 0xc00;
+	pci = mbar + 0xd00;
 	bes = mbar + 0x1200;
 	xlb = mbar + 0x1f00;
 	sram = mbar + 0x8000;
@@ -85,6 +93,7 @@
 static struct mpc52xx_xlb sxlb;
 static struct mpc52xx_gpio sgps;
 static struct mpc52xx_gpio_wkup sgpw;
+static char spci[0x200];
 
 static void lite5200_save_regs(void)
 {
@@ -94,6 +103,7 @@
 	_memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
 	_memcpy_fromio(&sgps, gps, sizeof(*gps));
 	_memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
+	_memcpy_fromio(spci, pci, 0x200);
 
 	_memcpy_fromio(saved_sram, sram, sram_size);
 }
@@ -103,6 +113,8 @@
 	int i;
 	_memcpy_toio(sram, saved_sram, sram_size);
 
+	/* PCI Configuration */
+	_memcpy_toio(pci, spci, 0x200);
 
 	/*
 	 * GPIOs. Interrupt Master Enable has higher address then other
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8a07f41..bf07b6f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -383,6 +383,7 @@
 config KVM_CLOCK
 	bool "KVM paravirtualized clock"
 	select PARAVIRT
+	select PARAVIRT_CLOCK
 	depends on !(X86_VISWS || X86_VOYAGER)
 	help
 	  Turning on this option will allow you to run a paravirtualized clock
@@ -410,6 +411,10 @@
 	  over full virtualization.  However, when run without a hypervisor
 	  the kernel is theoretically slower and slightly larger.
 
+config PARAVIRT_CLOCK
+	bool
+	default n
+
 endif
 
 config MEMTEST_BOOTPARAM
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 5e618c3..77807d4 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -82,6 +82,7 @@
 obj-$(CONFIG_KVM_GUEST)		+= kvm.o
 obj-$(CONFIG_KVM_CLOCK)		+= kvmclock.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o paravirt_patch_$(BITS).o
+obj-$(CONFIG_PARAVIRT_CLOCK)	+= pvclock.o
 
 obj-$(CONFIG_PCSPKR_PLATFORM)	+= pcspeaker.o
 
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 08a3098..87edf1c 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -18,6 +18,7 @@
 
 #include <linux/clocksource.h>
 #include <linux/kvm_para.h>
+#include <asm/pvclock.h>
 #include <asm/arch_hooks.h>
 #include <asm/msr.h>
 #include <asm/apic.h>
@@ -36,18 +37,9 @@
 early_param("no-kvmclock", parse_no_kvmclock);
 
 /* The hypervisor will put information about time periodically here */
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct kvm_vcpu_time_info, hv_clock);
-#define get_clock(cpu, field) per_cpu(hv_clock, cpu).field
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct pvclock_vcpu_time_info, hv_clock);
+static struct pvclock_wall_clock wall_clock;
 
-static inline u64 kvm_get_delta(u64 last_tsc)
-{
-	int cpu = smp_processor_id();
-	u64 delta = native_read_tsc() - last_tsc;
-	return (delta * get_clock(cpu, tsc_to_system_mul)) >> KVM_SCALE;
-}
-
-static struct kvm_wall_clock wall_clock;
-static cycle_t kvm_clock_read(void);
 /*
  * The wallclock is the time of day when we booted. Since then, some time may
  * have elapsed since the hypervisor wrote the data. So we try to account for
@@ -55,64 +47,37 @@
  */
 static unsigned long kvm_get_wallclock(void)
 {
-	u32 wc_sec, wc_nsec;
-	u64 delta;
+	struct pvclock_vcpu_time_info *vcpu_time;
 	struct timespec ts;
-	int version, nsec;
 	int low, high;
 
 	low = (int)__pa(&wall_clock);
 	high = ((u64)__pa(&wall_clock) >> 32);
-
-	delta = kvm_clock_read();
-
 	native_write_msr(MSR_KVM_WALL_CLOCK, low, high);
-	do {
-		version = wall_clock.wc_version;
-		rmb();
-		wc_sec = wall_clock.wc_sec;
-		wc_nsec = wall_clock.wc_nsec;
-		rmb();
-	} while ((wall_clock.wc_version != version) || (version & 1));
 
-	delta = kvm_clock_read() - delta;
-	delta += wc_nsec;
-	nsec = do_div(delta, NSEC_PER_SEC);
-	set_normalized_timespec(&ts, wc_sec + delta, nsec);
-	/*
-	 * Of all mechanisms of time adjustment I've tested, this one
-	 * was the champion!
-	 */
-	return ts.tv_sec + 1;
+	vcpu_time = &get_cpu_var(hv_clock);
+	pvclock_read_wallclock(&wall_clock, vcpu_time, &ts);
+	put_cpu_var(hv_clock);
+
+	return ts.tv_sec;
 }
 
 static int kvm_set_wallclock(unsigned long now)
 {
-	return 0;
+	return -1;
 }
 
-/*
- * This is our read_clock function. The host puts an tsc timestamp each time
- * it updates a new time. Without the tsc adjustment, we can have a situation
- * in which a vcpu starts to run earlier (smaller system_time), but probes
- * time later (compared to another vcpu), leading to backwards time
- */
 static cycle_t kvm_clock_read(void)
 {
-	u64 last_tsc, now;
-	int cpu;
+	struct pvclock_vcpu_time_info *src;
+	cycle_t ret;
 
-	preempt_disable();
-	cpu = smp_processor_id();
-
-	last_tsc = get_clock(cpu, tsc_timestamp);
-	now = get_clock(cpu, system_time);
-
-	now += kvm_get_delta(last_tsc);
-	preempt_enable();
-
-	return now;
+	src = &get_cpu_var(hv_clock);
+	ret = pvclock_clocksource_read(src);
+	put_cpu_var(hv_clock);
+	return ret;
 }
+
 static struct clocksource kvm_clock = {
 	.name = "kvm-clock",
 	.read = kvm_clock_read,
@@ -123,13 +88,14 @@
 	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static int kvm_register_clock(void)
+static int kvm_register_clock(char *txt)
 {
 	int cpu = smp_processor_id();
 	int low, high;
 	low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1;
 	high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
-
+	printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
+	       cpu, high, low, txt);
 	return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high);
 }
 
@@ -140,12 +106,20 @@
 	 * Now that the first cpu already had this clocksource initialized,
 	 * we shouldn't fail.
 	 */
-	WARN_ON(kvm_register_clock());
+	WARN_ON(kvm_register_clock("secondary cpu clock"));
 	/* ok, done with our trickery, call native */
 	setup_secondary_APIC_clock();
 }
 #endif
 
+#ifdef CONFIG_SMP
+void __init kvm_smp_prepare_boot_cpu(void)
+{
+	WARN_ON(kvm_register_clock("primary cpu clock"));
+	native_smp_prepare_boot_cpu();
+}
+#endif
+
 /*
  * After the clock is registered, the host will keep writing to the
  * registered memory location. If the guest happens to shutdown, this memory
@@ -174,7 +148,7 @@
 		return;
 
 	if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
-		if (kvm_register_clock())
+		if (kvm_register_clock("boot clock"))
 			return;
 		pv_time_ops.get_wallclock = kvm_get_wallclock;
 		pv_time_ops.set_wallclock = kvm_set_wallclock;
@@ -182,6 +156,9 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 		pv_apic_ops.setup_secondary_clock = kvm_setup_secondary_clock;
 #endif
+#ifdef CONFIG_SMP
+		smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
+#endif
 		machine_ops.shutdown  = kvm_shutdown;
 #ifdef CONFIG_KEXEC
 		machine_ops.crash_shutdown  = kvm_crash_shutdown;
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
new file mode 100644
index 0000000..05fbe9a
--- /dev/null
+++ b/arch/x86/kernel/pvclock.c
@@ -0,0 +1,141 @@
+/*  paravirtual clock -- common code used by kvm/xen
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <asm/pvclock.h>
+
+/*
+ * These are perodically updated
+ *    xen: magic shared_info page
+ *    kvm: gpa registered via msr
+ * and then copied here.
+ */
+struct pvclock_shadow_time {
+	u64 tsc_timestamp;     /* TSC at last update of time vals.  */
+	u64 system_timestamp;  /* Time, in nanosecs, since boot.    */
+	u32 tsc_to_nsec_mul;
+	int tsc_shift;
+	u32 version;
+};
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+	u64 product;
+#ifdef __i386__
+	u32 tmp1, tmp2;
+#endif
+
+	if (shift < 0)
+		delta >>= -shift;
+	else
+		delta <<= shift;
+
+#ifdef __i386__
+	__asm__ (
+		"mul  %5       ; "
+		"mov  %4,%%eax ; "
+		"mov  %%edx,%4 ; "
+		"mul  %5       ; "
+		"xor  %5,%5    ; "
+		"add  %4,%%eax ; "
+		"adc  %5,%%edx ; "
+		: "=A" (product), "=r" (tmp1), "=r" (tmp2)
+		: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif __x86_64__
+	__asm__ (
+		"mul %%rdx ; shrd $32,%%rdx,%%rax"
+		: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+	return product;
+}
+
+static u64 pvclock_get_nsec_offset(struct pvclock_shadow_time *shadow)
+{
+	u64 delta = native_read_tsc() - shadow->tsc_timestamp;
+	return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+}
+
+/*
+ * Reads a consistent set of time-base values from hypervisor,
+ * into a shadow data area.
+ */
+static unsigned pvclock_get_time_values(struct pvclock_shadow_time *dst,
+					struct pvclock_vcpu_time_info *src)
+{
+	do {
+		dst->version = src->version;
+		rmb();		/* fetch version before data */
+		dst->tsc_timestamp     = src->tsc_timestamp;
+		dst->system_timestamp  = src->system_time;
+		dst->tsc_to_nsec_mul   = src->tsc_to_system_mul;
+		dst->tsc_shift         = src->tsc_shift;
+		rmb();		/* test version after fetching data */
+	} while ((src->version & 1) || (dst->version != src->version));
+
+	return dst->version;
+}
+
+cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
+{
+	struct pvclock_shadow_time shadow;
+	unsigned version;
+	cycle_t ret, offset;
+
+	do {
+		version = pvclock_get_time_values(&shadow, src);
+		barrier();
+		offset = pvclock_get_nsec_offset(&shadow);
+		ret = shadow.system_timestamp + offset;
+		barrier();
+	} while (version != src->version);
+
+	return ret;
+}
+
+void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
+			    struct pvclock_vcpu_time_info *vcpu_time,
+			    struct timespec *ts)
+{
+	u32 version;
+	u64 delta;
+	struct timespec now;
+
+	/* get wallclock at system boot */
+	do {
+		version = wall_clock->version;
+		rmb();		/* fetch version before time */
+		now.tv_sec  = wall_clock->sec;
+		now.tv_nsec = wall_clock->nsec;
+		rmb();		/* fetch time before checking version */
+	} while ((wall_clock->version & 1) || (version != wall_clock->version));
+
+	delta = pvclock_clocksource_read(vcpu_time);	/* time since system boot */
+	delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
+
+	now.tv_nsec = do_div(delta, NSEC_PER_SEC);
+	now.tv_sec = delta;
+
+	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+}
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index f2f5d26..3829aa7 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -200,9 +200,12 @@
 
 	atomic_inc(&pt->pending);
 	smp_mb__after_atomic_inc();
-	if (vcpu0 && waitqueue_active(&vcpu0->wq)) {
-		vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
-		wake_up_interruptible(&vcpu0->wq);
+	if (vcpu0) {
+		set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
+		if (waitqueue_active(&vcpu0->wq)) {
+			vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+			wake_up_interruptible(&vcpu0->wq);
+		}
 	}
 
 	pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index c297c50..ebc03f5 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -940,6 +940,7 @@
 	wait_queue_head_t *q = &apic->vcpu->wq;
 
 	atomic_inc(&apic->timer.pending);
+	set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
 	if (waitqueue_active(q)) {
 		apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 		wake_up_interruptible(q);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index ee3f530..7e7c396 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -640,6 +640,7 @@
 			rmap_remove(kvm, spte);
 			--kvm->stat.lpages;
 			set_shadow_pte(spte, shadow_trap_nonpresent_pte);
+			spte = NULL;
 			write_protected = 1;
 		}
 		spte = rmap_next(kvm, rmapp, spte);
@@ -1082,10 +1083,6 @@
 		struct kvm_mmu_page *shadow;
 
 		spte |= PT_WRITABLE_MASK;
-		if (user_fault) {
-			mmu_unshadow(vcpu->kvm, gfn);
-			goto unshadowed;
-		}
 
 		shadow = kvm_mmu_lookup_page(vcpu->kvm, gfn);
 		if (shadow ||
@@ -1102,8 +1099,6 @@
 		}
 	}
 
-unshadowed:
-
 	if (pte_access & ACC_WRITE_MASK)
 		mark_page_dirty(vcpu->kvm, gfn);
 
@@ -1580,11 +1575,13 @@
 				  u64 *spte,
 				  const void *new)
 {
-	if ((sp->role.level != PT_PAGE_TABLE_LEVEL)
-	    && !vcpu->arch.update_pte.largepage) {
-		++vcpu->kvm->stat.mmu_pde_zapped;
-		return;
-	}
+	if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
+		if (!vcpu->arch.update_pte.largepage ||
+		    sp->role.glevels == PT32_ROOT_LEVEL) {
+			++vcpu->kvm->stat.mmu_pde_zapped;
+			return;
+		}
+        }
 
 	++vcpu->kvm->stat.mmu_pte_updated;
 	if (sp->role.glevels == PT32_ROOT_LEVEL)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 02efbe7..540e951 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -566,7 +566,7 @@
 	load_transition_efer(vmx);
 }
 
-static void vmx_load_host_state(struct vcpu_vmx *vmx)
+static void __vmx_load_host_state(struct vcpu_vmx *vmx)
 {
 	unsigned long flags;
 
@@ -596,6 +596,13 @@
 	reload_host_efer(vmx);
 }
 
+static void vmx_load_host_state(struct vcpu_vmx *vmx)
+{
+	preempt_disable();
+	__vmx_load_host_state(vmx);
+	preempt_enable();
+}
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -654,7 +661,7 @@
 
 static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
 {
-	vmx_load_host_state(to_vmx(vcpu));
+	__vmx_load_host_state(to_vmx(vcpu));
 }
 
 static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -884,11 +891,8 @@
 	switch (msr_index) {
 #ifdef CONFIG_X86_64
 	case MSR_EFER:
+		vmx_load_host_state(vmx);
 		ret = kvm_set_msr_common(vcpu, msr_index, data);
-		if (vmx->host_state.loaded) {
-			reload_host_efer(vmx);
-			load_transition_efer(vmx);
-		}
 		break;
 	case MSR_FS_BASE:
 		vmcs_writel(GUEST_FS_BASE, data);
@@ -910,11 +914,10 @@
 		guest_write_tsc(data);
 		break;
 	default:
+		vmx_load_host_state(vmx);
 		msr = find_msr_entry(vmx, msr_index);
 		if (msr) {
 			msr->data = data;
-			if (vmx->host_state.loaded)
-				load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
 			break;
 		}
 		ret = kvm_set_msr_common(vcpu, msr_index, data);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 00acf13..63a77ca 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -492,8 +492,8 @@
 static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
 {
 	static int version;
-	struct kvm_wall_clock wc;
-	struct timespec wc_ts;
+	struct pvclock_wall_clock wc;
+	struct timespec now, sys, boot;
 
 	if (!wall_clock)
 		return;
@@ -502,10 +502,19 @@
 
 	kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
 
-	wc_ts = current_kernel_time();
-	wc.wc_sec = wc_ts.tv_sec;
-	wc.wc_nsec = wc_ts.tv_nsec;
-	wc.wc_version = version;
+	/*
+	 * The guest calculates current wall clock time by adding
+	 * system time (updated by kvm_write_guest_time below) to the
+	 * wall clock specified here.  guest system time equals host
+	 * system time for us, thus we must fill in host boot time here.
+	 */
+	now = current_kernel_time();
+	ktime_get_ts(&sys);
+	boot = ns_to_timespec(timespec_to_ns(&now) - timespec_to_ns(&sys));
+
+	wc.sec = boot.tv_sec;
+	wc.nsec = boot.tv_nsec;
+	wc.version = version;
 
 	kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
 
@@ -513,6 +522,45 @@
 	kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
 }
 
+static uint32_t div_frac(uint32_t dividend, uint32_t divisor)
+{
+	uint32_t quotient, remainder;
+
+	/* Don't try to replace with do_div(), this one calculates
+	 * "(dividend << 32) / divisor" */
+	__asm__ ( "divl %4"
+		  : "=a" (quotient), "=d" (remainder)
+		  : "0" (0), "1" (dividend), "r" (divisor) );
+	return quotient;
+}
+
+static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *hv_clock)
+{
+	uint64_t nsecs = 1000000000LL;
+	int32_t  shift = 0;
+	uint64_t tps64;
+	uint32_t tps32;
+
+	tps64 = tsc_khz * 1000LL;
+	while (tps64 > nsecs*2) {
+		tps64 >>= 1;
+		shift--;
+	}
+
+	tps32 = (uint32_t)tps64;
+	while (tps32 <= (uint32_t)nsecs) {
+		tps32 <<= 1;
+		shift++;
+	}
+
+	hv_clock->tsc_shift = shift;
+	hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
+
+	pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
+		 __FUNCTION__, tsc_khz, hv_clock->tsc_shift,
+		 hv_clock->tsc_to_system_mul);
+}
+
 static void kvm_write_guest_time(struct kvm_vcpu *v)
 {
 	struct timespec ts;
@@ -523,6 +571,11 @@
 	if ((!vcpu->time_page))
 		return;
 
+	if (unlikely(vcpu->hv_clock_tsc_khz != tsc_khz)) {
+		kvm_set_time_scale(tsc_khz, &vcpu->hv_clock);
+		vcpu->hv_clock_tsc_khz = tsc_khz;
+	}
+
 	/* Keep irq disabled to prevent changes to the clock */
 	local_irq_save(flags);
 	kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER,
@@ -537,14 +590,14 @@
 	/*
 	 * The interface expects us to write an even number signaling that the
 	 * update is finished. Since the guest won't see the intermediate
-	 * state, we just write "2" at the end
+	 * state, we just increase by 2 at the end.
 	 */
-	vcpu->hv_clock.version = 2;
+	vcpu->hv_clock.version += 2;
 
 	shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0);
 
 	memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock,
-		sizeof(vcpu->hv_clock));
+	       sizeof(vcpu->hv_clock));
 
 	kunmap_atomic(shared_kaddr, KM_USER0);
 
@@ -599,10 +652,6 @@
 		/* ...but clean it before doing the actual write */
 		vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);
 
-		vcpu->arch.hv_clock.tsc_to_system_mul =
-					clocksource_khz2mult(tsc_khz, 22);
-		vcpu->arch.hv_clock.tsc_shift = 22;
-
 		down_read(&current->mm->mmap_sem);
 		vcpu->arch.time_page =
 				gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
@@ -2759,6 +2808,8 @@
 	if (vcpu->requests) {
 		if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests))
 			__kvm_migrate_timers(vcpu);
+		if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
+			kvm_x86_ops->tlb_flush(vcpu);
 		if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
 				       &vcpu->requests)) {
 			kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS;
@@ -2772,6 +2823,7 @@
 		}
 	}
 
+	clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
 	kvm_inject_pending_timer_irqs(vcpu);
 
 	preempt_disable();
@@ -2781,21 +2833,13 @@
 
 	local_irq_disable();
 
-	if (need_resched()) {
+	if (vcpu->requests || need_resched()) {
 		local_irq_enable();
 		preempt_enable();
 		r = 1;
 		goto out;
 	}
 
-	if (vcpu->requests)
-		if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) {
-			local_irq_enable();
-			preempt_enable();
-			r = 1;
-			goto out;
-		}
-
 	if (signal_pending(current)) {
 		local_irq_enable();
 		preempt_enable();
@@ -2825,9 +2869,6 @@
 
 	kvm_guest_enter();
 
-	if (vcpu->requests)
-		if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
-			kvm_x86_ops->tlb_flush(vcpu);
 
 	KVMTRACE_0D(VMENTRY, vcpu, entryexit);
 	kvm_x86_ops->run(vcpu, kvm_run);
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 525b108..6c388e5 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -5,6 +5,7 @@
 config XEN
 	bool "Xen guest support"
 	select PARAVIRT
+	select PARAVIRT_CLOCK
 	depends on X86_32
 	depends on X86_CMPXCHG && X86_TSC && X86_PAE && !(X86_VISWS || X86_VOYAGER)
 	help
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 52b2e38..41e2175 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -14,6 +14,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/math64.h>
 
+#include <asm/pvclock.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
@@ -31,17 +32,6 @@
 
 static cycle_t xen_clocksource_read(void);
 
-/* These are perodically updated in shared_info, and then copied here. */
-struct shadow_time_info {
-	u64 tsc_timestamp;     /* TSC at last update of time vals.  */
-	u64 system_timestamp;  /* Time, in nanosecs, since boot.    */
-	u32 tsc_to_nsec_mul;
-	int tsc_shift;
-	u32 version;
-};
-
-static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
-
 /* runstate info updated by Xen */
 static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
 
@@ -211,7 +201,7 @@
 unsigned long xen_cpu_khz(void)
 {
 	u64 xen_khz = 1000000ULL << 32;
-	const struct vcpu_time_info *info =
+	const struct pvclock_vcpu_time_info *info =
 		&HYPERVISOR_shared_info->vcpu_info[0].time;
 
 	do_div(xen_khz, info->tsc_to_system_mul);
@@ -223,121 +213,26 @@
 	return xen_khz;
 }
 
-/*
- * Reads a consistent set of time-base values from Xen, into a shadow data
- * area.
- */
-static unsigned get_time_values_from_xen(void)
-{
-	struct vcpu_time_info   *src;
-	struct shadow_time_info *dst;
-
-	/* src is shared memory with the hypervisor, so we need to
-	   make sure we get a consistent snapshot, even in the face of
-	   being preempted. */
-	src = &__get_cpu_var(xen_vcpu)->time;
-	dst = &__get_cpu_var(shadow_time);
-
-	do {
-		dst->version = src->version;
-		rmb();		/* fetch version before data */
-		dst->tsc_timestamp     = src->tsc_timestamp;
-		dst->system_timestamp  = src->system_time;
-		dst->tsc_to_nsec_mul   = src->tsc_to_system_mul;
-		dst->tsc_shift         = src->tsc_shift;
-		rmb();		/* test version after fetching data */
-	} while ((src->version & 1) | (dst->version ^ src->version));
-
-	return dst->version;
-}
-
-/*
- * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
- * yielding a 64-bit result.
- */
-static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
-{
-	u64 product;
-#ifdef __i386__
-	u32 tmp1, tmp2;
-#endif
-
-	if (shift < 0)
-		delta >>= -shift;
-	else
-		delta <<= shift;
-
-#ifdef __i386__
-	__asm__ (
-		"mul  %5       ; "
-		"mov  %4,%%eax ; "
-		"mov  %%edx,%4 ; "
-		"mul  %5       ; "
-		"xor  %5,%5    ; "
-		"add  %4,%%eax ; "
-		"adc  %5,%%edx ; "
-		: "=A" (product), "=r" (tmp1), "=r" (tmp2)
-		: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
-#elif __x86_64__
-	__asm__ (
-		"mul %%rdx ; shrd $32,%%rdx,%%rax"
-		: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
-#else
-#error implement me!
-#endif
-
-	return product;
-}
-
-static u64 get_nsec_offset(struct shadow_time_info *shadow)
-{
-	u64 now, delta;
-	now = native_read_tsc();
-	delta = now - shadow->tsc_timestamp;
-	return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
-}
-
 static cycle_t xen_clocksource_read(void)
 {
-	struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
+        struct pvclock_vcpu_time_info *src;
 	cycle_t ret;
-	unsigned version;
 
-	do {
-		version = get_time_values_from_xen();
-		barrier();
-		ret = shadow->system_timestamp + get_nsec_offset(shadow);
-		barrier();
-	} while (version != __get_cpu_var(xen_vcpu)->time.version);
-
-	put_cpu_var(shadow_time);
-
+	src = &get_cpu_var(xen_vcpu)->time;
+	ret = pvclock_clocksource_read(src);
+	put_cpu_var(xen_vcpu);
 	return ret;
 }
 
 static void xen_read_wallclock(struct timespec *ts)
 {
-	const struct shared_info *s = HYPERVISOR_shared_info;
-	u32 version;
-	u64 delta;
-	struct timespec now;
+	struct shared_info *s = HYPERVISOR_shared_info;
+	struct pvclock_wall_clock *wall_clock = &(s->wc);
+        struct pvclock_vcpu_time_info *vcpu_time;
 
-	/* get wallclock at system boot */
-	do {
-		version = s->wc_version;
-		rmb();		/* fetch version before time */
-		now.tv_sec  = s->wc_sec;
-		now.tv_nsec = s->wc_nsec;
-		rmb();		/* fetch time before checking version */
-	} while ((s->wc_version & 1) | (version ^ s->wc_version));
-
-	delta = xen_clocksource_read();	/* time since system boot */
-	delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
-
-	now.tv_nsec = do_div(delta, NSEC_PER_SEC);
-	now.tv_sec = delta;
-
-	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+	vcpu_time = &get_cpu_var(xen_vcpu)->time;
+	pvclock_read_wallclock(wall_clock, vcpu_time, ts);
+	put_cpu_var(xen_vcpu);
 }
 
 unsigned long xen_get_wallclock(void)
@@ -345,7 +240,6 @@
 	struct timespec ts;
 
 	xen_read_wallclock(&ts);
-
 	return ts.tv_sec;
 }
 
@@ -569,8 +463,6 @@
 {
 	int cpu = smp_processor_id();
 
-	get_time_values_from_xen();
-
 	clocksource_register(&xen_clocksource);
 
 	if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 8c39467..743f33a 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -831,6 +831,8 @@
 	}
 
 	if (ad->changed_batch && ad->nr_dispatched == 1) {
+		ad->current_batch_expires = jiffies +
+					ad->batch_expire[ad->batch_data_dir];
 		kblockd_schedule_work(&ad->antic_work);
 		ad->changed_batch = 0;
 
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 5b73f6a..831883b 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -233,6 +233,9 @@
 
 	device = ac->device;
 	switch (event) {
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Unsupported event [0x%x]\n", event));
 	case ACPI_AC_NOTIFY_STATUS:
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
@@ -244,11 +247,6 @@
 #ifdef CONFIG_ACPI_SYSFS_POWER
 		kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
 #endif
-		break;
-	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Unsupported event [0x%x]\n", event));
-		break;
 	}
 
 	return;
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 26038c2..61b6c5b 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -377,6 +377,9 @@
 
 	INIT_LIST_HEAD(&drive_bays);
 
+	if (acpi_disabled)
+		return -ENODEV;
+
 	/* look for dockable drive bays */
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 		ACPI_UINT32_MAX, find_bay, &bays, NULL);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 96c542f..bb7c51f 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -917,6 +917,9 @@
 
 	dock_station = NULL;
 
+	if (acpi_disabled)
+		return 0;
+
 	/* look for a dock station */
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 			    ACPI_UINT32_MAX, find_dock, &num, NULL);
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 2808dc6..9b227d4 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -333,6 +333,9 @@
 {
 	struct device *dev = get_rtc_dev();
 
+	if (acpi_disabled)
+		return 0;
+
 	if (dev) {
 		rtc_wake_setup();
 		rtc_info.wake_on = rtc_wake_on;
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 224c57c..4ebbba2 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -315,8 +315,11 @@
 		cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control);
 	if (acpi_gbl_FADT.month_alarm)
 		cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control);
-	if (acpi_gbl_FADT.century)
+	if (acpi_gbl_FADT.century) {
+		if (adjust)
+			yr += cmos_bcd_read(acpi_gbl_FADT.century, rtc_control) * 100;
 		cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control);
+	}
 	/* enable the rtc alarm interrupt */
 	rtc_control |= RTC_AIE;
 	CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 5e5dda3a..d089c45 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1713,7 +1713,8 @@
 
 		status = acpi_video_bus_get_one_device(dev, video);
 		if (ACPI_FAILURE(status)) {
-			ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+					"Cant attach device"));
 			continue;
 		}
 	}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 9bf2986..ae84949 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -651,9 +651,17 @@
 	  Support for the Winbond W83759A controller on Vesa Local Bus
 	  systems.
 
+config HAVE_PATA_PLATFORM
+	bool
+	help
+	  This is an internal configuration node for any machine that
+	  uses pata-platform driver to enable the relevant driver in the
+	  configuration structure without having to submit endless patches
+	  to update the PATA_PLATFORM entry.
+
 config PATA_PLATFORM
 	tristate "Generic platform device PATA support"
-	depends on EMBEDDED || ARCH_RPC || PPC
+	depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM
 	help
 	  This option enables support for generic directly connected ATA
 	  devices commonly found on embedded systems.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 966ab40..061817a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -90,6 +90,7 @@
 	board_ahci_mv		= 4,
 	board_ahci_sb700	= 5,
 	board_ahci_mcp65	= 6,
+	board_ahci_nopmp	= 7,
 
 	/* global controller registers */
 	HOST_CAP		= 0x00, /* host capabilities */
@@ -401,6 +402,14 @@
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
+	/* board_ahci_nopmp */
+	{
+		AHCI_HFLAGS	(AHCI_HFLAG_NO_PMP),
+		.flags		= AHCI_FLAG_COMMON,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &ahci_ops,
+	},
 };
 
 static const struct pci_device_id ahci_pci_tbl[] = {
@@ -525,9 +534,9 @@
 	{ PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci },		/* MCP7B */
 
 	/* SiS */
-	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
-	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
-	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+	{ PCI_VDEVICE(SI, 0x1184), board_ahci_nopmp },		/* SiS 966 */
+	{ PCI_VDEVICE(SI, 0x1185), board_ahci_nopmp },		/* SiS 968 */
+	{ PCI_VDEVICE(SI, 0x0186), board_ahci_nopmp },		/* SiS 968 */
 
 	/* Marvell */
 	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
@@ -653,6 +662,14 @@
 		cap &= ~HOST_CAP_PMP;
 	}
 
+	if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
+	    port_map != 1) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			   "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
+			   port_map, 1);
+		port_map = 1;
+	}
+
 	/*
 	 * Temporary Marvell 6145 hack: PATA port presence
 	 * is asserted through the standard AHCI port
@@ -1760,7 +1777,7 @@
 	struct ahci_host_priv *hpriv;
 	unsigned int i, handled = 0;
 	void __iomem *mmio;
-	u32 irq_stat, irq_ack = 0;
+	u32 irq_stat;
 
 	VPRINTK("ENTER\n");
 
@@ -1792,14 +1809,11 @@
 					"interrupt on disabled port %u\n", i);
 		}
 
-		irq_ack |= (1 << i);
-	}
-
-	if (irq_ack) {
-		writel(irq_ack, mmio + HOST_IRQ_STAT);
 		handled = 1;
 	}
 
+	writel(irq_stat, mmio + HOST_IRQ_STAT);
+
 	spin_unlock(&host->lock);
 
 	VPRINTK("EXIT\n");
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 81b7ae3..a90ae03 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1043,6 +1043,13 @@
 			},
 		},
 		{
+			.ident = "TECRA M4",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M4"),
+			},
+		},
+		{
 			.ident = "TECRA M5",
 			.matches = {
 				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index cc816ca..303fc0d 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4297,7 +4297,7 @@
 }
 
 /**
- *	ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ *	atapi_check_dma - Check whether ATAPI DMA can be supported
  *	@qc: Metadata associated with taskfile to check
  *
  *	Allow low-level driver to filter ATA PACKET commands, returning
@@ -4310,7 +4310,7 @@
  *	RETURNS: 0 when ATAPI DMA can be used
  *               nonzero otherwise
  */
-int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+int atapi_check_dma(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 2e6e162..57a4364 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2343,8 +2343,8 @@
 {
 	struct scsi_cmnd *scmd = qc->scsicmd;
 	struct ata_device *dev = qc->dev;
-	int using_pio = (dev->flags & ATA_DFLAG_PIO);
 	int nodata = (scmd->sc_data_direction == DMA_NONE);
+	int using_pio = !nodata && (dev->flags & ATA_DFLAG_PIO);
 	unsigned int nbytes;
 
 	memset(qc->cdb, 0, dev->cdb_len);
@@ -2362,7 +2362,7 @@
 	ata_qc_set_pc_nbytes(qc);
 
 	/* check whether ATAPI DMA is safe */
-	if (!using_pio && ata_check_atapi_dma(qc))
+	if (!nodata && !using_pio && atapi_check_dma(qc))
 		using_pio = 1;
 
 	/* Some controller variants snoop this value for Packet
@@ -2402,13 +2402,11 @@
 	qc->tf.lbam = (nbytes & 0xFF);
 	qc->tf.lbah = (nbytes >> 8);
 
-	if (using_pio || nodata) {
-		/* no data, or PIO data xfer */
-		if (nodata)
-			qc->tf.protocol = ATAPI_PROT_NODATA;
-		else
-			qc->tf.protocol = ATAPI_PROT_PIO;
-	} else {
+	if (nodata)
+		qc->tf.protocol = ATAPI_PROT_NODATA;
+	else if (using_pio)
+		qc->tf.protocol = ATAPI_PROT_PIO;
+	else {
 		/* DMA data xfer */
 		qc->tf.protocol = ATAPI_PROT_DMA;
 		qc->tf.feature |= ATAPI_PKT_DMA;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 215d186..c0908c2 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1094,6 +1094,7 @@
 int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
 		     u8 status, int in_wq)
 {
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	unsigned long flags = 0;
 	int poll_next;
 
@@ -1125,9 +1126,12 @@
 			if (likely(status & (ATA_ERR | ATA_DF)))
 				/* device stops HSM for abort/error */
 				qc->err_mask |= AC_ERR_DEV;
-			else
+			else {
 				/* HSM violation. Let EH handle this */
+				ata_ehi_push_desc(ehi,
+					"ST_FIRST: !(DRQ|ERR|DF)");
 				qc->err_mask |= AC_ERR_HSM;
+			}
 
 			ap->hsm_task_state = HSM_ST_ERR;
 			goto fsm_start;
@@ -1146,9 +1150,9 @@
 			 * the CDB.
 			 */
 			if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
-				ata_port_printk(ap, KERN_WARNING,
-						"DRQ=1 with device error, "
-						"dev_stat 0x%X\n", status);
+				ata_ehi_push_desc(ehi, "ST_FIRST: "
+					"DRQ=1 with device error, "
+					"dev_stat 0x%X", status);
 				qc->err_mask |= AC_ERR_HSM;
 				ap->hsm_task_state = HSM_ST_ERR;
 				goto fsm_start;
@@ -1205,9 +1209,9 @@
 			 * let the EH abort the command or reset the device.
 			 */
 			if (unlikely(status & (ATA_ERR | ATA_DF))) {
-				ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
-						"device error, dev_stat 0x%X\n",
-						status);
+				ata_ehi_push_desc(ehi, "ST-ATAPI: "
+					"DRQ=1 with device error, "
+					"dev_stat 0x%X", status);
 				qc->err_mask |= AC_ERR_HSM;
 				ap->hsm_task_state = HSM_ST_ERR;
 				goto fsm_start;
@@ -1226,13 +1230,17 @@
 				if (likely(status & (ATA_ERR | ATA_DF)))
 					/* device stops HSM for abort/error */
 					qc->err_mask |= AC_ERR_DEV;
-				else
+				else {
 					/* HSM violation. Let EH handle this.
 					 * Phantom devices also trigger this
 					 * condition.  Mark hint.
 					 */
+					ata_ehi_push_desc(ehi, "ST-ATA: "
+						"DRQ=1 with device error, "
+						"dev_stat 0x%X", status);
 					qc->err_mask |= AC_ERR_HSM |
 							AC_ERR_NODEV_HINT;
+				}
 
 				ap->hsm_task_state = HSM_ST_ERR;
 				goto fsm_start;
@@ -1257,8 +1265,12 @@
 					status = ata_wait_idle(ap);
 				}
 
-				if (status & (ATA_BUSY | ATA_DRQ))
+				if (status & (ATA_BUSY | ATA_DRQ)) {
+					ata_ehi_push_desc(ehi, "ST-ATA: "
+						"BUSY|DRQ persists on ERR|DF, "
+						"dev_stat 0x%X", status);
 					qc->err_mask |= AC_ERR_HSM;
+				}
 
 				/* ata_pio_sectors() might change the
 				 * state to HSM_ST_LAST. so, the state
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4514283..1cf803a 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -106,7 +106,7 @@
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
 extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+extern int atapi_check_dma(struct ata_queued_cmd *qc);
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
 extern void ata_dev_init(struct ata_device *dev);
 extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 3d39f9d..41b4361 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -414,6 +414,7 @@
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
 	PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
+	PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
 	PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
 	PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
@@ -424,6 +425,7 @@
 	PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
 	PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
+	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 60391e9..ad169ff 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -1322,6 +1322,9 @@
 		goto out_port_free_dma_mem;
 	memset(pp->crpb, 0, MV_CRPB_Q_SZ);
 
+	/* 6041/6081 Rev. "C0" (and newer) are okay with async notify */
+	if (hpriv->hp_flags & MV_HP_ERRATA_60X1C0)
+		ap->flags |= ATA_FLAG_AN;
 	/*
 	 * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
 	 * For later hardware, we need one unique sg_tbl per NCQ tag.
@@ -1592,6 +1595,24 @@
 
 	if ((qc->tf.protocol != ATA_PROT_DMA) &&
 	    (qc->tf.protocol != ATA_PROT_NCQ)) {
+		static int limit_warnings = 10;
+		/*
+		 * Errata SATA#16, SATA#24: warn if multiple DRQs expected.
+		 *
+		 * Someday, we might implement special polling workarounds
+		 * for these, but it all seems rather unnecessary since we
+		 * normally use only DMA for commands which transfer more
+		 * than a single block of data.
+		 *
+		 * Much of the time, this could just work regardless.
+		 * So for now, just log the incident, and allow the attempt.
+		 */
+		if (limit_warnings > 0 && (qc->nbytes / qc->sect_size) > 1) {
+			--limit_warnings;
+			ata_link_printk(qc->dev->link, KERN_WARNING, DRV_NAME
+					": attempting PIO w/multiple DRQ: "
+					"this may fail due to h/w errata\n");
+		}
 		/*
 		 * We're about to send a non-EDMA capable command to the
 		 * port.  Turn off EDMA so there won't be problems accessing
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 8ee6b5b..84ffcc2 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -370,6 +370,7 @@
 	{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
 	{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
 	{ PCI_VDEVICE(CMD, 0x0242), BID_SIL3132 },
+	{ PCI_VDEVICE(CMD, 0x0244), BID_SIL3132 },
 	{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
 	{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
 
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index f277cea..db529b8 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -83,6 +83,7 @@
 	.inherits		= &ata_bmdma_port_ops,
 	.scr_read		= uli_scr_read,
 	.scr_write		= uli_scr_write,
+	.hardreset		= ATA_OP_NULL,
 };
 
 static const struct ata_port_info uli_port_info = {
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 043353b..14b9d5f 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -64,7 +64,7 @@
 	  Amount of time the ks0108 should wait between each control write
 	  to the parallel port.
 
-	  If your driver seems to miss random writings, increment this.
+	  If your LCD seems to miss random writings, increment this.
 
 	  If you don't know what I'm talking about, ignore it.
 
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c
index 80bb061..683509f 100644
--- a/drivers/auxdisplay/cfag12864b.c
+++ b/drivers/auxdisplay/cfag12864b.c
@@ -5,7 +5,7 @@
  *     License: GPLv2
  *     Depends: ks0108
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -398,5 +398,5 @@
 module_exit(cfag12864b_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 MODULE_DESCRIPTION("cfag12864b LCD driver");
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
index 307c190..fe3a865 100644
--- a/drivers/auxdisplay/cfag12864bfb.c
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -5,7 +5,7 @@
  *     License: GPLv2
  *     Depends: cfag12864b
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -186,5 +186,5 @@
 module_exit(cfag12864bfb_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver");
diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c
index e6c3646..5b93852 100644
--- a/drivers/auxdisplay/ks0108.c
+++ b/drivers/auxdisplay/ks0108.c
@@ -5,7 +5,7 @@
  *     License: GPLv2
  *     Depends: parport
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -173,6 +173,6 @@
 module_exit(ks0108_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 MODULE_DESCRIPTION("ks0108 LCD Controller driver");
 
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 39f3d1b..0f867a0 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -84,8 +84,8 @@
 		       nid, K(i.totalram),
 		       nid, K(i.freeram),
 		       nid, K(i.totalram - i.freeram),
-		       nid, node_page_state(nid, NR_ACTIVE),
-		       nid, node_page_state(nid, NR_INACTIVE),
+		       nid, K(node_page_state(nid, NR_ACTIVE)),
+		       nid, K(node_page_state(nid, NR_INACTIVE)),
 #ifdef CONFIG_HIGHMEM
 		       nid, K(i.totalhigh),
 		       nid, K(i.freehigh),
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 5f1e1cc..d81632c 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -106,35 +106,34 @@
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
  *  access = Address of the struct of function pointers
- *  nr_cmds = Number of commands supported by controller
  */
 static struct board_type products[] = {
-	{0x40700E11, "Smart Array 5300", &SA5_access, 512},
-	{0x40800E11, "Smart Array 5i", &SA5B_access, 512},
-	{0x40820E11, "Smart Array 532", &SA5B_access, 512},
-	{0x40830E11, "Smart Array 5312", &SA5B_access, 512},
-	{0x409A0E11, "Smart Array 641", &SA5_access, 512},
-	{0x409B0E11, "Smart Array 642", &SA5_access, 512},
-	{0x409C0E11, "Smart Array 6400", &SA5_access, 512},
-	{0x409D0E11, "Smart Array 6400 EM", &SA5_access, 512},
-	{0x40910E11, "Smart Array 6i", &SA5_access, 512},
-	{0x3225103C, "Smart Array P600", &SA5_access, 512},
-	{0x3223103C, "Smart Array P800", &SA5_access, 512},
-	{0x3234103C, "Smart Array P400", &SA5_access, 512},
-	{0x3235103C, "Smart Array P400i", &SA5_access, 512},
-	{0x3211103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3212103C, "Smart Array E200", &SA5_access, 120},
-	{0x3213103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3214103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3215103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3237103C, "Smart Array E500", &SA5_access, 512},
-	{0x323D103C, "Smart Array P700m", &SA5_access, 512},
-	{0x3241103C, "Smart Array P212", &SA5_access, 384},
-	{0x3243103C, "Smart Array P410", &SA5_access, 384},
-	{0x3245103C, "Smart Array P410i", &SA5_access, 384},
-	{0x3247103C, "Smart Array P411", &SA5_access, 384},
-	{0x3249103C, "Smart Array P812", &SA5_access, 384},
-	{0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
+	{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},
+	{0x3237103C, "Smart Array E500", &SA5_access},
+	{0x323D103C, "Smart Array P700m", &SA5_access},
+	{0x3241103C, "Smart Array P212", &SA5_access},
+	{0x3243103C, "Smart Array P410", &SA5_access},
+	{0x3245103C, "Smart Array P410i", &SA5_access},
+	{0x3247103C, "Smart Array P411", &SA5_access},
+	{0x3249103C, "Smart Array P812", &SA5_access},
+	{0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -3086,11 +3085,20 @@
 	print_cfg_table(c->cfgtable);
 #endif				/* CCISS_DEBUG */
 
+	/* Some controllers support Zero Memory Raid (ZMR).
+	 * When configured in ZMR mode the number of supported
+	 * commands drops to 64. So instead of just setting an
+	 * arbitrary value we make the driver a little smarter.
+	 * We read the config table to tell us how many commands
+	 * are supported on the controller then subtract 4 to
+	 * leave a little room for ioctl calls.
+	 */
+	c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
 	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);
-			c->nr_cmds = products[i].nr_cmds;
+			c->nr_cmds = c->max_commands - 4;
 			break;
 		}
 	}
@@ -3110,7 +3118,7 @@
 		if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
 			c->product_name = products[i-1].product_name;
 			c->access = *(products[i-1].access);
-			c->nr_cmds = products[i-1].nr_cmds;
+			c->nr_cmds = c->max_commands - 4;
 			printk(KERN_WARNING "cciss: This is an unknown "
 				"Smart Array controller.\n"
 				"cciss: Please update to the latest driver "
@@ -3546,6 +3554,10 @@
 	for (j = 0; j <= hba[i]->highest_lun; j++)
 		add_disk(hba[i]->gendisk[j]);
 
+	/* we must register the controller even if no disks exist */
+	if (hba[i]->highest_lun == -1)
+		add_disk(hba[i]->gendisk[0]);
+
 	return 1;
 
       clean4:
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 1ae64bb..df70264 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -948,7 +948,7 @@
 	intel_private.ifp_resource.flags = IORESOURCE_MEM;
 
 	/* Setup chipset flush for 915 */
-	if (IS_I965 || IS_G33) {
+	if (IS_I965 || IS_G33 || IS_G4X) {
 		intel_i965_g33_setup_chipset_flush();
 	} else {
 		intel_i915_setup_chipset_flush();
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index b710426..c533d0c 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -76,7 +76,7 @@
 		for (i = 0; i < pages; i++) {
 			if (!entry->busaddr[i])
 				break;
-			pci_unmap_single(dev->pdev, entry->busaddr[i],
+			pci_unmap_page(dev->pdev, entry->busaddr[i],
 					 PAGE_SIZE, PCI_DMA_TODEVICE);
 		}
 
@@ -137,10 +137,8 @@
 
 	for (i = 0; i < pages; i++) {
 		/* we need to support large memory configurations */
-		entry->busaddr[i] = pci_map_single(dev->pdev,
-						   page_address(entry->
-								pagelist[i]),
-						   PAGE_SIZE, PCI_DMA_TODEVICE);
+		entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
+						 0, PAGE_SIZE, PCI_DMA_TODEVICE);
 		if (entry->busaddr[i] == 0) {
 			DRM_ERROR("unable to map PCIGART pages!\n");
 			drm_ati_pcigart_cleanup(dev, gart_info);
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 3a05c6d..38d3c6b 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -628,7 +628,7 @@
 #define DRM_IOCTL_AGP_BIND		DRM_IOW( 0x36, struct drm_agp_binding)
 #define DRM_IOCTL_AGP_UNBIND		DRM_IOW( 0x37, struct drm_agp_binding)
 
-#define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, struct drm_scatter_gather)
+#define DRM_IOCTL_SG_ALLOC		DRM_IOWR(0x38, struct drm_scatter_gather)
 #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, struct drm_scatter_gather)
 
 #define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, union drm_wait_vblank)
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index fc54140..5641387 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -470,17 +470,18 @@
 	if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
 	    (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
 		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
-	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
+	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
 		ioctl = &drm_ioctls[nr];
-	else
+		cmd = ioctl->cmd;
+	} else
 		goto err_i1;
 
+	/* Do not trust userspace, use our own definition */
 	func = ioctl->func;
 	/* is there a local override? */
 	if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
 		func = dev->driver->dma_ioctl;
 
-
 	if (!func) {
 		DRM_DEBUG("no function\n");
 		retcode = -EINVAL;
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index a6a499f..135bd19 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -103,20 +103,18 @@
 	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
 	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
-	{0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-	{0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-	{0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-	{0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+	{0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+	{0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+	{0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+	{0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-	{0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-	{0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
-	{0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+	{0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+	{0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
 	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
 	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
@@ -411,4 +409,7 @@
 	{0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2e02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2e12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x2e22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0, 0, 0}
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index e8f3d68..93aed1c 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -389,6 +389,7 @@
 	pci_restore_state(dev->pdev);
 	if (pci_enable_device(dev->pdev))
 		return -1;
+	pci_set_master(dev->pdev);
 
 	pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
 
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 1b20f7c..d7326d9 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -1112,12 +1112,19 @@
 		       (dev)->pci_device == 0x29A2 || \
 		       (dev)->pci_device == 0x2A02 || \
 		       (dev)->pci_device == 0x2A12 || \
-		       (dev)->pci_device == 0x2A42)
+		       (dev)->pci_device == 0x2A42 || \
+		       (dev)->pci_device == 0x2E02 || \
+		       (dev)->pci_device == 0x2E12 || \
+		       (dev)->pci_device == 0x2E22)
 
 #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
 
 #define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42)
 
+#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
+		     (dev)->pci_device == 0x2E12 || \
+		     (dev)->pci_device == 0x2E22)
+
 #define IS_G33(dev)    ((dev)->pci_device == 0x29C2 ||	\
 			(dev)->pci_device == 0x29B2 ||	\
 			(dev)->pci_device == 0x29D2)
@@ -1128,7 +1135,7 @@
 #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
 			IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev))
 
-#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev))
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index f7f16e7..df03611 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -62,11 +62,11 @@
 	u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
 	RING_LOCALS;
 
-	if (sarea_priv->front_tiled) {
+	if (IS_I965G(dev) && sarea_priv->front_tiled) {
 		cmd |= XY_SRC_COPY_BLT_DST_TILED;
 		dst_pitch >>= 2;
 	}
-	if (sarea_priv->back_tiled) {
+	if (IS_I965G(dev) && sarea_priv->back_tiled) {
 		cmd |= XY_SRC_COPY_BLT_SRC_TILED;
 		src_pitch >>= 2;
 	}
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index f535812..702df45 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -189,18 +189,12 @@
 	ADD_RANGE(R300_RE_CULL_CNTL, 1);
 	ADD_RANGE(0x42C0, 2);
 	ADD_RANGE(R300_RS_CNTL_0, 2);
-	ADD_RANGE(R300_RS_INTERP_0, 8);
-	ADD_RANGE(R300_RS_ROUTE_0, 8);
-	ADD_RANGE(0x43A4, 2);
+
+	ADD_RANGE(R300_SC_HYPERZ, 2);
 	ADD_RANGE(0x43E8, 1);
-	ADD_RANGE(R300_PFS_CNTL_0, 3);
-	ADD_RANGE(R300_PFS_NODE_0, 4);
-	ADD_RANGE(R300_PFS_TEXI_0, 64);
+
 	ADD_RANGE(0x46A4, 5);
-	ADD_RANGE(R300_PFS_INSTR0_0, 64);
-	ADD_RANGE(R300_PFS_INSTR1_0, 64);
-	ADD_RANGE(R300_PFS_INSTR2_0, 64);
-	ADD_RANGE(R300_PFS_INSTR3_0, 64);
+
 	ADD_RANGE(R300_RE_FOG_STATE, 1);
 	ADD_RANGE(R300_FOG_COLOR_R, 3);
 	ADD_RANGE(R300_PP_ALPHA_TEST, 2);
@@ -215,14 +209,12 @@
 	ADD_RANGE(0x4E50, 9);
 	ADD_RANGE(0x4E88, 1);
 	ADD_RANGE(0x4EA0, 2);
-	ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);
-	ADD_RANGE(R300_RB3D_ZSTENCIL_FORMAT, 4);
-	ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET);	/* check offset */
-	ADD_RANGE(R300_RB3D_DEPTHPITCH, 1);
-	ADD_RANGE(0x4F28, 1);
-	ADD_RANGE(0x4F30, 2);
-	ADD_RANGE(0x4F44, 1);
-	ADD_RANGE(0x4F54, 1);
+	ADD_RANGE(R300_ZB_CNTL, 3);
+	ADD_RANGE(R300_ZB_FORMAT, 4);
+	ADD_RANGE_MARK(R300_ZB_DEPTHOFFSET, 1, MARK_CHECK_OFFSET);	/* check offset */
+	ADD_RANGE(R300_ZB_DEPTHPITCH, 1);
+	ADD_RANGE(R300_ZB_DEPTHCLEARVALUE, 1);
+	ADD_RANGE(R300_ZB_ZMASK_OFFSET, 13);
 
 	ADD_RANGE(R300_TX_FILTER_0, 16);
 	ADD_RANGE(R300_TX_FILTER1_0, 16);
@@ -235,13 +227,32 @@
 	ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
 
 	/* Sporadic registers used as primitives are emitted */
-	ADD_RANGE(R300_RB3D_ZCACHE_CTLSTAT, 1);
+	ADD_RANGE(R300_ZB_ZCACHE_CTLSTAT, 1);
 	ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
 	ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
 	ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
 
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
-		ADD_RANGE(0x4074, 16);
+		ADD_RANGE(R500_VAP_INDEX_OFFSET, 1);
+		ADD_RANGE(R500_US_CONFIG, 2);
+		ADD_RANGE(R500_US_CODE_ADDR, 3);
+		ADD_RANGE(R500_US_FC_CTRL, 1);
+		ADD_RANGE(R500_RS_IP_0, 16);
+		ADD_RANGE(R500_RS_INST_0, 16);
+		ADD_RANGE(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2);
+		ADD_RANGE(R500_RB3D_CONSTANT_COLOR_AR, 2);
+		ADD_RANGE(R500_ZB_FIFO_SIZE, 2);
+	} else {
+		ADD_RANGE(R300_PFS_CNTL_0, 3);
+		ADD_RANGE(R300_PFS_NODE_0, 4);
+		ADD_RANGE(R300_PFS_TEXI_0, 64);
+		ADD_RANGE(R300_PFS_INSTR0_0, 64);
+		ADD_RANGE(R300_PFS_INSTR1_0, 64);
+		ADD_RANGE(R300_PFS_INSTR2_0, 64);
+		ADD_RANGE(R300_PFS_INSTR3_0, 64);
+		ADD_RANGE(R300_RS_INTERP_0, 8);
+		ADD_RANGE(R300_RS_ROUTE_0, 8);
+
 	}
 }
 
@@ -707,8 +718,9 @@
 	BEGIN_RING(6);
 	OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
 	OUT_RING(R300_RB3D_DSTCACHE_UNKNOWN_0A);
-	OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
-	OUT_RING(R300_RB3D_ZCACHE_UNKNOWN_03);
+	OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0));
+	OUT_RING(R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE|
+		 R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE);
 	OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0));
 	OUT_RING(0x0);
 	ADVANCE_RING();
@@ -829,6 +841,54 @@
 }
 
 /**
+ * Uploads user-supplied vertex program instructions or parameters onto
+ * the graphics card.
+ * Called by r300_do_cp_cmdbuf.
+ */
+static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
+				       drm_radeon_kcmd_buffer_t *cmdbuf,
+				       drm_r300_cmd_header_t header)
+{
+	int sz;
+	int addr;
+	int type;
+	int clamp;
+	int stride;
+	RING_LOCALS;
+
+	sz = header.r500fp.count;
+	/* address is 9 bits 0 - 8, bit 1 of flags is part of address */
+	addr = ((header.r500fp.adrhi_flags & 1) << 8) | header.r500fp.adrlo;
+
+	type = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_TYPE);
+	clamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
+
+	addr |= (type << 16);
+	addr |= (clamp << 17);
+
+	stride = type ? 4 : 6;
+
+	DRM_DEBUG("r500fp %d %d type: %d\n", sz, addr, type);
+	if (!sz)
+		return 0;
+	if (sz * stride * 4 > cmdbuf->bufsz)
+		return -EINVAL;
+
+	BEGIN_RING(3 + sz * stride);
+	OUT_RING_REG(R500_GA_US_VECTOR_INDEX, addr);
+	OUT_RING(CP_PACKET0_TABLE(R500_GA_US_VECTOR_DATA, sz * stride - 1));
+	OUT_RING_TABLE((int *)cmdbuf->buf, sz * stride);
+
+	ADVANCE_RING();
+
+	cmdbuf->buf += sz * stride * 4;
+	cmdbuf->bufsz -= sz * stride * 4;
+
+	return 0;
+}
+
+
+/**
  * Parses and validates a user-supplied command buffer and emits appropriate
  * commands on the DMA ring buffer.
  * Called by the ioctl handler function radeon_cp_cmdbuf.
@@ -963,6 +1023,19 @@
 			}
 			break;
 
+		case R300_CMD_R500FP:
+			if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
+				DRM_ERROR("Calling r500 command on r300 card\n");
+				ret = -EINVAL;
+				goto cleanup;
+			}
+			DRM_DEBUG("R300_CMD_R500FP\n");
+			ret = r300_emit_r500fp(dev_priv, cmdbuf, header);
+			if (ret) {
+				DRM_ERROR("r300_emit_r500fp failed\n");
+				goto cleanup;
+			}
+			break;
 		default:
 			DRM_ERROR("bad cmd_type %i at %p\n",
 				  header.header.cmd_type,
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index 8f664af..a6802f2 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -702,6 +702,27 @@
 #		define R300_RS_ROUTE_1_UNKNOWN11         (1 << 11)
 /* END: Rasterization / Interpolators - many guesses */
 
+/* Hierarchical Z Enable */
+#define R300_SC_HYPERZ                   0x43a4
+#	define R300_SC_HYPERZ_DISABLE     (0 << 0)
+#	define R300_SC_HYPERZ_ENABLE      (1 << 0)
+#	define R300_SC_HYPERZ_MIN         (0 << 1)
+#	define R300_SC_HYPERZ_MAX         (1 << 1)
+#	define R300_SC_HYPERZ_ADJ_256     (0 << 2)
+#	define R300_SC_HYPERZ_ADJ_128     (1 << 2)
+#	define R300_SC_HYPERZ_ADJ_64      (2 << 2)
+#	define R300_SC_HYPERZ_ADJ_32      (3 << 2)
+#	define R300_SC_HYPERZ_ADJ_16      (4 << 2)
+#	define R300_SC_HYPERZ_ADJ_8       (5 << 2)
+#	define R300_SC_HYPERZ_ADJ_4       (6 << 2)
+#	define R300_SC_HYPERZ_ADJ_2       (7 << 2)
+#	define R300_SC_HYPERZ_HZ_Z0MIN_NO (0 << 5)
+#	define R300_SC_HYPERZ_HZ_Z0MIN    (1 << 5)
+#	define R300_SC_HYPERZ_HZ_Z0MAX_NO (0 << 6)
+#	define R300_SC_HYPERZ_HZ_Z0MAX    (1 << 6)
+
+#define R300_SC_EDGERULE                 0x43a8
+
 /* BEGIN: Scissors and cliprects */
 
 /* There are four clipping rectangles. Their corner coordinates are inclusive.
@@ -1346,7 +1367,7 @@
 /* Guess by Vladimir.
  * Set to 0A before 3D operations, set to 02 afterwards.
  */
-#define R300_RB3D_DSTCACHE_CTLSTAT          0x4E4C
+/*#define R300_RB3D_DSTCACHE_CTLSTAT          0x4E4C*/
 #       define R300_RB3D_DSTCACHE_UNKNOWN_02             0x00000002
 #       define R300_RB3D_DSTCACHE_UNKNOWN_0A             0x0000000A
 
@@ -1355,19 +1376,14 @@
  * for this.
  * Bit (1<<8) is the "test" bit. so plain write is 6  - vd
  */
-#define R300_RB3D_ZSTENCIL_CNTL_0                   0x4F00
-#       define R300_RB3D_Z_DISABLED_1            0x00000010
-#       define R300_RB3D_Z_DISABLED_2            0x00000014
-#       define R300_RB3D_Z_TEST                  0x00000012
-#       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
-#       define R300_RB3D_Z_WRITE_ONLY		 0x00000006
+#define R300_ZB_CNTL                             0x4F00
+#	define R300_STENCIL_ENABLE		 (1 << 0)
+#	define R300_Z_ENABLE		         (1 << 1)
+#	define R300_Z_WRITE_ENABLE		 (1 << 2)
+#	define R300_Z_SIGNED_COMPARE		 (1 << 3)
+#	define R300_STENCIL_FRONT_BACK		 (1 << 4)
 
-#       define R300_RB3D_Z_TEST                  0x00000012
-#       define R300_RB3D_Z_TEST_AND_WRITE        0x00000016
-#       define R300_RB3D_Z_WRITE_ONLY		 0x00000006
-#	define R300_RB3D_STENCIL_ENABLE		 0x00000001
-
-#define R300_RB3D_ZSTENCIL_CNTL_1                   0x4F04
+#define R300_ZB_ZSTENCILCNTL                   0x4f04
 	/* functions */
 #	define R300_ZS_NEVER			0
 #	define R300_ZS_LESS			1
@@ -1387,52 +1403,166 @@
 #	define R300_ZS_INVERT			5
 #	define R300_ZS_INCR_WRAP		6
 #	define R300_ZS_DECR_WRAP		7
+#	define R300_Z_FUNC_SHIFT		0
 	/* front and back refer to operations done for front
 	   and back faces, i.e. separate stencil function support */
-#	define R300_RB3D_ZS1_DEPTH_FUNC_SHIFT		0
-#	define R300_RB3D_ZS1_FRONT_FUNC_SHIFT		3
-#	define R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT	6
-#	define R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT	9
-#	define R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT      12
-#	define R300_RB3D_ZS1_BACK_FUNC_SHIFT           15
-#	define R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT        18
-#	define R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT       21
-#	define R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT       24
+#	define R300_S_FRONT_FUNC_SHIFT	        3
+#	define R300_S_FRONT_SFAIL_OP_SHIFT	6
+#	define R300_S_FRONT_ZPASS_OP_SHIFT	9
+#	define R300_S_FRONT_ZFAIL_OP_SHIFT      12
+#	define R300_S_BACK_FUNC_SHIFT           15
+#	define R300_S_BACK_SFAIL_OP_SHIFT       18
+#	define R300_S_BACK_ZPASS_OP_SHIFT       21
+#	define R300_S_BACK_ZFAIL_OP_SHIFT       24
 
-#define R300_RB3D_ZSTENCIL_CNTL_2                   0x4F08
-#	define R300_RB3D_ZS2_STENCIL_REF_SHIFT		0
-#	define R300_RB3D_ZS2_STENCIL_MASK		0xFF
-#	define R300_RB3D_ZS2_STENCIL_MASK_SHIFT	        8
-#	define R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT	16
+#define R300_ZB_STENCILREFMASK                        0x4f08
+#	define R300_STENCILREF_SHIFT       0
+#	define R300_STENCILREF_MASK        0x000000ff
+#	define R300_STENCILMASK_SHIFT      8
+#	define R300_STENCILMASK_MASK       0x0000ff00
+#	define R300_STENCILWRITEMASK_SHIFT 16
+#	define R300_STENCILWRITEMASK_MASK  0x00ff0000
 
 /* gap */
 
-#define R300_RB3D_ZSTENCIL_FORMAT                   0x4F10
-#	define R300_DEPTH_FORMAT_16BIT_INT_Z     (0 << 0)
-#	define R300_DEPTH_FORMAT_24BIT_INT_Z     (2 << 0)
-	/* 16 bit format or some aditional bit ? */
-#	define R300_DEPTH_FORMAT_UNK32          (32 << 0)
+#define R300_ZB_FORMAT                             0x4f10
+#	define R300_DEPTHFORMAT_16BIT_INT_Z   (0 << 0)
+#	define R300_DEPTHFORMAT_16BIT_13E3    (1 << 0)
+#	define R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL   (2 << 0)
+/* reserved up to (15 << 0) */
+#	define R300_INVERT_13E3_LEADING_ONES  (0 << 4)
+#	define R300_INVERT_13E3_LEADING_ZEROS (1 << 4)
 
-#define R300_RB3D_EARLY_Z                           0x4F14
-#	define R300_EARLY_Z_DISABLE              (0 << 0)
-#	define R300_EARLY_Z_ENABLE               (1 << 0)
+#define R300_ZB_ZTOP                             0x4F14
+#	define R300_ZTOP_DISABLE                 (0 << 0)
+#	define R300_ZTOP_ENABLE                  (1 << 0)
 
 /* gap */
 
-#define R300_RB3D_ZCACHE_CTLSTAT            0x4F18 /* GUESS */
-#       define R300_RB3D_ZCACHE_UNKNOWN_01  0x1
-#       define R300_RB3D_ZCACHE_UNKNOWN_03  0x3
+#define R300_ZB_ZCACHE_CTLSTAT            0x4f18
+#       define R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_NO_EFFECT      (0 << 0)
+#       define R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE (1 << 0)
+#       define R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_NO_EFFECT       (0 << 1)
+#       define R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE            (1 << 1)
+#       define R300_ZB_ZCACHE_CTLSTAT_ZC_BUSY_IDLE            (0 << 31)
+#       define R300_ZB_ZCACHE_CTLSTAT_ZC_BUSY_BUSY            (1 << 31)
+
+#define R300_ZB_BW_CNTL                     0x4f1c
+#	define R300_HIZ_DISABLE                              (0 << 0)
+#	define R300_HIZ_ENABLE                               (1 << 0)
+#	define R300_HIZ_MIN                                  (0 << 1)
+#	define R300_HIZ_MAX                                  (1 << 1)
+#	define R300_FAST_FILL_DISABLE                        (0 << 2)
+#	define R300_FAST_FILL_ENABLE                         (1 << 2)
+#	define R300_RD_COMP_DISABLE                          (0 << 3)
+#	define R300_RD_COMP_ENABLE                           (1 << 3)
+#	define R300_WR_COMP_DISABLE                          (0 << 4)
+#	define R300_WR_COMP_ENABLE                           (1 << 4)
+#	define R300_ZB_CB_CLEAR_RMW                          (0 << 5)
+#	define R300_ZB_CB_CLEAR_CACHE_LINEAR                 (1 << 5)
+#	define R300_FORCE_COMPRESSED_STENCIL_VALUE_DISABLE   (0 << 6)
+#	define R300_FORCE_COMPRESSED_STENCIL_VALUE_ENABLE    (1 << 6)
+
+#	define R500_ZEQUAL_OPTIMIZE_ENABLE                   (0 << 7)
+#	define R500_ZEQUAL_OPTIMIZE_DISABLE                  (1 << 7)
+#	define R500_SEQUAL_OPTIMIZE_ENABLE                   (0 << 8)
+#	define R500_SEQUAL_OPTIMIZE_DISABLE                  (1 << 8)
+
+#	define R500_BMASK_ENABLE                             (0 << 10)
+#	define R500_BMASK_DISABLE                            (1 << 10)
+#	define R500_HIZ_EQUAL_REJECT_DISABLE                 (0 << 11)
+#	define R500_HIZ_EQUAL_REJECT_ENABLE                  (1 << 11)
+#	define R500_HIZ_FP_EXP_BITS_DISABLE                  (0 << 12)
+#	define R500_HIZ_FP_EXP_BITS_1                        (1 << 12)
+#	define R500_HIZ_FP_EXP_BITS_2                        (2 << 12)
+#	define R500_HIZ_FP_EXP_BITS_3                        (3 << 12)
+#	define R500_HIZ_FP_EXP_BITS_4                        (4 << 12)
+#	define R500_HIZ_FP_EXP_BITS_5                        (5 << 12)
+#	define R500_HIZ_FP_INVERT_LEADING_ONES               (0 << 15)
+#	define R500_HIZ_FP_INVERT_LEADING_ZEROS              (1 << 15)
+#	define R500_TILE_OVERWRITE_RECOMPRESSION_ENABLE      (0 << 16)
+#	define R500_TILE_OVERWRITE_RECOMPRESSION_DISABLE     (1 << 16)
+#	define R500_CONTIGUOUS_6XAA_SAMPLES_ENABLE           (0 << 17)
+#	define R500_CONTIGUOUS_6XAA_SAMPLES_DISABLE          (1 << 17)
+#	define R500_PEQ_PACKING_DISABLE                      (0 << 18)
+#	define R500_PEQ_PACKING_ENABLE                       (1 << 18)
+#	define R500_COVERED_PTR_MASKING_DISABLE              (0 << 18)
+#	define R500_COVERED_PTR_MASKING_ENABLE               (1 << 18)
+
 
 /* gap */
 
-#define R300_RB3D_DEPTHOFFSET               0x4F20
-#define R300_RB3D_DEPTHPITCH                0x4F24
-#       define R300_DEPTHPITCH_MASK              0x00001FF8 /* GUESS */
-#       define R300_DEPTH_TILE_ENABLE            (1 << 16) /* GUESS */
-#       define R300_DEPTH_MICROTILE_ENABLE       (1 << 17) /* GUESS */
-#       define R300_DEPTH_ENDIAN_NO_SWAP         (0 << 18) /* GUESS */
-#       define R300_DEPTH_ENDIAN_WORD_SWAP       (1 << 18) /* GUESS */
-#       define R300_DEPTH_ENDIAN_DWORD_SWAP      (2 << 18) /* GUESS */
+/* Z Buffer Address Offset.
+ * Bits 31 to 5 are used for aligned Z buffer address offset for macro tiles.
+ */
+#define R300_ZB_DEPTHOFFSET               0x4f20
+
+/* Z Buffer Pitch and Endian Control */
+#define R300_ZB_DEPTHPITCH                0x4f24
+#       define R300_DEPTHPITCH_MASK              0x00003FFC
+#       define R300_DEPTHMACROTILE_DISABLE      (0 << 16)
+#       define R300_DEPTHMACROTILE_ENABLE       (1 << 16)
+#       define R300_DEPTHMICROTILE_LINEAR       (0 << 17)
+#       define R300_DEPTHMICROTILE_TILED        (1 << 17)
+#       define R300_DEPTHMICROTILE_TILED_SQUARE (2 << 17)
+#       define R300_DEPTHENDIAN_NO_SWAP         (0 << 18)
+#       define R300_DEPTHENDIAN_WORD_SWAP       (1 << 18)
+#       define R300_DEPTHENDIAN_DWORD_SWAP      (2 << 18)
+#       define R300_DEPTHENDIAN_HALF_DWORD_SWAP (3 << 18)
+
+/* Z Buffer Clear Value */
+#define R300_ZB_DEPTHCLEARVALUE                  0x4f28
+
+#define R300_ZB_ZMASK_OFFSET			 0x4f30
+#define R300_ZB_ZMASK_PITCH			 0x4f34
+#define R300_ZB_ZMASK_WRINDEX			 0x4f38
+#define R300_ZB_ZMASK_DWORD			 0x4f3c
+#define R300_ZB_ZMASK_RDINDEX			 0x4f40
+
+/* Hierarchical Z Memory Offset */
+#define R300_ZB_HIZ_OFFSET                       0x4f44
+
+/* Hierarchical Z Write Index */
+#define R300_ZB_HIZ_WRINDEX                      0x4f48
+
+/* Hierarchical Z Data */
+#define R300_ZB_HIZ_DWORD                        0x4f4c
+
+/* Hierarchical Z Read Index */
+#define R300_ZB_HIZ_RDINDEX                      0x4f50
+
+/* Hierarchical Z Pitch */
+#define R300_ZB_HIZ_PITCH                        0x4f54
+
+/* Z Buffer Z Pass Counter Data */
+#define R300_ZB_ZPASS_DATA                       0x4f58
+
+/* Z Buffer Z Pass Counter Address */
+#define R300_ZB_ZPASS_ADDR                       0x4f5c
+
+/* Depth buffer X and Y coordinate offset */
+#define R300_ZB_DEPTHXY_OFFSET                   0x4f60
+#	define R300_DEPTHX_OFFSET_SHIFT  1
+#	define R300_DEPTHX_OFFSET_MASK   0x000007FE
+#	define R300_DEPTHY_OFFSET_SHIFT  17
+#	define R300_DEPTHY_OFFSET_MASK   0x07FE0000
+
+/* Sets the fifo sizes */
+#define R500_ZB_FIFO_SIZE                        0x4fd0
+#	define R500_OP_FIFO_SIZE_FULL   (0 << 0)
+#	define R500_OP_FIFO_SIZE_HALF   (1 << 0)
+#	define R500_OP_FIFO_SIZE_QUATER (2 << 0)
+#	define R500_OP_FIFO_SIZE_EIGTHS (4 << 0)
+
+/* Stencil Reference Value and Mask for backfacing quads */
+/* R300_ZB_STENCILREFMASK handles front face */
+#define R500_ZB_STENCILREFMASK_BF                0x4fd4
+#	define R500_STENCILREF_SHIFT       0
+#	define R500_STENCILREF_MASK        0x000000ff
+#	define R500_STENCILMASK_SHIFT      8
+#	define R500_STENCILMASK_MASK       0x0000ff00
+#	define R500_STENCILWRITEMASK_SHIFT 16
+#	define R500_STENCILWRITEMASK_MASK  0x00ff0000
 
 /* BEGIN: Vertex program instruction set */
 
@@ -1623,4 +1753,20 @@
  */
 #define R300_CP_CMD_BITBLT_MULTI	0xC0009B00
 
+#define R500_VAP_INDEX_OFFSET		0x208c
+
+#define R500_GA_US_VECTOR_INDEX         0x4250
+#define R500_GA_US_VECTOR_DATA          0x4254
+
+#define R500_RS_IP_0                    0x4074
+#define R500_RS_INST_0                  0x4320
+
+#define R500_US_CONFIG                  0x4600
+
+#define R500_US_FC_CTRL			0x4624
+#define R500_US_CODE_ADDR		0x4630
+
+#define R500_RB3D_COLOR_CLEAR_VALUE_AR  0x46c0
+#define R500_RB3D_CONSTANT_COLOR_AR     0x4ef8
+
 #endif /* _R300_REG_H */
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index f6f6c92..e53158f 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -2,6 +2,7 @@
 /*
  * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
  * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
+ * Copyright 2007 Advanced Micro Devices, Inc.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,789 +35,13 @@
 #include "radeon_drv.h"
 #include "r300_reg.h"
 
+#include "radeon_microcode.h"
+
 #define RADEON_FIFO_DEBUG	0
 
 static int radeon_do_cleanup_cp(struct drm_device * dev);
 
-/* CP microcode (from ATI) */
-static const u32 R200_cp_microcode[][2] = {
-	{0x21007000, 0000000000},
-	{0x20007000, 0000000000},
-	{0x000000ab, 0x00000004},
-	{0x000000af, 0x00000004},
-	{0x66544a49, 0000000000},
-	{0x49494174, 0000000000},
-	{0x54517d83, 0000000000},
-	{0x498d8b64, 0000000000},
-	{0x49494949, 0000000000},
-	{0x49da493c, 0000000000},
-	{0x49989898, 0000000000},
-	{0xd34949d5, 0000000000},
-	{0x9dc90e11, 0000000000},
-	{0xce9b9b9b, 0000000000},
-	{0x000f0000, 0x00000016},
-	{0x352e232c, 0000000000},
-	{0x00000013, 0x00000004},
-	{0x000f0000, 0x00000016},
-	{0x352e272c, 0000000000},
-	{0x000f0001, 0x00000016},
-	{0x3239362f, 0000000000},
-	{0x000077ef, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x00000020, 0x0000001a},
-	{0x00004000, 0x0000001e},
-	{0x00061000, 0x00000002},
-	{0x00000020, 0x0000001a},
-	{0x00004000, 0x0000001e},
-	{0x00061000, 0x00000002},
-	{0x00000020, 0x0000001a},
-	{0x00004000, 0x0000001e},
-	{0x00000016, 0x00000004},
-	{0x0003802a, 0x00000002},
-	{0x040067e0, 0x00000002},
-	{0x00000016, 0x00000004},
-	{0x000077e0, 0x00000002},
-	{0x00065000, 0x00000002},
-	{0x000037e1, 0x00000002},
-	{0x040067e1, 0x00000006},
-	{0x000077e0, 0x00000002},
-	{0x000077e1, 0x00000002},
-	{0x000077e1, 0x00000006},
-	{0xffffffff, 0000000000},
-	{0x10000000, 0000000000},
-	{0x0003802a, 0x00000002},
-	{0x040067e0, 0x00000006},
-	{0x00007675, 0x00000002},
-	{0x00007676, 0x00000002},
-	{0x00007677, 0x00000002},
-	{0x00007678, 0x00000006},
-	{0x0003802b, 0x00000002},
-	{0x04002676, 0x00000002},
-	{0x00007677, 0x00000002},
-	{0x00007678, 0x00000006},
-	{0x0000002e, 0x00000018},
-	{0x0000002e, 0x00000018},
-	{0000000000, 0x00000006},
-	{0x0000002f, 0x00000018},
-	{0x0000002f, 0x00000018},
-	{0000000000, 0x00000006},
-	{0x01605000, 0x00000002},
-	{0x00065000, 0x00000002},
-	{0x00098000, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x64c0603d, 0x00000004},
-	{0x00080000, 0x00000016},
-	{0000000000, 0000000000},
-	{0x0400251d, 0x00000002},
-	{0x00007580, 0x00000002},
-	{0x00067581, 0x00000002},
-	{0x04002580, 0x00000002},
-	{0x00067581, 0x00000002},
-	{0x00000046, 0x00000004},
-	{0x00005000, 0000000000},
-	{0x00061000, 0x00000002},
-	{0x0000750e, 0x00000002},
-	{0x00019000, 0x00000002},
-	{0x00011055, 0x00000014},
-	{0x00000055, 0x00000012},
-	{0x0400250f, 0x00000002},
-	{0x0000504a, 0x00000004},
-	{0x00007565, 0x00000002},
-	{0x00007566, 0x00000002},
-	{0x00000051, 0x00000004},
-	{0x01e655b4, 0x00000002},
-	{0x4401b0dc, 0x00000002},
-	{0x01c110dc, 0x00000002},
-	{0x2666705d, 0x00000018},
-	{0x040c2565, 0x00000002},
-	{0x0000005d, 0x00000018},
-	{0x04002564, 0x00000002},
-	{0x00007566, 0x00000002},
-	{0x00000054, 0x00000004},
-	{0x00401060, 0x00000008},
-	{0x00101000, 0x00000002},
-	{0x000d80ff, 0x00000002},
-	{0x00800063, 0x00000008},
-	{0x000f9000, 0x00000002},
-	{0x000e00ff, 0x00000002},
-	{0000000000, 0x00000006},
-	{0x00000080, 0x00000018},
-	{0x00000054, 0x00000004},
-	{0x00007576, 0x00000002},
-	{0x00065000, 0x00000002},
-	{0x00009000, 0x00000002},
-	{0x00041000, 0x00000002},
-	{0x0c00350e, 0x00000002},
-	{0x00049000, 0x00000002},
-	{0x00051000, 0x00000002},
-	{0x01e785f8, 0x00000002},
-	{0x00200000, 0x00000002},
-	{0x00600073, 0x0000000c},
-	{0x00007563, 0x00000002},
-	{0x006075f0, 0x00000021},
-	{0x20007068, 0x00000004},
-	{0x00005068, 0x00000004},
-	{0x00007576, 0x00000002},
-	{0x00007577, 0x00000002},
-	{0x0000750e, 0x00000002},
-	{0x0000750f, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00600076, 0x0000000c},
-	{0x006075f0, 0x00000021},
-	{0x000075f8, 0x00000002},
-	{0x00000076, 0x00000004},
-	{0x000a750e, 0x00000002},
-	{0x0020750f, 0x00000002},
-	{0x00600079, 0x00000004},
-	{0x00007570, 0x00000002},
-	{0x00007571, 0x00000002},
-	{0x00007572, 0x00000006},
-	{0x00005000, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00007568, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x00000084, 0x0000000c},
-	{0x00058000, 0x00000002},
-	{0x0c607562, 0x00000002},
-	{0x00000086, 0x00000004},
-	{0x00600085, 0x00000004},
-	{0x400070dd, 0000000000},
-	{0x000380dd, 0x00000002},
-	{0x00000093, 0x0000001c},
-	{0x00065095, 0x00000018},
-	{0x040025bb, 0x00000002},
-	{0x00061096, 0x00000018},
-	{0x040075bc, 0000000000},
-	{0x000075bb, 0x00000002},
-	{0x000075bc, 0000000000},
-	{0x00090000, 0x00000006},
-	{0x00090000, 0x00000002},
-	{0x000d8002, 0x00000006},
-	{0x00005000, 0x00000002},
-	{0x00007821, 0x00000002},
-	{0x00007800, 0000000000},
-	{0x00007821, 0x00000002},
-	{0x00007800, 0000000000},
-	{0x01665000, 0x00000002},
-	{0x000a0000, 0x00000002},
-	{0x000671cc, 0x00000002},
-	{0x0286f1cd, 0x00000002},
-	{0x000000a3, 0x00000010},
-	{0x21007000, 0000000000},
-	{0x000000aa, 0x0000001c},
-	{0x00065000, 0x00000002},
-	{0x000a0000, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x000b0000, 0x00000002},
-	{0x38067000, 0x00000002},
-	{0x000a00a6, 0x00000004},
-	{0x20007000, 0000000000},
-	{0x01200000, 0x00000002},
-	{0x20077000, 0x00000002},
-	{0x01200000, 0x00000002},
-	{0x20007000, 0000000000},
-	{0x00061000, 0x00000002},
-	{0x0120751b, 0x00000002},
-	{0x8040750a, 0x00000002},
-	{0x8040750b, 0x00000002},
-	{0x00110000, 0x00000002},
-	{0x000380dd, 0x00000002},
-	{0x000000bd, 0x0000001c},
-	{0x00061096, 0x00000018},
-	{0x844075bd, 0x00000002},
-	{0x00061095, 0x00000018},
-	{0x840075bb, 0x00000002},
-	{0x00061096, 0x00000018},
-	{0x844075bc, 0x00000002},
-	{0x000000c0, 0x00000004},
-	{0x804075bd, 0x00000002},
-	{0x800075bb, 0x00000002},
-	{0x804075bc, 0x00000002},
-	{0x00108000, 0x00000002},
-	{0x01400000, 0x00000002},
-	{0x006000c4, 0x0000000c},
-	{0x20c07000, 0x00000020},
-	{0x000000c6, 0x00000012},
-	{0x00800000, 0x00000006},
-	{0x0080751d, 0x00000006},
-	{0x000025bb, 0x00000002},
-	{0x000040c0, 0x00000004},
-	{0x0000775c, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00661000, 0x00000002},
-	{0x0460275d, 0x00000020},
-	{0x00004000, 0000000000},
-	{0x00007999, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00661000, 0x00000002},
-	{0x0460299b, 0x00000020},
-	{0x00004000, 0000000000},
-	{0x01e00830, 0x00000002},
-	{0x21007000, 0000000000},
-	{0x00005000, 0x00000002},
-	{0x00038042, 0x00000002},
-	{0x040025e0, 0x00000002},
-	{0x000075e1, 0000000000},
-	{0x00000001, 0000000000},
-	{0x000380d9, 0x00000002},
-	{0x04007394, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-};
-
-static const u32 radeon_cp_microcode[][2] = {
-	{0x21007000, 0000000000},
-	{0x20007000, 0000000000},
-	{0x000000b4, 0x00000004},
-	{0x000000b8, 0x00000004},
-	{0x6f5b4d4c, 0000000000},
-	{0x4c4c427f, 0000000000},
-	{0x5b568a92, 0000000000},
-	{0x4ca09c6d, 0000000000},
-	{0xad4c4c4c, 0000000000},
-	{0x4ce1af3d, 0000000000},
-	{0xd8afafaf, 0000000000},
-	{0xd64c4cdc, 0000000000},
-	{0x4cd10d10, 0000000000},
-	{0x000f0000, 0x00000016},
-	{0x362f242d, 0000000000},
-	{0x00000012, 0x00000004},
-	{0x000f0000, 0x00000016},
-	{0x362f282d, 0000000000},
-	{0x000380e7, 0x00000002},
-	{0x04002c97, 0x00000002},
-	{0x000f0001, 0x00000016},
-	{0x333a3730, 0000000000},
-	{0x000077ef, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x00000021, 0x0000001a},
-	{0x00004000, 0x0000001e},
-	{0x00061000, 0x00000002},
-	{0x00000021, 0x0000001a},
-	{0x00004000, 0x0000001e},
-	{0x00061000, 0x00000002},
-	{0x00000021, 0x0000001a},
-	{0x00004000, 0x0000001e},
-	{0x00000017, 0x00000004},
-	{0x0003802b, 0x00000002},
-	{0x040067e0, 0x00000002},
-	{0x00000017, 0x00000004},
-	{0x000077e0, 0x00000002},
-	{0x00065000, 0x00000002},
-	{0x000037e1, 0x00000002},
-	{0x040067e1, 0x00000006},
-	{0x000077e0, 0x00000002},
-	{0x000077e1, 0x00000002},
-	{0x000077e1, 0x00000006},
-	{0xffffffff, 0000000000},
-	{0x10000000, 0000000000},
-	{0x0003802b, 0x00000002},
-	{0x040067e0, 0x00000006},
-	{0x00007675, 0x00000002},
-	{0x00007676, 0x00000002},
-	{0x00007677, 0x00000002},
-	{0x00007678, 0x00000006},
-	{0x0003802c, 0x00000002},
-	{0x04002676, 0x00000002},
-	{0x00007677, 0x00000002},
-	{0x00007678, 0x00000006},
-	{0x0000002f, 0x00000018},
-	{0x0000002f, 0x00000018},
-	{0000000000, 0x00000006},
-	{0x00000030, 0x00000018},
-	{0x00000030, 0x00000018},
-	{0000000000, 0x00000006},
-	{0x01605000, 0x00000002},
-	{0x00065000, 0x00000002},
-	{0x00098000, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x64c0603e, 0x00000004},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00080000, 0x00000016},
-	{0000000000, 0000000000},
-	{0x0400251d, 0x00000002},
-	{0x00007580, 0x00000002},
-	{0x00067581, 0x00000002},
-	{0x04002580, 0x00000002},
-	{0x00067581, 0x00000002},
-	{0x00000049, 0x00000004},
-	{0x00005000, 0000000000},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x0000750e, 0x00000002},
-	{0x00019000, 0x00000002},
-	{0x00011055, 0x00000014},
-	{0x00000055, 0x00000012},
-	{0x0400250f, 0x00000002},
-	{0x0000504f, 0x00000004},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00007565, 0x00000002},
-	{0x00007566, 0x00000002},
-	{0x00000058, 0x00000004},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x01e655b4, 0x00000002},
-	{0x4401b0e4, 0x00000002},
-	{0x01c110e4, 0x00000002},
-	{0x26667066, 0x00000018},
-	{0x040c2565, 0x00000002},
-	{0x00000066, 0x00000018},
-	{0x04002564, 0x00000002},
-	{0x00007566, 0x00000002},
-	{0x0000005d, 0x00000004},
-	{0x00401069, 0x00000008},
-	{0x00101000, 0x00000002},
-	{0x000d80ff, 0x00000002},
-	{0x0080006c, 0x00000008},
-	{0x000f9000, 0x00000002},
-	{0x000e00ff, 0x00000002},
-	{0000000000, 0x00000006},
-	{0x0000008f, 0x00000018},
-	{0x0000005b, 0x00000004},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00007576, 0x00000002},
-	{0x00065000, 0x00000002},
-	{0x00009000, 0x00000002},
-	{0x00041000, 0x00000002},
-	{0x0c00350e, 0x00000002},
-	{0x00049000, 0x00000002},
-	{0x00051000, 0x00000002},
-	{0x01e785f8, 0x00000002},
-	{0x00200000, 0x00000002},
-	{0x0060007e, 0x0000000c},
-	{0x00007563, 0x00000002},
-	{0x006075f0, 0x00000021},
-	{0x20007073, 0x00000004},
-	{0x00005073, 0x00000004},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00007576, 0x00000002},
-	{0x00007577, 0x00000002},
-	{0x0000750e, 0x00000002},
-	{0x0000750f, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00600083, 0x0000000c},
-	{0x006075f0, 0x00000021},
-	{0x000075f8, 0x00000002},
-	{0x00000083, 0x00000004},
-	{0x000a750e, 0x00000002},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x0020750f, 0x00000002},
-	{0x00600086, 0x00000004},
-	{0x00007570, 0x00000002},
-	{0x00007571, 0x00000002},
-	{0x00007572, 0x00000006},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00005000, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00007568, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x00000095, 0x0000000c},
-	{0x00058000, 0x00000002},
-	{0x0c607562, 0x00000002},
-	{0x00000097, 0x00000004},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x00600096, 0x00000004},
-	{0x400070e5, 0000000000},
-	{0x000380e6, 0x00000002},
-	{0x040025c5, 0x00000002},
-	{0x000380e5, 0x00000002},
-	{0x000000a8, 0x0000001c},
-	{0x000650aa, 0x00000018},
-	{0x040025bb, 0x00000002},
-	{0x000610ab, 0x00000018},
-	{0x040075bc, 0000000000},
-	{0x000075bb, 0x00000002},
-	{0x000075bc, 0000000000},
-	{0x00090000, 0x00000006},
-	{0x00090000, 0x00000002},
-	{0x000d8002, 0x00000006},
-	{0x00007832, 0x00000002},
-	{0x00005000, 0x00000002},
-	{0x000380e7, 0x00000002},
-	{0x04002c97, 0x00000002},
-	{0x00007820, 0x00000002},
-	{0x00007821, 0x00000002},
-	{0x00007800, 0000000000},
-	{0x01200000, 0x00000002},
-	{0x20077000, 0x00000002},
-	{0x01200000, 0x00000002},
-	{0x20007000, 0x00000002},
-	{0x00061000, 0x00000002},
-	{0x0120751b, 0x00000002},
-	{0x8040750a, 0x00000002},
-	{0x8040750b, 0x00000002},
-	{0x00110000, 0x00000002},
-	{0x000380e5, 0x00000002},
-	{0x000000c6, 0x0000001c},
-	{0x000610ab, 0x00000018},
-	{0x844075bd, 0x00000002},
-	{0x000610aa, 0x00000018},
-	{0x840075bb, 0x00000002},
-	{0x000610ab, 0x00000018},
-	{0x844075bc, 0x00000002},
-	{0x000000c9, 0x00000004},
-	{0x804075bd, 0x00000002},
-	{0x800075bb, 0x00000002},
-	{0x804075bc, 0x00000002},
-	{0x00108000, 0x00000002},
-	{0x01400000, 0x00000002},
-	{0x006000cd, 0x0000000c},
-	{0x20c07000, 0x00000020},
-	{0x000000cf, 0x00000012},
-	{0x00800000, 0x00000006},
-	{0x0080751d, 0x00000006},
-	{0000000000, 0000000000},
-	{0x0000775c, 0x00000002},
-	{0x00a05000, 0x00000002},
-	{0x00661000, 0x00000002},
-	{0x0460275d, 0x00000020},
-	{0x00004000, 0000000000},
-	{0x01e00830, 0x00000002},
-	{0x21007000, 0000000000},
-	{0x6464614d, 0000000000},
-	{0x69687420, 0000000000},
-	{0x00000073, 0000000000},
-	{0000000000, 0000000000},
-	{0x00005000, 0x00000002},
-	{0x000380d0, 0x00000002},
-	{0x040025e0, 0x00000002},
-	{0x000075e1, 0000000000},
-	{0x00000001, 0000000000},
-	{0x000380e0, 0x00000002},
-	{0x04002394, 0x00000002},
-	{0x00005000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0x00000008, 0000000000},
-	{0x00000004, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-};
-
-static const u32 R300_cp_microcode[][2] = {
-	{0x4200e000, 0000000000},
-	{0x4000e000, 0000000000},
-	{0x000000af, 0x00000008},
-	{0x000000b3, 0x00000008},
-	{0x6c5a504f, 0000000000},
-	{0x4f4f497a, 0000000000},
-	{0x5a578288, 0000000000},
-	{0x4f91906a, 0000000000},
-	{0x4f4f4f4f, 0000000000},
-	{0x4fe24f44, 0000000000},
-	{0x4f9c9c9c, 0000000000},
-	{0xdc4f4fde, 0000000000},
-	{0xa1cd4f4f, 0000000000},
-	{0xd29d9d9d, 0000000000},
-	{0x4f0f9fd7, 0000000000},
-	{0x000ca000, 0x00000004},
-	{0x000d0012, 0x00000038},
-	{0x0000e8b4, 0x00000004},
-	{0x000d0014, 0x00000038},
-	{0x0000e8b6, 0x00000004},
-	{0x000d0016, 0x00000038},
-	{0x0000e854, 0x00000004},
-	{0x000d0018, 0x00000038},
-	{0x0000e855, 0x00000004},
-	{0x000d001a, 0x00000038},
-	{0x0000e856, 0x00000004},
-	{0x000d001c, 0x00000038},
-	{0x0000e857, 0x00000004},
-	{0x000d001e, 0x00000038},
-	{0x0000e824, 0x00000004},
-	{0x000d0020, 0x00000038},
-	{0x0000e825, 0x00000004},
-	{0x000d0022, 0x00000038},
-	{0x0000e830, 0x00000004},
-	{0x000d0024, 0x00000038},
-	{0x0000f0c0, 0x00000004},
-	{0x000d0026, 0x00000038},
-	{0x0000f0c1, 0x00000004},
-	{0x000d0028, 0x00000038},
-	{0x0000f041, 0x00000004},
-	{0x000d002a, 0x00000038},
-	{0x0000f184, 0x00000004},
-	{0x000d002c, 0x00000038},
-	{0x0000f185, 0x00000004},
-	{0x000d002e, 0x00000038},
-	{0x0000f186, 0x00000004},
-	{0x000d0030, 0x00000038},
-	{0x0000f187, 0x00000004},
-	{0x000d0032, 0x00000038},
-	{0x0000f180, 0x00000004},
-	{0x000d0034, 0x00000038},
-	{0x0000f393, 0x00000004},
-	{0x000d0036, 0x00000038},
-	{0x0000f38a, 0x00000004},
-	{0x000d0038, 0x00000038},
-	{0x0000f38e, 0x00000004},
-	{0x0000e821, 0x00000004},
-	{0x0140a000, 0x00000004},
-	{0x00000043, 0x00000018},
-	{0x00cce800, 0x00000004},
-	{0x001b0001, 0x00000004},
-	{0x08004800, 0x00000004},
-	{0x001b0001, 0x00000004},
-	{0x08004800, 0x00000004},
-	{0x001b0001, 0x00000004},
-	{0x08004800, 0x00000004},
-	{0x0000003a, 0x00000008},
-	{0x0000a000, 0000000000},
-	{0x02c0a000, 0x00000004},
-	{0x000ca000, 0x00000004},
-	{0x00130000, 0x00000004},
-	{0x000c2000, 0x00000004},
-	{0xc980c045, 0x00000008},
-	{0x2000451d, 0x00000004},
-	{0x0000e580, 0x00000004},
-	{0x000ce581, 0x00000004},
-	{0x08004580, 0x00000004},
-	{0x000ce581, 0x00000004},
-	{0x0000004c, 0x00000008},
-	{0x0000a000, 0000000000},
-	{0x000c2000, 0x00000004},
-	{0x0000e50e, 0x00000004},
-	{0x00032000, 0x00000004},
-	{0x00022056, 0x00000028},
-	{0x00000056, 0x00000024},
-	{0x0800450f, 0x00000004},
-	{0x0000a050, 0x00000008},
-	{0x0000e565, 0x00000004},
-	{0x0000e566, 0x00000004},
-	{0x00000057, 0x00000008},
-	{0x03cca5b4, 0x00000004},
-	{0x05432000, 0x00000004},
-	{0x00022000, 0x00000004},
-	{0x4ccce063, 0x00000030},
-	{0x08274565, 0x00000004},
-	{0x00000063, 0x00000030},
-	{0x08004564, 0x00000004},
-	{0x0000e566, 0x00000004},
-	{0x0000005a, 0x00000008},
-	{0x00802066, 0x00000010},
-	{0x00202000, 0x00000004},
-	{0x001b00ff, 0x00000004},
-	{0x01000069, 0x00000010},
-	{0x001f2000, 0x00000004},
-	{0x001c00ff, 0x00000004},
-	{0000000000, 0x0000000c},
-	{0x00000085, 0x00000030},
-	{0x0000005a, 0x00000008},
-	{0x0000e576, 0x00000004},
-	{0x000ca000, 0x00000004},
-	{0x00012000, 0x00000004},
-	{0x00082000, 0x00000004},
-	{0x1800650e, 0x00000004},
-	{0x00092000, 0x00000004},
-	{0x000a2000, 0x00000004},
-	{0x000f0000, 0x00000004},
-	{0x00400000, 0x00000004},
-	{0x00000079, 0x00000018},
-	{0x0000e563, 0x00000004},
-	{0x00c0e5f9, 0x000000c2},
-	{0x0000006e, 0x00000008},
-	{0x0000a06e, 0x00000008},
-	{0x0000e576, 0x00000004},
-	{0x0000e577, 0x00000004},
-	{0x0000e50e, 0x00000004},
-	{0x0000e50f, 0x00000004},
-	{0x0140a000, 0x00000004},
-	{0x0000007c, 0x00000018},
-	{0x00c0e5f9, 0x000000c2},
-	{0x0000007c, 0x00000008},
-	{0x0014e50e, 0x00000004},
-	{0x0040e50f, 0x00000004},
-	{0x00c0007f, 0x00000008},
-	{0x0000e570, 0x00000004},
-	{0x0000e571, 0x00000004},
-	{0x0000e572, 0x0000000c},
-	{0x0000a000, 0x00000004},
-	{0x0140a000, 0x00000004},
-	{0x0000e568, 0x00000004},
-	{0x000c2000, 0x00000004},
-	{0x00000089, 0x00000018},
-	{0x000b0000, 0x00000004},
-	{0x18c0e562, 0x00000004},
-	{0x0000008b, 0x00000008},
-	{0x00c0008a, 0x00000008},
-	{0x000700e4, 0x00000004},
-	{0x00000097, 0x00000038},
-	{0x000ca099, 0x00000030},
-	{0x080045bb, 0x00000004},
-	{0x000c209a, 0x00000030},
-	{0x0800e5bc, 0000000000},
-	{0x0000e5bb, 0x00000004},
-	{0x0000e5bc, 0000000000},
-	{0x00120000, 0x0000000c},
-	{0x00120000, 0x00000004},
-	{0x001b0002, 0x0000000c},
-	{0x0000a000, 0x00000004},
-	{0x0000e821, 0x00000004},
-	{0x0000e800, 0000000000},
-	{0x0000e821, 0x00000004},
-	{0x0000e82e, 0000000000},
-	{0x02cca000, 0x00000004},
-	{0x00140000, 0x00000004},
-	{0x000ce1cc, 0x00000004},
-	{0x050de1cd, 0x00000004},
-	{0x000000a7, 0x00000020},
-	{0x4200e000, 0000000000},
-	{0x000000ae, 0x00000038},
-	{0x000ca000, 0x00000004},
-	{0x00140000, 0x00000004},
-	{0x000c2000, 0x00000004},
-	{0x00160000, 0x00000004},
-	{0x700ce000, 0x00000004},
-	{0x001400aa, 0x00000008},
-	{0x4000e000, 0000000000},
-	{0x02400000, 0x00000004},
-	{0x400ee000, 0x00000004},
-	{0x02400000, 0x00000004},
-	{0x4000e000, 0000000000},
-	{0x000c2000, 0x00000004},
-	{0x0240e51b, 0x00000004},
-	{0x0080e50a, 0x00000005},
-	{0x0080e50b, 0x00000005},
-	{0x00220000, 0x00000004},
-	{0x000700e4, 0x00000004},
-	{0x000000c1, 0x00000038},
-	{0x000c209a, 0x00000030},
-	{0x0880e5bd, 0x00000005},
-	{0x000c2099, 0x00000030},
-	{0x0800e5bb, 0x00000005},
-	{0x000c209a, 0x00000030},
-	{0x0880e5bc, 0x00000005},
-	{0x000000c4, 0x00000008},
-	{0x0080e5bd, 0x00000005},
-	{0x0000e5bb, 0x00000005},
-	{0x0080e5bc, 0x00000005},
-	{0x00210000, 0x00000004},
-	{0x02800000, 0x00000004},
-	{0x00c000c8, 0x00000018},
-	{0x4180e000, 0x00000040},
-	{0x000000ca, 0x00000024},
-	{0x01000000, 0x0000000c},
-	{0x0100e51d, 0x0000000c},
-	{0x000045bb, 0x00000004},
-	{0x000080c4, 0x00000008},
-	{0x0000f3ce, 0x00000004},
-	{0x0140a000, 0x00000004},
-	{0x00cc2000, 0x00000004},
-	{0x08c053cf, 0x00000040},
-	{0x00008000, 0000000000},
-	{0x0000f3d2, 0x00000004},
-	{0x0140a000, 0x00000004},
-	{0x00cc2000, 0x00000004},
-	{0x08c053d3, 0x00000040},
-	{0x00008000, 0000000000},
-	{0x0000f39d, 0x00000004},
-	{0x0140a000, 0x00000004},
-	{0x00cc2000, 0x00000004},
-	{0x08c0539e, 0x00000040},
-	{0x00008000, 0000000000},
-	{0x03c00830, 0x00000004},
-	{0x4200e000, 0000000000},
-	{0x0000a000, 0x00000004},
-	{0x200045e0, 0x00000004},
-	{0x0000e5e1, 0000000000},
-	{0x00000001, 0000000000},
-	{0x000700e1, 0x00000004},
-	{0x0800e394, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-	{0000000000, 0000000000},
-};
-
-static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
 	u32 ret;
 	RADEON_WRITE(R520_MC_IND_INDEX, 0x7f0000 | (addr & 0xff));
@@ -825,21 +50,41 @@
 	return ret;
 }
 
+static u32 RS480_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+	u32 ret;
+	RADEON_WRITE(RS480_NB_MC_INDEX, addr & 0xff);
+	ret = RADEON_READ(RS480_NB_MC_DATA);
+	RADEON_WRITE(RS480_NB_MC_INDEX, 0xff);
+	return ret;
+}
+
 static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
 {
+	u32 ret;
 	RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
-	return RADEON_READ(RS690_MC_DATA);
+	ret = RADEON_READ(RS690_MC_DATA);
+	RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_MASK);
+	return ret;
+}
+
+static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+		return RS690_READ_MCIND(dev_priv, addr);
+	else
+		return RS480_READ_MCIND(dev_priv, addr);
 }
 
 u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
 {
 
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
-		return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
+		return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
 		return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
-		return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
+		return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
 	else
 		return RADEON_READ(RADEON_MC_FB_LOCATION);
 }
@@ -847,11 +92,11 @@
 static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
 {
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
-		RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
+		R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
 		RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
-		RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
+		R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
 	else
 		RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
 }
@@ -859,15 +104,39 @@
 static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
 {
 	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
-		RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
+		R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
 		RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
 	else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
-		RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
+		R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
 	else
 		RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
 }
 
+static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
+{
+	u32 agp_base_hi = upper_32_bits(agp_base);
+	u32 agp_base_lo = agp_base & 0xffffffff;
+
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
+		R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
+		R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
+	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+		RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
+		RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
+	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
+		R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
+		R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
+	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) {
+		RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
+		RADEON_WRITE(RS480_AGP_BASE_2, 0);
+	} else {
+		RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
+		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
+			RADEON_WRITE(RADEON_AGP_BASE_2, agp_base_hi);
+	}
+}
+
 static int RADEON_READ_PLL(struct drm_device * dev, int addr)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -882,15 +151,6 @@
 	return RADEON_READ(RADEON_PCIE_DATA);
 }
 
-static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
-{
-	u32 ret;
-	RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f);
-	ret = RADEON_READ(RADEON_IGPGART_DATA);
-	RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f);
-	return ret;
-}
-
 #if RADEON_FIFO_DEBUG
 static void radeon_status(drm_radeon_private_t * dev_priv)
 {
@@ -925,16 +185,36 @@
 
 	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
-	tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
-	tmp |= RADEON_RB3D_DC_FLUSH_ALL;
-	RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {
+		tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
+		tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+		RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
 
-	for (i = 0; i < dev_priv->usec_timeout; i++) {
-		if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
-		      & RADEON_RB3D_DC_BUSY)) {
-			return 0;
+		for (i = 0; i < dev_priv->usec_timeout; i++) {
+			if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
+			      & RADEON_RB3D_DC_BUSY)) {
+				return 0;
+			}
+			DRM_UDELAY(1);
 		}
-		DRM_UDELAY(1);
+	} else {
+		/* 3D */
+		tmp = RADEON_READ(R300_RB3D_DSTCACHE_CTLSTAT);
+		tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+		RADEON_WRITE(R300_RB3D_DSTCACHE_CTLSTAT, tmp);
+
+		/* 2D */
+		tmp = RADEON_READ(R300_DSTCACHE_CTLSTAT);
+		tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+		RADEON_WRITE(R300_DSTCACHE_CTLSTAT, tmp);
+
+		for (i = 0; i < dev_priv->usec_timeout; i++) {
+			if (!(RADEON_READ(R300_DSTCACHE_CTLSTAT)
+			  & RADEON_RB3D_DC_BUSY)) {
+				return 0;
+			}
+			DRM_UDELAY(1);
+		}
 	}
 
 #if RADEON_FIFO_DEBUG
@@ -991,6 +271,50 @@
 	return -EBUSY;
 }
 
+static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
+{
+	uint32_t gb_tile_config, gb_pipe_sel = 0;
+
+	/* RS4xx/RS6xx/R4xx/R5xx */
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R420) {
+		gb_pipe_sel = RADEON_READ(R400_GB_PIPE_SELECT);
+		dev_priv->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
+	} else {
+		/* R3xx */
+		if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
+		    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350)) {
+			dev_priv->num_gb_pipes = 2;
+		} else {
+			/* R3Vxx */
+			dev_priv->num_gb_pipes = 1;
+		}
+	}
+	DRM_INFO("Num pipes: %d\n", dev_priv->num_gb_pipes);
+
+	gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16 /*| R300_SUBPIXEL_1_16*/);
+
+	switch (dev_priv->num_gb_pipes) {
+	case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break;
+	case 3: gb_tile_config |= R300_PIPE_COUNT_R420_3P; break;
+	case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break;
+	default:
+	case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break;
+	}
+
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
+		RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
+		RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
+	}
+	RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config);
+	radeon_do_wait_for_idle(dev_priv);
+	RADEON_WRITE(R300_DST_PIPE_CONFIG, RADEON_READ(R300_DST_PIPE_CONFIG) | R300_PIPE_AUTO_CONFIG);
+	RADEON_WRITE(R300_RB2D_DSTCACHE_MODE, (RADEON_READ(R300_RB2D_DSTCACHE_MODE) |
+					       R300_DC_AUTOFLUSH_ENABLE |
+					       R300_DC_DC_DISABLE_IGNORE_PE));
+
+
+}
+
 /* ================================================================
  * CP control, initialization
  */
@@ -1004,8 +328,22 @@
 	radeon_do_wait_for_idle(dev_priv);
 
 	RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
-
-	if (dev_priv->microcode_version == UCODE_R200) {
+	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R100) ||
+	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV100) ||
+	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV200) ||
+	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS100) ||
+	    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS200)) {
+		DRM_INFO("Loading R100 Microcode\n");
+		for (i = 0; i < 256; i++) {
+			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+				     R100_cp_microcode[i][1]);
+			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+				     R100_cp_microcode[i][0]);
+		}
+	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R200) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV250) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV280) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS300)) {
 		DRM_INFO("Loading R200 Microcode\n");
 		for (i = 0; i < 256; i++) {
 			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
@@ -1013,7 +351,11 @@
 			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
 				     R200_cp_microcode[i][0]);
 		}
-	} else if (dev_priv->microcode_version == UCODE_R300) {
+	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
 		DRM_INFO("Loading R300 Microcode\n");
 		for (i = 0; i < 256; i++) {
 			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
@@ -1021,12 +363,35 @@
 			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
 				     R300_cp_microcode[i][0]);
 		}
-	} else {
+	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
+		DRM_INFO("Loading R400 Microcode\n");
 		for (i = 0; i < 256; i++) {
 			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
-				     radeon_cp_microcode[i][1]);
+				     R420_cp_microcode[i][1]);
 			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
-				     radeon_cp_microcode[i][0]);
+				     R420_cp_microcode[i][0]);
+		}
+	} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+		DRM_INFO("Loading RS690 Microcode\n");
+		for (i = 0; i < 256; i++) {
+			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+				     RS690_cp_microcode[i][1]);
+			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+				     RS690_cp_microcode[i][0]);
+		}
+	} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R580) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV560) ||
+		   ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV570)) {
+		DRM_INFO("Loading R500 Microcode\n");
+		for (i = 0; i < 256; i++) {
+			RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+				     R520_cp_microcode[i][1]);
+			RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+				     R520_cp_microcode[i][0]);
 		}
 	}
 }
@@ -1121,12 +486,13 @@
 static int radeon_do_engine_reset(struct drm_device * dev)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+	u32 clock_cntl_index = 0, mclk_cntl = 0, rbbm_soft_reset;
 	DRM_DEBUG("\n");
 
 	radeon_do_pixcache_flush(dev_priv);
 
-	if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
+		/* may need something similar for newer chips */
 		clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX);
 		mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL);
 
@@ -1137,33 +503,39 @@
 						    RADEON_FORCEON_YCLKB |
 						    RADEON_FORCEON_MC |
 						    RADEON_FORCEON_AIC));
+	}
 
-		rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
+	rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
 
-		RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
-						      RADEON_SOFT_RESET_CP |
-						      RADEON_SOFT_RESET_HI |
-						      RADEON_SOFT_RESET_SE |
-						      RADEON_SOFT_RESET_RE |
-						      RADEON_SOFT_RESET_PP |
-						      RADEON_SOFT_RESET_E2 |
-						      RADEON_SOFT_RESET_RB));
-		RADEON_READ(RADEON_RBBM_SOFT_RESET);
-		RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
-						      ~(RADEON_SOFT_RESET_CP |
-							RADEON_SOFT_RESET_HI |
-							RADEON_SOFT_RESET_SE |
-							RADEON_SOFT_RESET_RE |
-							RADEON_SOFT_RESET_PP |
-							RADEON_SOFT_RESET_E2 |
-							RADEON_SOFT_RESET_RB)));
-		RADEON_READ(RADEON_RBBM_SOFT_RESET);
+	RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
+					      RADEON_SOFT_RESET_CP |
+					      RADEON_SOFT_RESET_HI |
+					      RADEON_SOFT_RESET_SE |
+					      RADEON_SOFT_RESET_RE |
+					      RADEON_SOFT_RESET_PP |
+					      RADEON_SOFT_RESET_E2 |
+					      RADEON_SOFT_RESET_RB));
+	RADEON_READ(RADEON_RBBM_SOFT_RESET);
+	RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
+					      ~(RADEON_SOFT_RESET_CP |
+						RADEON_SOFT_RESET_HI |
+						RADEON_SOFT_RESET_SE |
+						RADEON_SOFT_RESET_RE |
+						RADEON_SOFT_RESET_PP |
+						RADEON_SOFT_RESET_E2 |
+						RADEON_SOFT_RESET_RB)));
+	RADEON_READ(RADEON_RBBM_SOFT_RESET);
 
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
 		RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl);
 		RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
 		RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
 	}
 
+	/* setup the raster pipes */
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R300)
+	    radeon_init_pipes(dev_priv);
+
 	/* Reset the CP ring */
 	radeon_do_cp_reset(dev_priv);
 
@@ -1194,7 +566,8 @@
 
 #if __OS_HAS_AGP
 	if (dev_priv->flags & RADEON_IS_AGP) {
-		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
+		radeon_write_agp_base(dev_priv, dev->agp->base);
+
 		radeon_write_agp_location(dev_priv,
 			     (((dev_priv->gart_vm_start - 1 +
 				dev_priv->gart_size) & 0xffff0000) |
@@ -1339,102 +712,70 @@
 /* Enable or disable IGP GART on the chip */
 static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
 {
-	u32 temp, tmp;
-
-	tmp = RADEON_READ(RADEON_AIC_CNTL);
-	if (on) {
-		DRM_DEBUG("programming igpgart %08X %08lX %08X\n",
-			 dev_priv->gart_vm_start,
-			 (long)dev_priv->gart_info.bus_addr,
-			 dev_priv->gart_size);
-
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR,
-				     dev_priv->gart_info.bus_addr);
-
-		temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp);
-
-		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
-		dev_priv->gart_size = 32*1024*1024;
-		radeon_write_agp_location(dev_priv,
-			     (((dev_priv->gart_vm_start - 1 +
-			       dev_priv->gart_size) & 0xffff0000) |
-			     (dev_priv->gart_vm_start >> 16)));
-
-		temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp);
-
-		RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1);
-		RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
-		RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0);
-       }
-}
-
-/* Enable or disable RS690 GART on the chip */
-static void radeon_set_rs690gart(drm_radeon_private_t *dev_priv, int on)
-{
 	u32 temp;
 
 	if (on) {
-		DRM_DEBUG("programming rs690 gart %08X %08lX %08X\n",
+		DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
 			  dev_priv->gart_vm_start,
 			  (long)dev_priv->gart_info.bus_addr,
 			  dev_priv->gart_size);
 
-		temp = RS690_READ_MCIND(dev_priv, RS690_MC_MISC_CNTL);
-		RS690_WRITE_MCIND(RS690_MC_MISC_CNTL, 0x5000);
+		temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
+		if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+			IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
+							     RS690_BLOCK_GFX_D3_EN));
+		else
+			IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN);
 
-		RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
-				  RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
+							       RS480_VA_SIZE_32MB));
 
-		temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_FEATURE_ID);
-		RS690_WRITE_MCIND(RS690_MC_GART_FEATURE_ID, 0x42040800);
+		temp = IGP_READ_MCIND(dev_priv, RS480_GART_FEATURE_ID);
+		IGP_WRITE_MCIND(RS480_GART_FEATURE_ID, (RS480_HANG_EN |
+							RS480_TLB_ENABLE |
+							RS480_GTW_LAC_EN |
+							RS480_1LEVEL_GART));
 
-		RS690_WRITE_MCIND(RS690_MC_GART_BASE,
-				  dev_priv->gart_info.bus_addr);
+		temp = dev_priv->gart_info.bus_addr & 0xfffff000;
+		temp |= (upper_32_bits(dev_priv->gart_info.bus_addr) & 0xff) << 4;
+		IGP_WRITE_MCIND(RS480_GART_BASE, temp);
 
-		temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_MODE_CONTROL);
-		RS690_WRITE_MCIND(RS690_MC_AGP_MODE_CONTROL, 0x01400000);
+		temp = IGP_READ_MCIND(dev_priv, RS480_AGP_MODE_CNTL);
+		IGP_WRITE_MCIND(RS480_AGP_MODE_CNTL, ((1 << RS480_REQ_TYPE_SNOOP_SHIFT) |
+						      RS480_REQ_TYPE_SNOOP_DIS));
 
-		RS690_WRITE_MCIND(RS690_MC_AGP_BASE,
-				  (unsigned int)dev_priv->gart_vm_start);
+		radeon_write_agp_base(dev_priv, dev_priv->gart_vm_start);
 
 		dev_priv->gart_size = 32*1024*1024;
 		temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) &
 			 0xffff0000) | (dev_priv->gart_vm_start >> 16));
 
-		RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, temp);
+		radeon_write_agp_location(dev_priv, temp);
 
-		temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_SIZE);
-		RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
-				  RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+		temp = IGP_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE);
+		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
+							       RS480_VA_SIZE_32MB));
 
 		do {
-			temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
-			if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
-			    RS690_MC_GART_CLEAR_DONE)
+			temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
+			if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
 				break;
 			DRM_UDELAY(1);
 		} while (1);
 
-		RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
-				  RS690_MC_GART_CC_CLEAR);
+		IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL,
+				RS480_GART_CACHE_INVALIDATE);
+
 		do {
-			temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
-			if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
-				   RS690_MC_GART_CLEAR_DONE)
+			temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
+			if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
 				break;
 			DRM_UDELAY(1);
 		} while (1);
 
-		RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
-				  RS690_MC_GART_CC_NO_CHANGE);
+		IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0);
 	} else {
-		RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, RS690_MC_GART_DIS);
+		IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
 	}
 }
 
@@ -1472,12 +813,8 @@
 {
 	u32 tmp;
 
-	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
-		radeon_set_rs690gart(dev_priv, on);
-		return;
-	}
-
-	if (dev_priv->flags & RADEON_IS_IGPGART) {
+	if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+	    (dev_priv->flags & RADEON_IS_IGPGART)) {
 		radeon_set_igpgart(dev_priv, on);
 		return;
 	}
@@ -1951,6 +1288,7 @@
 	radeon_cp_init_ring_buffer(dev, dev_priv);
 
 	radeon_do_engine_reset(dev);
+	radeon_enable_interrupt(dev);
 
 	DRM_DEBUG("radeon_do_resume_cp() complete\n");
 
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index aab82e1..73ff51f 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -240,6 +240,7 @@
 #	define R300_NEW_WAIT_2D_2D_CLEAN_3D_3D_CLEAN	0x8
 
 #define R300_CMD_SCRATCH		8
+#define R300_CMD_R500FP                 9
 
 typedef union {
 	unsigned int u;
@@ -268,6 +269,9 @@
 	struct {
 		unsigned char cmd_type, reg, n_bufs, flags;
 	} scratch;
+	struct {
+		unsigned char cmd_type, count, adrlo, adrhi_flags;
+	} r500fp;
 } drm_r300_cmd_header_t;
 
 #define RADEON_FRONT			0x1
@@ -278,6 +282,9 @@
 #define RADEON_USE_HIERZ		0x40000000
 #define RADEON_USE_COMP_ZBUF		0x20000000
 
+#define R500FP_CONSTANT_TYPE  (1 << 1)
+#define R500FP_CONSTANT_CLAMP (1 << 2)
+
 /* Primitive types
  */
 #define RADEON_POINTS			0x1
@@ -669,6 +676,7 @@
 #define RADEON_PARAM_CARD_TYPE             12
 #define RADEON_PARAM_VBLANK_CRTC           13   /* VBLANK CRTC */
 #define RADEON_PARAM_FB_LOCATION           14   /* FB location */
+#define RADEON_PARAM_NUM_GB_PIPES          15   /* num GB pipes */
 
 typedef struct drm_radeon_getparam {
 	int param;
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 173ae62..3f0eca9 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -38,7 +38,7 @@
 
 #define DRIVER_NAME		"radeon"
 #define DRIVER_DESC		"ATI Radeon"
-#define DRIVER_DATE		"20060524"
+#define DRIVER_DATE		"20080528"
 
 /* Interface history:
  *
@@ -98,9 +98,10 @@
  * 1.26- Add support for variable size PCI(E) gart aperture
  * 1.27- Add support for IGP GART
  * 1.28- Add support for VBL on CRTC2
+ * 1.29- R500 3D cmd buffer support
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		28
+#define DRIVER_MINOR		29
 #define DRIVER_PATCHLEVEL	0
 
 /*
@@ -122,7 +123,7 @@
 	CHIP_RV380,
 	CHIP_R420,
 	CHIP_RV410,
-	CHIP_RS400,
+	CHIP_RS480,
 	CHIP_RS690,
 	CHIP_RV515,
 	CHIP_R520,
@@ -294,6 +295,7 @@
 	int vblank_crtc;
 	uint32_t irq_enable_reg;
 	int irq_enabled;
+	uint32_t r500_disp_irq_reg;
 
 	struct radeon_surface surfaces[RADEON_MAX_SURFACES];
 	struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
@@ -307,6 +309,8 @@
 	/* starting from here on, data is preserved accross an open */
 	uint32_t flags;		/* see radeon_chip_flags */
 	unsigned long fb_aper_offset;
+
+	int num_gb_pipes;
 } drm_radeon_private_t;
 
 typedef struct drm_radeon_buf_priv {
@@ -382,6 +386,7 @@
 extern void radeon_driver_irq_preinstall(struct drm_device * dev);
 extern void radeon_driver_irq_postinstall(struct drm_device * dev);
 extern void radeon_driver_irq_uninstall(struct drm_device * dev);
+extern void radeon_enable_interrupt(struct drm_device *dev);
 extern int radeon_vblank_crtc_get(struct drm_device *dev);
 extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
 
@@ -444,13 +449,13 @@
 #define RADEON_PCIE_DATA                0x0034
 #define RADEON_PCIE_TX_GART_CNTL	0x10
 #	define RADEON_PCIE_TX_GART_EN		(1 << 0)
-#	define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0<<1)
-#	define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO  (1<<1)
-#	define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD   (3<<1)
-#	define RADEON_PCIE_TX_GART_MODE_32_128_CACHE	(0<<3)
-#	define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE	(1<<3)
-#	define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN      (1<<5)
-#	define RADEON_PCIE_TX_GART_INVALIDATE_TLB	(1<<8)
+#	define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0 << 1)
+#	define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO  (1 << 1)
+#	define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD   (3 << 1)
+#	define RADEON_PCIE_TX_GART_MODE_32_128_CACHE	(0 << 3)
+#	define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE	(1 << 3)
+#	define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN      (1 << 5)
+#	define RADEON_PCIE_TX_GART_INVALIDATE_TLB	(1 << 8)
 #define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11
 #define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12
 #define RADEON_PCIE_TX_GART_BASE	0x13
@@ -459,14 +464,9 @@
 #define RADEON_PCIE_TX_GART_END_LO	0x16
 #define RADEON_PCIE_TX_GART_END_HI	0x17
 
-#define RADEON_IGPGART_INDEX            0x168
-#define RADEON_IGPGART_DATA             0x16c
-#define RADEON_IGPGART_UNK_18           0x18
-#define RADEON_IGPGART_CTRL             0x2b
-#define RADEON_IGPGART_BASE_ADDR        0x2c
-#define RADEON_IGPGART_FLUSH            0x2e
-#define RADEON_IGPGART_ENABLE           0x38
-#define RADEON_IGPGART_UNK_39           0x39
+#define RS480_NB_MC_INDEX               0x168
+#	define RS480_NB_MC_IND_WR_EN	(1 << 8)
+#define RS480_NB_MC_DATA                0x16c
 
 #define RS690_MC_INDEX                  0x78
 #   define RS690_MC_INDEX_MASK          0x1ff
@@ -474,45 +474,91 @@
 #   define RS690_MC_INDEX_WR_ACK        0x7f
 #define RS690_MC_DATA                   0x7c
 
-#define RS690_MC_MISC_CNTL              0x18
-#define RS690_MC_GART_FEATURE_ID        0x2b
-#define RS690_MC_GART_BASE              0x2c
-#define RS690_MC_GART_CACHE_CNTL	0x2e
-#   define RS690_MC_GART_CC_NO_CHANGE   0x0
-#   define RS690_MC_GART_CC_CLEAR       0x1
-#   define RS690_MC_GART_CLEAR_STATUS   (1 << 1)
-#       define RS690_MC_GART_CLEAR_DONE     (0 << 1)
-#       define RS690_MC_GART_CLEAR_PENDING  (1 << 1)
-#define RS690_MC_AGP_SIZE               0x38
-#   define RS690_MC_GART_DIS            0x0
-#   define RS690_MC_GART_EN             0x1
-#   define RS690_MC_AGP_SIZE_32MB       (0 << 1)
-#   define RS690_MC_AGP_SIZE_64MB       (1 << 1)
-#   define RS690_MC_AGP_SIZE_128MB      (2 << 1)
-#   define RS690_MC_AGP_SIZE_256MB      (3 << 1)
-#   define RS690_MC_AGP_SIZE_512MB      (4 << 1)
-#   define RS690_MC_AGP_SIZE_1GB        (5 << 1)
-#   define RS690_MC_AGP_SIZE_2GB        (6 << 1)
-#define RS690_MC_AGP_MODE_CONTROL       0x39
+/* MC indirect registers */
+#define RS480_MC_MISC_CNTL              0x18
+#	define RS480_DISABLE_GTW	(1 << 1)
+/* switch between MCIND GART and MM GART registers. 0 = mmgart, 1 = mcind gart */
+#	define RS480_GART_INDEX_REG_EN	(1 << 12)
+#	define RS690_BLOCK_GFX_D3_EN	(1 << 14)
+#define RS480_K8_FB_LOCATION            0x1e
+#define RS480_GART_FEATURE_ID           0x2b
+#	define RS480_HANG_EN	        (1 << 11)
+#	define RS480_TLB_ENABLE	        (1 << 18)
+#	define RS480_P2P_ENABLE	        (1 << 19)
+#	define RS480_GTW_LAC_EN	        (1 << 25)
+#	define RS480_2LEVEL_GART	(0 << 30)
+#	define RS480_1LEVEL_GART	(1 << 30)
+#	define RS480_PDC_EN	        (1 << 31)
+#define RS480_GART_BASE                 0x2c
+#define RS480_GART_CACHE_CNTRL          0x2e
+#	define RS480_GART_CACHE_INVALIDATE (1 << 0) /* wait for it to clear */
+#define RS480_AGP_ADDRESS_SPACE_SIZE    0x38
+#	define RS480_GART_EN	        (1 << 0)
+#	define RS480_VA_SIZE_32MB	(0 << 1)
+#	define RS480_VA_SIZE_64MB	(1 << 1)
+#	define RS480_VA_SIZE_128MB	(2 << 1)
+#	define RS480_VA_SIZE_256MB	(3 << 1)
+#	define RS480_VA_SIZE_512MB	(4 << 1)
+#	define RS480_VA_SIZE_1GB	(5 << 1)
+#	define RS480_VA_SIZE_2GB	(6 << 1)
+#define RS480_AGP_MODE_CNTL             0x39
+#	define RS480_POST_GART_Q_SIZE	(1 << 18)
+#	define RS480_NONGART_SNOOP	(1 << 19)
+#	define RS480_AGP_RD_BUF_SIZE	(1 << 20)
+#	define RS480_REQ_TYPE_SNOOP_SHIFT 22
+#	define RS480_REQ_TYPE_SNOOP_MASK  0x3
+#	define RS480_REQ_TYPE_SNOOP_DIS	(1 << 24)
+#define RS480_MC_MISC_UMA_CNTL          0x5f
+#define RS480_MC_MCLK_CNTL              0x7a
+#define RS480_MC_UMA_DUALCH_CNTL        0x86
+
 #define RS690_MC_FB_LOCATION            0x100
 #define RS690_MC_AGP_LOCATION           0x101
 #define RS690_MC_AGP_BASE               0x102
+#define RS690_MC_AGP_BASE_2             0x103
 
 #define R520_MC_IND_INDEX 0x70
-#define R520_MC_IND_WR_EN (1<<24)
+#define R520_MC_IND_WR_EN (1 << 24)
 #define R520_MC_IND_DATA  0x74
 
 #define RV515_MC_FB_LOCATION 0x01
 #define RV515_MC_AGP_LOCATION 0x02
+#define RV515_MC_AGP_BASE     0x03
+#define RV515_MC_AGP_BASE_2   0x04
 
 #define R520_MC_FB_LOCATION 0x04
 #define R520_MC_AGP_LOCATION 0x05
+#define R520_MC_AGP_BASE     0x06
+#define R520_MC_AGP_BASE_2   0x07
 
 #define RADEON_MPP_TB_CONFIG		0x01c0
 #define RADEON_MEM_CNTL			0x0140
 #define RADEON_MEM_SDRAM_MODE_REG	0x0158
+#define RADEON_AGP_BASE_2		0x015c /* r200+ only */
+#define RS480_AGP_BASE_2		0x0164
 #define RADEON_AGP_BASE			0x0170
 
+/* pipe config regs */
+#define R400_GB_PIPE_SELECT             0x402c
+#define R500_DYN_SCLK_PWMEM_PIPE        0x000d /* PLL */
+#define R500_SU_REG_DEST                0x42c8
+#define R300_GB_TILE_CONFIG             0x4018
+#       define R300_ENABLE_TILING       (1 << 0)
+#       define R300_PIPE_COUNT_RV350    (0 << 1)
+#       define R300_PIPE_COUNT_R300     (3 << 1)
+#       define R300_PIPE_COUNT_R420_3P  (6 << 1)
+#       define R300_PIPE_COUNT_R420     (7 << 1)
+#       define R300_TILE_SIZE_8         (0 << 4)
+#       define R300_TILE_SIZE_16        (1 << 4)
+#       define R300_TILE_SIZE_32        (2 << 4)
+#       define R300_SUBPIXEL_1_12       (0 << 16)
+#       define R300_SUBPIXEL_1_16       (1 << 16)
+#define R300_DST_PIPE_CONFIG            0x170c
+#       define R300_PIPE_AUTO_CONFIG    (1 << 31)
+#define R300_RB2D_DSTCACHE_MODE         0x3428
+#       define R300_DC_AUTOFLUSH_ENABLE (1 << 8)
+#       define R300_DC_DC_DISABLE_IGNORE_PE (1 << 17)
+
 #define RADEON_RB3D_COLOROFFSET		0x1c40
 #define RADEON_RB3D_COLORPITCH		0x1c48
 
@@ -616,11 +662,12 @@
 #define RADEON_PP_TXFILTER_1		0x1c6c
 #define RADEON_PP_TXFILTER_2		0x1c84
 
-#define RADEON_RB2D_DSTCACHE_CTLSTAT	0x342c
-#	define RADEON_RB2D_DC_FLUSH		(3 << 0)
-#	define RADEON_RB2D_DC_FREE		(3 << 2)
-#	define RADEON_RB2D_DC_FLUSH_ALL		0xf
-#	define RADEON_RB2D_DC_BUSY		(1 << 31)
+#define R300_RB2D_DSTCACHE_CTLSTAT	0x342c /* use R300_DSTCACHE_CTLSTAT */
+#define R300_DSTCACHE_CTLSTAT		0x1714
+#	define R300_RB2D_DC_FLUSH		(3 << 0)
+#	define R300_RB2D_DC_FREE		(3 << 2)
+#	define R300_RB2D_DC_FLUSH_ALL		0xf
+#	define R300_RB2D_DC_BUSY		(1 << 31)
 #define RADEON_RB3D_CNTL		0x1c3c
 #	define RADEON_ALPHA_BLEND_ENABLE	(1 << 0)
 #	define RADEON_PLANE_MASK_ENABLE		(1 << 1)
@@ -643,11 +690,18 @@
 #	define RADEON_RB3D_ZC_FREE		(1 << 2)
 #	define RADEON_RB3D_ZC_FLUSH_ALL		0x5
 #	define RADEON_RB3D_ZC_BUSY		(1 << 31)
+#define R300_ZB_ZCACHE_CTLSTAT                  0x4f18
+#	define R300_ZC_FLUSH		        (1 << 0)
+#	define R300_ZC_FREE		        (1 << 1)
+#	define R300_ZC_FLUSH_ALL		0x3
+#	define R300_ZC_BUSY		        (1 << 31)
 #define RADEON_RB3D_DSTCACHE_CTLSTAT	0x325c
 #	define RADEON_RB3D_DC_FLUSH		(3 << 0)
 #	define RADEON_RB3D_DC_FREE		(3 << 2)
 #	define RADEON_RB3D_DC_FLUSH_ALL		0xf
 #	define RADEON_RB3D_DC_BUSY		(1 << 31)
+#define R300_RB3D_DSTCACHE_CTLSTAT              0x4e4c
+#	define R300_RB3D_DC_FINISH		(1 << 4)
 #define RADEON_RB3D_ZSTENCILCNTL	0x1c2c
 #	define RADEON_Z_TEST_MASK		(7 << 4)
 #	define RADEON_Z_TEST_ALWAYS		(7 << 4)
@@ -1057,6 +1111,31 @@
 
 #define R200_VAP_PVS_CNTL_1               0x22D0
 
+#define R500_D1CRTC_STATUS 0x609c
+#define R500_D2CRTC_STATUS 0x689c
+#define R500_CRTC_V_BLANK (1<<0)
+
+#define R500_D1CRTC_FRAME_COUNT 0x60a4
+#define R500_D2CRTC_FRAME_COUNT 0x68a4
+
+#define R500_D1MODE_V_COUNTER 0x6530
+#define R500_D2MODE_V_COUNTER 0x6d30
+
+#define R500_D1MODE_VBLANK_STATUS 0x6534
+#define R500_D2MODE_VBLANK_STATUS 0x6d34
+#define R500_VBLANK_OCCURED (1<<0)
+#define R500_VBLANK_ACK     (1<<4)
+#define R500_VBLANK_STAT    (1<<12)
+#define R500_VBLANK_INT     (1<<16)
+
+#define R500_DxMODE_INT_MASK 0x6540
+#define R500_D1MODE_INT_MASK (1<<0)
+#define R500_D2MODE_INT_MASK (1<<8)
+
+#define R500_DISP_INTERRUPT_STATUS 0x7edc
+#define R500_D1_VBLANK_INTERRUPT (1 << 4)
+#define R500_D2_VBLANK_INTERRUPT (1 << 5)
+
 /* Constants */
 #define RADEON_MAX_USEC_TIMEOUT		100000	/* 100 ms */
 
@@ -1078,42 +1157,50 @@
 #define RADEON_READ8(reg)	DRM_READ8(  dev_priv->mmio, (reg) )
 #define RADEON_WRITE8(reg,val)	DRM_WRITE8( dev_priv->mmio, (reg), (val) )
 
-#define RADEON_WRITE_PLL( addr, val )					\
+#define RADEON_WRITE_PLL(addr, val)					\
 do {									\
-	RADEON_WRITE8( RADEON_CLOCK_CNTL_INDEX,				\
+	RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX,				\
 		       ((addr) & 0x1f) | RADEON_PLL_WR_EN );		\
-	RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) );			\
+	RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, (val));			\
 } while (0)
 
-#define RADEON_WRITE_IGPGART( addr, val )				\
+#define RADEON_WRITE_PCIE(addr, val)					\
 do {									\
-	RADEON_WRITE( RADEON_IGPGART_INDEX,				\
-			((addr) & 0x7f) | (1 << 8));			\
-	RADEON_WRITE( RADEON_IGPGART_DATA, (val) );			\
-	RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f );			\
-} while (0)
-
-#define RADEON_WRITE_PCIE( addr, val )					\
-do {									\
-	RADEON_WRITE8( RADEON_PCIE_INDEX,				\
+	RADEON_WRITE8(RADEON_PCIE_INDEX,				\
 			((addr) & 0xff));				\
-	RADEON_WRITE( RADEON_PCIE_DATA, (val) );			\
+	RADEON_WRITE(RADEON_PCIE_DATA, (val));			\
 } while (0)
 
-#define RADEON_WRITE_MCIND( addr, val )					\
-	do {								\
-		RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff));	\
-		RADEON_WRITE(R520_MC_IND_DATA, (val));			\
-		RADEON_WRITE(R520_MC_IND_INDEX, 0);	\
-	} while (0)
+#define R500_WRITE_MCIND(addr, val)					\
+do {								\
+	RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff));	\
+	RADEON_WRITE(R520_MC_IND_DATA, (val));			\
+	RADEON_WRITE(R520_MC_IND_INDEX, 0);	\
+} while (0)
 
-#define RS690_WRITE_MCIND( addr, val )					\
+#define RS480_WRITE_MCIND(addr, val)				\
+do {									\
+	RADEON_WRITE(RS480_NB_MC_INDEX,				\
+			((addr) & 0xff) | RS480_NB_MC_IND_WR_EN);	\
+	RADEON_WRITE(RS480_NB_MC_DATA, (val));			\
+	RADEON_WRITE(RS480_NB_MC_INDEX, 0xff);			\
+} while (0)
+
+#define RS690_WRITE_MCIND(addr, val)					\
 do {								\
 	RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK));	\
 	RADEON_WRITE(RS690_MC_DATA, val);			\
 	RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);	\
 } while (0)
 
+#define IGP_WRITE_MCIND(addr, val)				\
+do {									\
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)       \
+		RS690_WRITE_MCIND(addr, val);				\
+	else								\
+		RS480_WRITE_MCIND(addr, val);				\
+} while (0)
+
 #define CP_PACKET0( reg, n )						\
 	(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
 #define CP_PACKET0_TABLE( reg, n )					\
@@ -1154,23 +1241,43 @@
 } while (0)
 
 #define RADEON_FLUSH_CACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB3D_DC_FLUSH );				\
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {	\
+		OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0));	\
+		OUT_RING(RADEON_RB3D_DC_FLUSH);				\
+	} else {                                                        \
+		OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));	\
+		OUT_RING(RADEON_RB3D_DC_FLUSH);				\
+	}                                                               \
 } while (0)
 
 #define RADEON_PURGE_CACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB3D_DC_FLUSH_ALL );				\
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {	\
+		OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0));	\
+		OUT_RING(RADEON_RB3D_DC_FLUSH_ALL);			\
+	} else {                                                        \
+		OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));	\
+		OUT_RING(RADEON_RB3D_DC_FLUSH_ALL);			\
+	}                                                               \
 } while (0)
 
 #define RADEON_FLUSH_ZCACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB3D_ZC_FLUSH );				\
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {	\
+		OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0));	\
+		OUT_RING(RADEON_RB3D_ZC_FLUSH);				\
+	} else {                                                        \
+		OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0));	\
+		OUT_RING(R300_ZC_FLUSH);				\
+	}                                                               \
 } while (0)
 
 #define RADEON_PURGE_ZCACHE() do {					\
-	OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) );	\
-	OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL );				\
+	if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {	\
+		OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0));	\
+		OUT_RING(RADEON_RB3D_ZC_FLUSH_ALL);			\
+	} else {                                                        \
+		OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));	\
+		OUT_RING(R300_ZC_FLUSH_ALL);				\
+	}                                                               \
 } while (0)
 
 /* ================================================================
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index 009af38..ee40d19 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -234,7 +234,7 @@
 	return radeon_wait_irq(dev, irqwait->irq_seq);
 }
 
-static void radeon_enable_interrupt(struct drm_device *dev)
+void radeon_enable_interrupt(struct drm_device *dev)
 {
 	drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
 
diff --git a/drivers/char/drm/radeon_microcode.h b/drivers/char/drm/radeon_microcode.h
new file mode 100644
index 0000000..a348c9e
--- /dev/null
+++ b/drivers/char/drm/radeon_microcode.h
@@ -0,0 +1,1844 @@
+/*
+ * Copyright 2007 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * 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
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef RADEON_MICROCODE_H
+#define RADEON_MICROCODE_H
+
+/* production radeon ucode r1xx-r6xx */
+static const u32 R100_cp_microcode[][2] = {
+    { 0x21007000, 0000000000 },
+    { 0x20007000, 0000000000 },
+    { 0x000000b4, 0x00000004 },
+    { 0x000000b8, 0x00000004 },
+    { 0x6f5b4d4c, 0000000000 },
+    { 0x4c4c427f, 0000000000 },
+    { 0x5b568a92, 0000000000 },
+    { 0x4ca09c6d, 0000000000 },
+    { 0xad4c4c4c, 0000000000 },
+    { 0x4ce1af3d, 0000000000 },
+    { 0xd8afafaf, 0000000000 },
+    { 0xd64c4cdc, 0000000000 },
+    { 0x4cd10d10, 0000000000 },
+    { 0x000f0000, 0x00000016 },
+    { 0x362f242d, 0000000000 },
+    { 0x00000012, 0x00000004 },
+    { 0x000f0000, 0x00000016 },
+    { 0x362f282d, 0000000000 },
+    { 0x000380e7, 0x00000002 },
+    { 0x04002c97, 0x00000002 },
+    { 0x000f0001, 0x00000016 },
+    { 0x333a3730, 0000000000 },
+    { 0x000077ef, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x00000021, 0x0000001a },
+    { 0x00004000, 0x0000001e },
+    { 0x00061000, 0x00000002 },
+    { 0x00000021, 0x0000001a },
+    { 0x00004000, 0x0000001e },
+    { 0x00061000, 0x00000002 },
+    { 0x00000021, 0x0000001a },
+    { 0x00004000, 0x0000001e },
+    { 0x00000017, 0x00000004 },
+    { 0x0003802b, 0x00000002 },
+    { 0x040067e0, 0x00000002 },
+    { 0x00000017, 0x00000004 },
+    { 0x000077e0, 0x00000002 },
+    { 0x00065000, 0x00000002 },
+    { 0x000037e1, 0x00000002 },
+    { 0x040067e1, 0x00000006 },
+    { 0x000077e0, 0x00000002 },
+    { 0x000077e1, 0x00000002 },
+    { 0x000077e1, 0x00000006 },
+    { 0xffffffff, 0000000000 },
+    { 0x10000000, 0000000000 },
+    { 0x0003802b, 0x00000002 },
+    { 0x040067e0, 0x00000006 },
+    { 0x00007675, 0x00000002 },
+    { 0x00007676, 0x00000002 },
+    { 0x00007677, 0x00000002 },
+    { 0x00007678, 0x00000006 },
+    { 0x0003802c, 0x00000002 },
+    { 0x04002676, 0x00000002 },
+    { 0x00007677, 0x00000002 },
+    { 0x00007678, 0x00000006 },
+    { 0x0000002f, 0x00000018 },
+    { 0x0000002f, 0x00000018 },
+    { 0000000000, 0x00000006 },
+    { 0x00000030, 0x00000018 },
+    { 0x00000030, 0x00000018 },
+    { 0000000000, 0x00000006 },
+    { 0x01605000, 0x00000002 },
+    { 0x00065000, 0x00000002 },
+    { 0x00098000, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x64c0603e, 0x00000004 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00080000, 0x00000016 },
+    { 0000000000, 0000000000 },
+    { 0x0400251d, 0x00000002 },
+    { 0x00007580, 0x00000002 },
+    { 0x00067581, 0x00000002 },
+    { 0x04002580, 0x00000002 },
+    { 0x00067581, 0x00000002 },
+    { 0x00000049, 0x00000004 },
+    { 0x00005000, 0000000000 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x0000750e, 0x00000002 },
+    { 0x00019000, 0x00000002 },
+    { 0x00011055, 0x00000014 },
+    { 0x00000055, 0x00000012 },
+    { 0x0400250f, 0x00000002 },
+    { 0x0000504f, 0x00000004 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00007565, 0x00000002 },
+    { 0x00007566, 0x00000002 },
+    { 0x00000058, 0x00000004 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x01e655b4, 0x00000002 },
+    { 0x4401b0e4, 0x00000002 },
+    { 0x01c110e4, 0x00000002 },
+    { 0x26667066, 0x00000018 },
+    { 0x040c2565, 0x00000002 },
+    { 0x00000066, 0x00000018 },
+    { 0x04002564, 0x00000002 },
+    { 0x00007566, 0x00000002 },
+    { 0x0000005d, 0x00000004 },
+    { 0x00401069, 0x00000008 },
+    { 0x00101000, 0x00000002 },
+    { 0x000d80ff, 0x00000002 },
+    { 0x0080006c, 0x00000008 },
+    { 0x000f9000, 0x00000002 },
+    { 0x000e00ff, 0x00000002 },
+    { 0000000000, 0x00000006 },
+    { 0x0000008f, 0x00000018 },
+    { 0x0000005b, 0x00000004 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00007576, 0x00000002 },
+    { 0x00065000, 0x00000002 },
+    { 0x00009000, 0x00000002 },
+    { 0x00041000, 0x00000002 },
+    { 0x0c00350e, 0x00000002 },
+    { 0x00049000, 0x00000002 },
+    { 0x00051000, 0x00000002 },
+    { 0x01e785f8, 0x00000002 },
+    { 0x00200000, 0x00000002 },
+    { 0x0060007e, 0x0000000c },
+    { 0x00007563, 0x00000002 },
+    { 0x006075f0, 0x00000021 },
+    { 0x20007073, 0x00000004 },
+    { 0x00005073, 0x00000004 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00007576, 0x00000002 },
+    { 0x00007577, 0x00000002 },
+    { 0x0000750e, 0x00000002 },
+    { 0x0000750f, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x00600083, 0x0000000c },
+    { 0x006075f0, 0x00000021 },
+    { 0x000075f8, 0x00000002 },
+    { 0x00000083, 0x00000004 },
+    { 0x000a750e, 0x00000002 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x0020750f, 0x00000002 },
+    { 0x00600086, 0x00000004 },
+    { 0x00007570, 0x00000002 },
+    { 0x00007571, 0x00000002 },
+    { 0x00007572, 0x00000006 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00005000, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x00007568, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x00000095, 0x0000000c },
+    { 0x00058000, 0x00000002 },
+    { 0x0c607562, 0x00000002 },
+    { 0x00000097, 0x00000004 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x00600096, 0x00000004 },
+    { 0x400070e5, 0000000000 },
+    { 0x000380e6, 0x00000002 },
+    { 0x040025c5, 0x00000002 },
+    { 0x000380e5, 0x00000002 },
+    { 0x000000a8, 0x0000001c },
+    { 0x000650aa, 0x00000018 },
+    { 0x040025bb, 0x00000002 },
+    { 0x000610ab, 0x00000018 },
+    { 0x040075bc, 0000000000 },
+    { 0x000075bb, 0x00000002 },
+    { 0x000075bc, 0000000000 },
+    { 0x00090000, 0x00000006 },
+    { 0x00090000, 0x00000002 },
+    { 0x000d8002, 0x00000006 },
+    { 0x00007832, 0x00000002 },
+    { 0x00005000, 0x00000002 },
+    { 0x000380e7, 0x00000002 },
+    { 0x04002c97, 0x00000002 },
+    { 0x00007820, 0x00000002 },
+    { 0x00007821, 0x00000002 },
+    { 0x00007800, 0000000000 },
+    { 0x01200000, 0x00000002 },
+    { 0x20077000, 0x00000002 },
+    { 0x01200000, 0x00000002 },
+    { 0x20007000, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x0120751b, 0x00000002 },
+    { 0x8040750a, 0x00000002 },
+    { 0x8040750b, 0x00000002 },
+    { 0x00110000, 0x00000002 },
+    { 0x000380e5, 0x00000002 },
+    { 0x000000c6, 0x0000001c },
+    { 0x000610ab, 0x00000018 },
+    { 0x844075bd, 0x00000002 },
+    { 0x000610aa, 0x00000018 },
+    { 0x840075bb, 0x00000002 },
+    { 0x000610ab, 0x00000018 },
+    { 0x844075bc, 0x00000002 },
+    { 0x000000c9, 0x00000004 },
+    { 0x804075bd, 0x00000002 },
+    { 0x800075bb, 0x00000002 },
+    { 0x804075bc, 0x00000002 },
+    { 0x00108000, 0x00000002 },
+    { 0x01400000, 0x00000002 },
+    { 0x006000cd, 0x0000000c },
+    { 0x20c07000, 0x00000020 },
+    { 0x000000cf, 0x00000012 },
+    { 0x00800000, 0x00000006 },
+    { 0x0080751d, 0x00000006 },
+    { 0000000000, 0000000000 },
+    { 0x0000775c, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x00661000, 0x00000002 },
+    { 0x0460275d, 0x00000020 },
+    { 0x00004000, 0000000000 },
+    { 0x01e00830, 0x00000002 },
+    { 0x21007000, 0000000000 },
+    { 0x6464614d, 0000000000 },
+    { 0x69687420, 0000000000 },
+    { 0x00000073, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x00005000, 0x00000002 },
+    { 0x000380d0, 0x00000002 },
+    { 0x040025e0, 0x00000002 },
+    { 0x000075e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000380e0, 0x00000002 },
+    { 0x04002394, 0x00000002 },
+    { 0x00005000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x00000008, 0000000000 },
+    { 0x00000004, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+static const u32 R200_cp_microcode[][2] = {
+    { 0x21007000, 0000000000 },
+    { 0x20007000, 0000000000 },
+    { 0x000000bf, 0x00000004 },
+    { 0x000000c3, 0x00000004 },
+    { 0x7a685e5d, 0000000000 },
+    { 0x5d5d5588, 0000000000 },
+    { 0x68659197, 0000000000 },
+    { 0x5da19f78, 0000000000 },
+    { 0x5d5d5d5d, 0000000000 },
+    { 0x5dee5d50, 0000000000 },
+    { 0xf2acacac, 0000000000 },
+    { 0xe75df9e9, 0000000000 },
+    { 0xb1dd0e11, 0000000000 },
+    { 0xe2afafaf, 0000000000 },
+    { 0x000f0000, 0x00000016 },
+    { 0x452f232d, 0000000000 },
+    { 0x00000013, 0x00000004 },
+    { 0x000f0000, 0x00000016 },
+    { 0x452f272d, 0000000000 },
+    { 0x000f0001, 0x00000016 },
+    { 0x3e4d4a37, 0000000000 },
+    { 0x000077ef, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x00000020, 0x0000001a },
+    { 0x00004000, 0x0000001e },
+    { 0x00061000, 0x00000002 },
+    { 0x00000020, 0x0000001a },
+    { 0x00004000, 0x0000001e },
+    { 0x00061000, 0x00000002 },
+    { 0x00000020, 0x0000001a },
+    { 0x00004000, 0x0000001e },
+    { 0x00000016, 0x00000004 },
+    { 0x0003802a, 0x00000002 },
+    { 0x040067e0, 0x00000002 },
+    { 0x00000016, 0x00000004 },
+    { 0x000077e0, 0x00000002 },
+    { 0x00065000, 0x00000002 },
+    { 0x000037e1, 0x00000002 },
+    { 0x040067e1, 0x00000006 },
+    { 0x000077e0, 0x00000002 },
+    { 0x000077e1, 0x00000002 },
+    { 0x000077e1, 0x00000006 },
+    { 0xffffffff, 0000000000 },
+    { 0x10000000, 0000000000 },
+    { 0x07f007f0, 0000000000 },
+    { 0x0003802a, 0x00000002 },
+    { 0x040067e0, 0x00000006 },
+    { 0x0003802c, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002743, 0x00000002 },
+    { 0x00007675, 0x00000002 },
+    { 0x00007676, 0x00000002 },
+    { 0x00007677, 0x00000002 },
+    { 0x00007678, 0x00000006 },
+    { 0x0003802c, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002743, 0x00000002 },
+    { 0x00007676, 0x00000002 },
+    { 0x00007677, 0x00000002 },
+    { 0x00007678, 0x00000006 },
+    { 0x0003802b, 0x00000002 },
+    { 0x04002676, 0x00000002 },
+    { 0x00007677, 0x00000002 },
+    { 0x0003802c, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002743, 0x00000002 },
+    { 0x00007678, 0x00000006 },
+    { 0x0003802c, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002741, 0x00000002 },
+    { 0x04002743, 0x00000002 },
+    { 0x00007678, 0x00000006 },
+    { 0x0000002f, 0x00000018 },
+    { 0x0000002f, 0x00000018 },
+    { 0000000000, 0x00000006 },
+    { 0x00000037, 0x00000018 },
+    { 0x00000037, 0x00000018 },
+    { 0000000000, 0x00000006 },
+    { 0x01605000, 0x00000002 },
+    { 0x00065000, 0x00000002 },
+    { 0x00098000, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x64c06051, 0x00000004 },
+    { 0x00080000, 0x00000016 },
+    { 0000000000, 0000000000 },
+    { 0x0400251d, 0x00000002 },
+    { 0x00007580, 0x00000002 },
+    { 0x00067581, 0x00000002 },
+    { 0x04002580, 0x00000002 },
+    { 0x00067581, 0x00000002 },
+    { 0x0000005a, 0x00000004 },
+    { 0x00005000, 0000000000 },
+    { 0x00061000, 0x00000002 },
+    { 0x0000750e, 0x00000002 },
+    { 0x00019000, 0x00000002 },
+    { 0x00011064, 0x00000014 },
+    { 0x00000064, 0x00000012 },
+    { 0x0400250f, 0x00000002 },
+    { 0x0000505e, 0x00000004 },
+    { 0x00007565, 0x00000002 },
+    { 0x00007566, 0x00000002 },
+    { 0x00000065, 0x00000004 },
+    { 0x01e655b4, 0x00000002 },
+    { 0x4401b0f0, 0x00000002 },
+    { 0x01c110f0, 0x00000002 },
+    { 0x26667071, 0x00000018 },
+    { 0x040c2565, 0x00000002 },
+    { 0x00000071, 0x00000018 },
+    { 0x04002564, 0x00000002 },
+    { 0x00007566, 0x00000002 },
+    { 0x00000068, 0x00000004 },
+    { 0x00401074, 0x00000008 },
+    { 0x00101000, 0x00000002 },
+    { 0x000d80ff, 0x00000002 },
+    { 0x00800077, 0x00000008 },
+    { 0x000f9000, 0x00000002 },
+    { 0x000e00ff, 0x00000002 },
+    { 0000000000, 0x00000006 },
+    { 0x00000094, 0x00000018 },
+    { 0x00000068, 0x00000004 },
+    { 0x00007576, 0x00000002 },
+    { 0x00065000, 0x00000002 },
+    { 0x00009000, 0x00000002 },
+    { 0x00041000, 0x00000002 },
+    { 0x0c00350e, 0x00000002 },
+    { 0x00049000, 0x00000002 },
+    { 0x00051000, 0x00000002 },
+    { 0x01e785f8, 0x00000002 },
+    { 0x00200000, 0x00000002 },
+    { 0x00600087, 0x0000000c },
+    { 0x00007563, 0x00000002 },
+    { 0x006075f0, 0x00000021 },
+    { 0x2000707c, 0x00000004 },
+    { 0x0000507c, 0x00000004 },
+    { 0x00007576, 0x00000002 },
+    { 0x00007577, 0x00000002 },
+    { 0x0000750e, 0x00000002 },
+    { 0x0000750f, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x0060008a, 0x0000000c },
+    { 0x006075f0, 0x00000021 },
+    { 0x000075f8, 0x00000002 },
+    { 0x0000008a, 0x00000004 },
+    { 0x000a750e, 0x00000002 },
+    { 0x0020750f, 0x00000002 },
+    { 0x0060008d, 0x00000004 },
+    { 0x00007570, 0x00000002 },
+    { 0x00007571, 0x00000002 },
+    { 0x00007572, 0x00000006 },
+    { 0x00005000, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x00007568, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x00000098, 0x0000000c },
+    { 0x00058000, 0x00000002 },
+    { 0x0c607562, 0x00000002 },
+    { 0x0000009a, 0x00000004 },
+    { 0x00600099, 0x00000004 },
+    { 0x400070f1, 0000000000 },
+    { 0x000380f1, 0x00000002 },
+    { 0x000000a7, 0x0000001c },
+    { 0x000650a9, 0x00000018 },
+    { 0x040025bb, 0x00000002 },
+    { 0x000610aa, 0x00000018 },
+    { 0x040075bc, 0000000000 },
+    { 0x000075bb, 0x00000002 },
+    { 0x000075bc, 0000000000 },
+    { 0x00090000, 0x00000006 },
+    { 0x00090000, 0x00000002 },
+    { 0x000d8002, 0x00000006 },
+    { 0x00005000, 0x00000002 },
+    { 0x00007821, 0x00000002 },
+    { 0x00007800, 0000000000 },
+    { 0x00007821, 0x00000002 },
+    { 0x00007800, 0000000000 },
+    { 0x01665000, 0x00000002 },
+    { 0x000a0000, 0x00000002 },
+    { 0x000671cc, 0x00000002 },
+    { 0x0286f1cd, 0x00000002 },
+    { 0x000000b7, 0x00000010 },
+    { 0x21007000, 0000000000 },
+    { 0x000000be, 0x0000001c },
+    { 0x00065000, 0x00000002 },
+    { 0x000a0000, 0x00000002 },
+    { 0x00061000, 0x00000002 },
+    { 0x000b0000, 0x00000002 },
+    { 0x38067000, 0x00000002 },
+    { 0x000a00ba, 0x00000004 },
+    { 0x20007000, 0000000000 },
+    { 0x01200000, 0x00000002 },
+    { 0x20077000, 0x00000002 },
+    { 0x01200000, 0x00000002 },
+    { 0x20007000, 0000000000 },
+    { 0x00061000, 0x00000002 },
+    { 0x0120751b, 0x00000002 },
+    { 0x8040750a, 0x00000002 },
+    { 0x8040750b, 0x00000002 },
+    { 0x00110000, 0x00000002 },
+    { 0x000380f1, 0x00000002 },
+    { 0x000000d1, 0x0000001c },
+    { 0x000610aa, 0x00000018 },
+    { 0x844075bd, 0x00000002 },
+    { 0x000610a9, 0x00000018 },
+    { 0x840075bb, 0x00000002 },
+    { 0x000610aa, 0x00000018 },
+    { 0x844075bc, 0x00000002 },
+    { 0x000000d4, 0x00000004 },
+    { 0x804075bd, 0x00000002 },
+    { 0x800075bb, 0x00000002 },
+    { 0x804075bc, 0x00000002 },
+    { 0x00108000, 0x00000002 },
+    { 0x01400000, 0x00000002 },
+    { 0x006000d8, 0x0000000c },
+    { 0x20c07000, 0x00000020 },
+    { 0x000000da, 0x00000012 },
+    { 0x00800000, 0x00000006 },
+    { 0x0080751d, 0x00000006 },
+    { 0x000025bb, 0x00000002 },
+    { 0x000040d4, 0x00000004 },
+    { 0x0000775c, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x00661000, 0x00000002 },
+    { 0x0460275d, 0x00000020 },
+    { 0x00004000, 0000000000 },
+    { 0x00007999, 0x00000002 },
+    { 0x00a05000, 0x00000002 },
+    { 0x00661000, 0x00000002 },
+    { 0x0460299b, 0x00000020 },
+    { 0x00004000, 0000000000 },
+    { 0x01e00830, 0x00000002 },
+    { 0x21007000, 0000000000 },
+    { 0x00005000, 0x00000002 },
+    { 0x00038056, 0x00000002 },
+    { 0x040025e0, 0x00000002 },
+    { 0x000075e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000380ed, 0x00000002 },
+    { 0x04007394, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x000078c4, 0x00000002 },
+    { 0x000078c5, 0x00000002 },
+    { 0x000078c6, 0x00000002 },
+    { 0x00007924, 0x00000002 },
+    { 0x00007925, 0x00000002 },
+    { 0x00007926, 0x00000002 },
+    { 0x000000f2, 0x00000004 },
+    { 0x00007924, 0x00000002 },
+    { 0x00007925, 0x00000002 },
+    { 0x00007926, 0x00000002 },
+    { 0x000000f9, 0x00000004 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+static const u32 R300_cp_microcode[][2] = {
+    { 0x4200e000, 0000000000 },
+    { 0x4000e000, 0000000000 },
+    { 0x000000ae, 0x00000008 },
+    { 0x000000b2, 0x00000008 },
+    { 0x67554b4a, 0000000000 },
+    { 0x4a4a4475, 0000000000 },
+    { 0x55527d83, 0000000000 },
+    { 0x4a8c8b65, 0000000000 },
+    { 0x4aef4af6, 0000000000 },
+    { 0x4ae14a4a, 0000000000 },
+    { 0xe4979797, 0000000000 },
+    { 0xdb4aebdd, 0000000000 },
+    { 0x9ccc4a4a, 0000000000 },
+    { 0xd1989898, 0000000000 },
+    { 0x4a0f9ad6, 0000000000 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000d0012, 0x00000038 },
+    { 0x0000e8b4, 0x00000004 },
+    { 0x000d0014, 0x00000038 },
+    { 0x0000e8b6, 0x00000004 },
+    { 0x000d0016, 0x00000038 },
+    { 0x0000e854, 0x00000004 },
+    { 0x000d0018, 0x00000038 },
+    { 0x0000e855, 0x00000004 },
+    { 0x000d001a, 0x00000038 },
+    { 0x0000e856, 0x00000004 },
+    { 0x000d001c, 0x00000038 },
+    { 0x0000e857, 0x00000004 },
+    { 0x000d001e, 0x00000038 },
+    { 0x0000e824, 0x00000004 },
+    { 0x000d0020, 0x00000038 },
+    { 0x0000e825, 0x00000004 },
+    { 0x000d0022, 0x00000038 },
+    { 0x0000e830, 0x00000004 },
+    { 0x000d0024, 0x00000038 },
+    { 0x0000f0c0, 0x00000004 },
+    { 0x000d0026, 0x00000038 },
+    { 0x0000f0c1, 0x00000004 },
+    { 0x000d0028, 0x00000038 },
+    { 0x0000f041, 0x00000004 },
+    { 0x000d002a, 0x00000038 },
+    { 0x0000f184, 0x00000004 },
+    { 0x000d002c, 0x00000038 },
+    { 0x0000f185, 0x00000004 },
+    { 0x000d002e, 0x00000038 },
+    { 0x0000f186, 0x00000004 },
+    { 0x000d0030, 0x00000038 },
+    { 0x0000f187, 0x00000004 },
+    { 0x000d0032, 0x00000038 },
+    { 0x0000f180, 0x00000004 },
+    { 0x000d0034, 0x00000038 },
+    { 0x0000f393, 0x00000004 },
+    { 0x000d0036, 0x00000038 },
+    { 0x0000f38a, 0x00000004 },
+    { 0x000d0038, 0x00000038 },
+    { 0x0000f38e, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000043, 0x00000018 },
+    { 0x00cce800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x0000003a, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x2000451d, 0x00000004 },
+    { 0x0000e580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x08004580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x00000047, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x00032000, 0x00000004 },
+    { 0x00022051, 0x00000028 },
+    { 0x00000051, 0x00000024 },
+    { 0x0800450f, 0x00000004 },
+    { 0x0000a04b, 0x00000008 },
+    { 0x0000e565, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000052, 0x00000008 },
+    { 0x03cca5b4, 0x00000004 },
+    { 0x05432000, 0x00000004 },
+    { 0x00022000, 0x00000004 },
+    { 0x4ccce05e, 0x00000030 },
+    { 0x08274565, 0x00000004 },
+    { 0x0000005e, 0x00000030 },
+    { 0x08004564, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000055, 0x00000008 },
+    { 0x00802061, 0x00000010 },
+    { 0x00202000, 0x00000004 },
+    { 0x001b00ff, 0x00000004 },
+    { 0x01000064, 0x00000010 },
+    { 0x001f2000, 0x00000004 },
+    { 0x001c00ff, 0x00000004 },
+    { 0000000000, 0x0000000c },
+    { 0x00000080, 0x00000030 },
+    { 0x00000055, 0x00000008 },
+    { 0x0000e576, 0x00000004 },
+    { 0x000ca000, 0x00000004 },
+    { 0x00012000, 0x00000004 },
+    { 0x00082000, 0x00000004 },
+    { 0x1800650e, 0x00000004 },
+    { 0x00092000, 0x00000004 },
+    { 0x000a2000, 0x00000004 },
+    { 0x000f0000, 0x00000004 },
+    { 0x00400000, 0x00000004 },
+    { 0x00000074, 0x00000018 },
+    { 0x0000e563, 0x00000004 },
+    { 0x00c0e5f9, 0x000000c2 },
+    { 0x00000069, 0x00000008 },
+    { 0x0000a069, 0x00000008 },
+    { 0x0000e576, 0x00000004 },
+    { 0x0000e577, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x0000e50f, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000077, 0x00000018 },
+    { 0x00c0e5f9, 0x000000c2 },
+    { 0x00000077, 0x00000008 },
+    { 0x0014e50e, 0x00000004 },
+    { 0x0040e50f, 0x00000004 },
+    { 0x00c0007a, 0x00000008 },
+    { 0x0000e570, 0x00000004 },
+    { 0x0000e571, 0x00000004 },
+    { 0x0000e572, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x0000e568, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00000084, 0x00000018 },
+    { 0x000b0000, 0x00000004 },
+    { 0x18c0e562, 0x00000004 },
+    { 0x00000086, 0x00000008 },
+    { 0x00c00085, 0x00000008 },
+    { 0x000700e3, 0x00000004 },
+    { 0x00000092, 0x00000038 },
+    { 0x000ca094, 0x00000030 },
+    { 0x080045bb, 0x00000004 },
+    { 0x000c2095, 0x00000030 },
+    { 0x0800e5bc, 0000000000 },
+    { 0x0000e5bb, 0x00000004 },
+    { 0x0000e5bc, 0000000000 },
+    { 0x00120000, 0x0000000c },
+    { 0x00120000, 0x00000004 },
+    { 0x001b0002, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e800, 0000000000 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e82e, 0000000000 },
+    { 0x02cca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000ce1cc, 0x00000004 },
+    { 0x050de1cd, 0x00000004 },
+    { 0x00400000, 0x00000004 },
+    { 0x000000a4, 0x00000018 },
+    { 0x00c0a000, 0x00000004 },
+    { 0x000000a1, 0x00000008 },
+    { 0x000000a6, 0x00000020 },
+    { 0x4200e000, 0000000000 },
+    { 0x000000ad, 0x00000038 },
+    { 0x000ca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00160000, 0x00000004 },
+    { 0x700ce000, 0x00000004 },
+    { 0x001400a9, 0x00000008 },
+    { 0x4000e000, 0000000000 },
+    { 0x02400000, 0x00000004 },
+    { 0x400ee000, 0x00000004 },
+    { 0x02400000, 0x00000004 },
+    { 0x4000e000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0240e51b, 0x00000004 },
+    { 0x0080e50a, 0x00000005 },
+    { 0x0080e50b, 0x00000005 },
+    { 0x00220000, 0x00000004 },
+    { 0x000700e3, 0x00000004 },
+    { 0x000000c0, 0x00000038 },
+    { 0x000c2095, 0x00000030 },
+    { 0x0880e5bd, 0x00000005 },
+    { 0x000c2094, 0x00000030 },
+    { 0x0800e5bb, 0x00000005 },
+    { 0x000c2095, 0x00000030 },
+    { 0x0880e5bc, 0x00000005 },
+    { 0x000000c3, 0x00000008 },
+    { 0x0080e5bd, 0x00000005 },
+    { 0x0000e5bb, 0x00000005 },
+    { 0x0080e5bc, 0x00000005 },
+    { 0x00210000, 0x00000004 },
+    { 0x02800000, 0x00000004 },
+    { 0x00c000c7, 0x00000018 },
+    { 0x4180e000, 0x00000040 },
+    { 0x000000c9, 0x00000024 },
+    { 0x01000000, 0x0000000c },
+    { 0x0100e51d, 0x0000000c },
+    { 0x000045bb, 0x00000004 },
+    { 0x000080c3, 0x00000008 },
+    { 0x0000f3ce, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053cf, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f3d2, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053d3, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f39d, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c0539e, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x03c00830, 0x00000004 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x200045e0, 0x00000004 },
+    { 0x0000e5e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000700e0, 0x00000004 },
+    { 0x0800e394, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x0000e8c4, 0x00000004 },
+    { 0x0000e8c5, 0x00000004 },
+    { 0x0000e8c6, 0x00000004 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000e4, 0x00000008 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000eb, 0x00000008 },
+    { 0x02c02000, 0x00000004 },
+    { 0x00060000, 0x00000004 },
+    { 0x000000f3, 0x00000034 },
+    { 0x000000f0, 0x00000008 },
+    { 0x00008000, 0x00000004 },
+    { 0xc000e000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x001d0018, 0x00000004 },
+    { 0x001a0001, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0x0500a04a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+static const u32 R420_cp_microcode[][2] = {
+    { 0x4200e000, 0000000000 },
+    { 0x4000e000, 0000000000 },
+    { 0x00000099, 0x00000008 },
+    { 0x0000009d, 0x00000008 },
+    { 0x4a554b4a, 0000000000 },
+    { 0x4a4a4467, 0000000000 },
+    { 0x55526f75, 0000000000 },
+    { 0x4a7e7d65, 0000000000 },
+    { 0xd9d3dff6, 0000000000 },
+    { 0x4ac54a4a, 0000000000 },
+    { 0xc8828282, 0000000000 },
+    { 0xbf4acfc1, 0000000000 },
+    { 0x87b04a4a, 0000000000 },
+    { 0xb5838383, 0000000000 },
+    { 0x4a0f85ba, 0000000000 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000d0012, 0x00000038 },
+    { 0x0000e8b4, 0x00000004 },
+    { 0x000d0014, 0x00000038 },
+    { 0x0000e8b6, 0x00000004 },
+    { 0x000d0016, 0x00000038 },
+    { 0x0000e854, 0x00000004 },
+    { 0x000d0018, 0x00000038 },
+    { 0x0000e855, 0x00000004 },
+    { 0x000d001a, 0x00000038 },
+    { 0x0000e856, 0x00000004 },
+    { 0x000d001c, 0x00000038 },
+    { 0x0000e857, 0x00000004 },
+    { 0x000d001e, 0x00000038 },
+    { 0x0000e824, 0x00000004 },
+    { 0x000d0020, 0x00000038 },
+    { 0x0000e825, 0x00000004 },
+    { 0x000d0022, 0x00000038 },
+    { 0x0000e830, 0x00000004 },
+    { 0x000d0024, 0x00000038 },
+    { 0x0000f0c0, 0x00000004 },
+    { 0x000d0026, 0x00000038 },
+    { 0x0000f0c1, 0x00000004 },
+    { 0x000d0028, 0x00000038 },
+    { 0x0000f041, 0x00000004 },
+    { 0x000d002a, 0x00000038 },
+    { 0x0000f184, 0x00000004 },
+    { 0x000d002c, 0x00000038 },
+    { 0x0000f185, 0x00000004 },
+    { 0x000d002e, 0x00000038 },
+    { 0x0000f186, 0x00000004 },
+    { 0x000d0030, 0x00000038 },
+    { 0x0000f187, 0x00000004 },
+    { 0x000d0032, 0x00000038 },
+    { 0x0000f180, 0x00000004 },
+    { 0x000d0034, 0x00000038 },
+    { 0x0000f393, 0x00000004 },
+    { 0x000d0036, 0x00000038 },
+    { 0x0000f38a, 0x00000004 },
+    { 0x000d0038, 0x00000038 },
+    { 0x0000f38e, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000043, 0x00000018 },
+    { 0x00cce800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x0000003a, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x2000451d, 0x00000004 },
+    { 0x0000e580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x08004580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x00000047, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x00032000, 0x00000004 },
+    { 0x00022051, 0x00000028 },
+    { 0x00000051, 0x00000024 },
+    { 0x0800450f, 0x00000004 },
+    { 0x0000a04b, 0x00000008 },
+    { 0x0000e565, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000052, 0x00000008 },
+    { 0x03cca5b4, 0x00000004 },
+    { 0x05432000, 0x00000004 },
+    { 0x00022000, 0x00000004 },
+    { 0x4ccce05e, 0x00000030 },
+    { 0x08274565, 0x00000004 },
+    { 0x0000005e, 0x00000030 },
+    { 0x08004564, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000055, 0x00000008 },
+    { 0x00802061, 0x00000010 },
+    { 0x00202000, 0x00000004 },
+    { 0x001b00ff, 0x00000004 },
+    { 0x01000064, 0x00000010 },
+    { 0x001f2000, 0x00000004 },
+    { 0x001c00ff, 0x00000004 },
+    { 0000000000, 0x0000000c },
+    { 0x00000072, 0x00000030 },
+    { 0x00000055, 0x00000008 },
+    { 0x0000e576, 0x00000004 },
+    { 0x0000e577, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x0000e50f, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000069, 0x00000018 },
+    { 0x00c0e5f9, 0x000000c2 },
+    { 0x00000069, 0x00000008 },
+    { 0x0014e50e, 0x00000004 },
+    { 0x0040e50f, 0x00000004 },
+    { 0x00c0006c, 0x00000008 },
+    { 0x0000e570, 0x00000004 },
+    { 0x0000e571, 0x00000004 },
+    { 0x0000e572, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x0000e568, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00000076, 0x00000018 },
+    { 0x000b0000, 0x00000004 },
+    { 0x18c0e562, 0x00000004 },
+    { 0x00000078, 0x00000008 },
+    { 0x00c00077, 0x00000008 },
+    { 0x000700c7, 0x00000004 },
+    { 0x00000080, 0x00000038 },
+    { 0x0000e5bb, 0x00000004 },
+    { 0x0000e5bc, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e800, 0000000000 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e82e, 0000000000 },
+    { 0x02cca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000ce1cc, 0x00000004 },
+    { 0x050de1cd, 0x00000004 },
+    { 0x00400000, 0x00000004 },
+    { 0x0000008f, 0x00000018 },
+    { 0x00c0a000, 0x00000004 },
+    { 0x0000008c, 0x00000008 },
+    { 0x00000091, 0x00000020 },
+    { 0x4200e000, 0000000000 },
+    { 0x00000098, 0x00000038 },
+    { 0x000ca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00160000, 0x00000004 },
+    { 0x700ce000, 0x00000004 },
+    { 0x00140094, 0x00000008 },
+    { 0x4000e000, 0000000000 },
+    { 0x02400000, 0x00000004 },
+    { 0x400ee000, 0x00000004 },
+    { 0x02400000, 0x00000004 },
+    { 0x4000e000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0240e51b, 0x00000004 },
+    { 0x0080e50a, 0x00000005 },
+    { 0x0080e50b, 0x00000005 },
+    { 0x00220000, 0x00000004 },
+    { 0x000700c7, 0x00000004 },
+    { 0x000000a4, 0x00000038 },
+    { 0x0080e5bd, 0x00000005 },
+    { 0x0000e5bb, 0x00000005 },
+    { 0x0080e5bc, 0x00000005 },
+    { 0x00210000, 0x00000004 },
+    { 0x02800000, 0x00000004 },
+    { 0x00c000ab, 0x00000018 },
+    { 0x4180e000, 0x00000040 },
+    { 0x000000ad, 0x00000024 },
+    { 0x01000000, 0x0000000c },
+    { 0x0100e51d, 0x0000000c },
+    { 0x000045bb, 0x00000004 },
+    { 0x000080a7, 0x00000008 },
+    { 0x0000f3ce, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053cf, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f3d2, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053d3, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f39d, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c0539e, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x03c00830, 0x00000004 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x200045e0, 0x00000004 },
+    { 0x0000e5e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000700c4, 0x00000004 },
+    { 0x0800e394, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x0000e8c4, 0x00000004 },
+    { 0x0000e8c5, 0x00000004 },
+    { 0x0000e8c6, 0x00000004 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000c8, 0x00000008 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000cf, 0x00000008 },
+    { 0x02c02000, 0x00000004 },
+    { 0x00060000, 0x00000004 },
+    { 0x000000d7, 0x00000034 },
+    { 0x000000d4, 0x00000008 },
+    { 0x00008000, 0x00000004 },
+    { 0xc000e000, 0000000000 },
+    { 0x0000e1cc, 0x00000004 },
+    { 0x0500e1cd, 0x00000004 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000000de, 0x00000034 },
+    { 0x000000da, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x0019e1cc, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x0500a000, 0x00000004 },
+    { 0x080041cd, 0x00000004 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x001d0018, 0x00000004 },
+    { 0x001a0001, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0x0500a04a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+static const u32 RS600_cp_microcode[][2] = {
+    { 0x4200e000, 0000000000 },
+    { 0x4000e000, 0000000000 },
+    { 0x000000a0, 0x00000008 },
+    { 0x000000a4, 0x00000008 },
+    { 0x4a554b4a, 0000000000 },
+    { 0x4a4a4467, 0000000000 },
+    { 0x55526f75, 0000000000 },
+    { 0x4a7e7d65, 0000000000 },
+    { 0x4ae74af6, 0000000000 },
+    { 0x4ad34a4a, 0000000000 },
+    { 0xd6898989, 0000000000 },
+    { 0xcd4addcf, 0000000000 },
+    { 0x8ebe4ae2, 0000000000 },
+    { 0xc38a8a8a, 0000000000 },
+    { 0x4a0f8cc8, 0000000000 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000d0012, 0x00000038 },
+    { 0x0000e8b4, 0x00000004 },
+    { 0x000d0014, 0x00000038 },
+    { 0x0000e8b6, 0x00000004 },
+    { 0x000d0016, 0x00000038 },
+    { 0x0000e854, 0x00000004 },
+    { 0x000d0018, 0x00000038 },
+    { 0x0000e855, 0x00000004 },
+    { 0x000d001a, 0x00000038 },
+    { 0x0000e856, 0x00000004 },
+    { 0x000d001c, 0x00000038 },
+    { 0x0000e857, 0x00000004 },
+    { 0x000d001e, 0x00000038 },
+    { 0x0000e824, 0x00000004 },
+    { 0x000d0020, 0x00000038 },
+    { 0x0000e825, 0x00000004 },
+    { 0x000d0022, 0x00000038 },
+    { 0x0000e830, 0x00000004 },
+    { 0x000d0024, 0x00000038 },
+    { 0x0000f0c0, 0x00000004 },
+    { 0x000d0026, 0x00000038 },
+    { 0x0000f0c1, 0x00000004 },
+    { 0x000d0028, 0x00000038 },
+    { 0x0000f041, 0x00000004 },
+    { 0x000d002a, 0x00000038 },
+    { 0x0000f184, 0x00000004 },
+    { 0x000d002c, 0x00000038 },
+    { 0x0000f185, 0x00000004 },
+    { 0x000d002e, 0x00000038 },
+    { 0x0000f186, 0x00000004 },
+    { 0x000d0030, 0x00000038 },
+    { 0x0000f187, 0x00000004 },
+    { 0x000d0032, 0x00000038 },
+    { 0x0000f180, 0x00000004 },
+    { 0x000d0034, 0x00000038 },
+    { 0x0000f393, 0x00000004 },
+    { 0x000d0036, 0x00000038 },
+    { 0x0000f38a, 0x00000004 },
+    { 0x000d0038, 0x00000038 },
+    { 0x0000f38e, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000043, 0x00000018 },
+    { 0x00cce800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x0000003a, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x2000451d, 0x00000004 },
+    { 0x0000e580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x08004580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x00000047, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x00032000, 0x00000004 },
+    { 0x00022051, 0x00000028 },
+    { 0x00000051, 0x00000024 },
+    { 0x0800450f, 0x00000004 },
+    { 0x0000a04b, 0x00000008 },
+    { 0x0000e565, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000052, 0x00000008 },
+    { 0x03cca5b4, 0x00000004 },
+    { 0x05432000, 0x00000004 },
+    { 0x00022000, 0x00000004 },
+    { 0x4ccce05e, 0x00000030 },
+    { 0x08274565, 0x00000004 },
+    { 0x0000005e, 0x00000030 },
+    { 0x08004564, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000055, 0x00000008 },
+    { 0x00802061, 0x00000010 },
+    { 0x00202000, 0x00000004 },
+    { 0x001b00ff, 0x00000004 },
+    { 0x01000064, 0x00000010 },
+    { 0x001f2000, 0x00000004 },
+    { 0x001c00ff, 0x00000004 },
+    { 0000000000, 0x0000000c },
+    { 0x00000072, 0x00000030 },
+    { 0x00000055, 0x00000008 },
+    { 0x0000e576, 0x00000004 },
+    { 0x0000e577, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x0000e50f, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000069, 0x00000018 },
+    { 0x00c0e5f9, 0x000000c2 },
+    { 0x00000069, 0x00000008 },
+    { 0x0014e50e, 0x00000004 },
+    { 0x0040e50f, 0x00000004 },
+    { 0x00c0006c, 0x00000008 },
+    { 0x0000e570, 0x00000004 },
+    { 0x0000e571, 0x00000004 },
+    { 0x0000e572, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x0000e568, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00000076, 0x00000018 },
+    { 0x000b0000, 0x00000004 },
+    { 0x18c0e562, 0x00000004 },
+    { 0x00000078, 0x00000008 },
+    { 0x00c00077, 0x00000008 },
+    { 0x000700d5, 0x00000004 },
+    { 0x00000084, 0x00000038 },
+    { 0x000ca086, 0x00000030 },
+    { 0x080045bb, 0x00000004 },
+    { 0x000c2087, 0x00000030 },
+    { 0x0800e5bc, 0000000000 },
+    { 0x0000e5bb, 0x00000004 },
+    { 0x0000e5bc, 0000000000 },
+    { 0x00120000, 0x0000000c },
+    { 0x00120000, 0x00000004 },
+    { 0x001b0002, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e800, 0000000000 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e82e, 0000000000 },
+    { 0x02cca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000ce1cc, 0x00000004 },
+    { 0x050de1cd, 0x00000004 },
+    { 0x00400000, 0x00000004 },
+    { 0x00000096, 0x00000018 },
+    { 0x00c0a000, 0x00000004 },
+    { 0x00000093, 0x00000008 },
+    { 0x00000098, 0x00000020 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000009f, 0x00000038 },
+    { 0x000ca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00160000, 0x00000004 },
+    { 0x700ce000, 0x00000004 },
+    { 0x0014009b, 0x00000008 },
+    { 0x4000e000, 0000000000 },
+    { 0x02400000, 0x00000004 },
+    { 0x400ee000, 0x00000004 },
+    { 0x02400000, 0x00000004 },
+    { 0x4000e000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0240e51b, 0x00000004 },
+    { 0x0080e50a, 0x00000005 },
+    { 0x0080e50b, 0x00000005 },
+    { 0x00220000, 0x00000004 },
+    { 0x000700d5, 0x00000004 },
+    { 0x000000b2, 0x00000038 },
+    { 0x000c2087, 0x00000030 },
+    { 0x0880e5bd, 0x00000005 },
+    { 0x000c2086, 0x00000030 },
+    { 0x0800e5bb, 0x00000005 },
+    { 0x000c2087, 0x00000030 },
+    { 0x0880e5bc, 0x00000005 },
+    { 0x000000b5, 0x00000008 },
+    { 0x0080e5bd, 0x00000005 },
+    { 0x0000e5bb, 0x00000005 },
+    { 0x0080e5bc, 0x00000005 },
+    { 0x00210000, 0x00000004 },
+    { 0x02800000, 0x00000004 },
+    { 0x00c000b9, 0x00000018 },
+    { 0x4180e000, 0x00000040 },
+    { 0x000000bb, 0x00000024 },
+    { 0x01000000, 0x0000000c },
+    { 0x0100e51d, 0x0000000c },
+    { 0x000045bb, 0x00000004 },
+    { 0x000080b5, 0x00000008 },
+    { 0x0000f3ce, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053cf, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f3d2, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053d3, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f39d, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c0539e, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x03c00830, 0x00000004 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x200045e0, 0x00000004 },
+    { 0x0000e5e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000700d2, 0x00000004 },
+    { 0x0800e394, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x0000e8c4, 0x00000004 },
+    { 0x0000e8c5, 0x00000004 },
+    { 0x0000e8c6, 0x00000004 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000d6, 0x00000008 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000dd, 0x00000008 },
+    { 0x00e00116, 0000000000 },
+    { 0x000700e1, 0x00000004 },
+    { 0x0800401c, 0x00000004 },
+    { 0x200050e7, 0x00000004 },
+    { 0x0000e01d, 0x00000004 },
+    { 0x000000e4, 0x00000008 },
+    { 0x02c02000, 0x00000004 },
+    { 0x00060000, 0x00000004 },
+    { 0x000000eb, 0x00000034 },
+    { 0x000000e8, 0x00000008 },
+    { 0x00008000, 0x00000004 },
+    { 0xc000e000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x001d0018, 0x00000004 },
+    { 0x001a0001, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0x0500a04a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+static const u32 RS690_cp_microcode[][2] = {
+    { 0x000000dd, 0x00000008 },
+    { 0x000000df, 0x00000008 },
+    { 0x000000a0, 0x00000008 },
+    { 0x000000a4, 0x00000008 },
+    { 0x4a554b4a, 0000000000 },
+    { 0x4a4a4467, 0000000000 },
+    { 0x55526f75, 0000000000 },
+    { 0x4a7e7d65, 0000000000 },
+    { 0x4ad74af6, 0000000000 },
+    { 0x4ac94a4a, 0000000000 },
+    { 0xcc898989, 0000000000 },
+    { 0xc34ad3c5, 0000000000 },
+    { 0x8e4a4a4a, 0000000000 },
+    { 0x4a8a8a8a, 0000000000 },
+    { 0x4a0f8c4a, 0000000000 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000d0012, 0x00000038 },
+    { 0x0000e8b4, 0x00000004 },
+    { 0x000d0014, 0x00000038 },
+    { 0x0000e8b6, 0x00000004 },
+    { 0x000d0016, 0x00000038 },
+    { 0x0000e854, 0x00000004 },
+    { 0x000d0018, 0x00000038 },
+    { 0x0000e855, 0x00000004 },
+    { 0x000d001a, 0x00000038 },
+    { 0x0000e856, 0x00000004 },
+    { 0x000d001c, 0x00000038 },
+    { 0x0000e857, 0x00000004 },
+    { 0x000d001e, 0x00000038 },
+    { 0x0000e824, 0x00000004 },
+    { 0x000d0020, 0x00000038 },
+    { 0x0000e825, 0x00000004 },
+    { 0x000d0022, 0x00000038 },
+    { 0x0000e830, 0x00000004 },
+    { 0x000d0024, 0x00000038 },
+    { 0x0000f0c0, 0x00000004 },
+    { 0x000d0026, 0x00000038 },
+    { 0x0000f0c1, 0x00000004 },
+    { 0x000d0028, 0x00000038 },
+    { 0x0000f041, 0x00000004 },
+    { 0x000d002a, 0x00000038 },
+    { 0x0000f184, 0x00000004 },
+    { 0x000d002c, 0x00000038 },
+    { 0x0000f185, 0x00000004 },
+    { 0x000d002e, 0x00000038 },
+    { 0x0000f186, 0x00000004 },
+    { 0x000d0030, 0x00000038 },
+    { 0x0000f187, 0x00000004 },
+    { 0x000d0032, 0x00000038 },
+    { 0x0000f180, 0x00000004 },
+    { 0x000d0034, 0x00000038 },
+    { 0x0000f393, 0x00000004 },
+    { 0x000d0036, 0x00000038 },
+    { 0x0000f38a, 0x00000004 },
+    { 0x000d0038, 0x00000038 },
+    { 0x0000f38e, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000043, 0x00000018 },
+    { 0x00cce800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x0000003a, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x2000451d, 0x00000004 },
+    { 0x0000e580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x08004580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x00000047, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x00032000, 0x00000004 },
+    { 0x00022051, 0x00000028 },
+    { 0x00000051, 0x00000024 },
+    { 0x0800450f, 0x00000004 },
+    { 0x0000a04b, 0x00000008 },
+    { 0x0000e565, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000052, 0x00000008 },
+    { 0x03cca5b4, 0x00000004 },
+    { 0x05432000, 0x00000004 },
+    { 0x00022000, 0x00000004 },
+    { 0x4ccce05e, 0x00000030 },
+    { 0x08274565, 0x00000004 },
+    { 0x0000005e, 0x00000030 },
+    { 0x08004564, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000055, 0x00000008 },
+    { 0x00802061, 0x00000010 },
+    { 0x00202000, 0x00000004 },
+    { 0x001b00ff, 0x00000004 },
+    { 0x01000064, 0x00000010 },
+    { 0x001f2000, 0x00000004 },
+    { 0x001c00ff, 0x00000004 },
+    { 0000000000, 0x0000000c },
+    { 0x00000072, 0x00000030 },
+    { 0x00000055, 0x00000008 },
+    { 0x0000e576, 0x00000004 },
+    { 0x0000e577, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x0000e50f, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000069, 0x00000018 },
+    { 0x00c0e5f9, 0x000000c2 },
+    { 0x00000069, 0x00000008 },
+    { 0x0014e50e, 0x00000004 },
+    { 0x0040e50f, 0x00000004 },
+    { 0x00c0006c, 0x00000008 },
+    { 0x0000e570, 0x00000004 },
+    { 0x0000e571, 0x00000004 },
+    { 0x0000e572, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x0000e568, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00000076, 0x00000018 },
+    { 0x000b0000, 0x00000004 },
+    { 0x18c0e562, 0x00000004 },
+    { 0x00000078, 0x00000008 },
+    { 0x00c00077, 0x00000008 },
+    { 0x000700cb, 0x00000004 },
+    { 0x00000084, 0x00000038 },
+    { 0x000ca086, 0x00000030 },
+    { 0x080045bb, 0x00000004 },
+    { 0x000c2087, 0x00000030 },
+    { 0x0800e5bc, 0000000000 },
+    { 0x0000e5bb, 0x00000004 },
+    { 0x0000e5bc, 0000000000 },
+    { 0x00120000, 0x0000000c },
+    { 0x00120000, 0x00000004 },
+    { 0x001b0002, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e800, 0000000000 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e82e, 0000000000 },
+    { 0x02cca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000ce1cc, 0x00000004 },
+    { 0x050de1cd, 0x00000004 },
+    { 0x00400000, 0x00000004 },
+    { 0x00000096, 0x00000018 },
+    { 0x00c0a000, 0x00000004 },
+    { 0x00000093, 0x00000008 },
+    { 0x00000098, 0x00000020 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000009f, 0x00000038 },
+    { 0x000ca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00160000, 0x00000004 },
+    { 0x700ce000, 0x00000004 },
+    { 0x0014009b, 0x00000008 },
+    { 0x4000e000, 0000000000 },
+    { 0x02400000, 0x00000004 },
+    { 0x400ee000, 0x00000004 },
+    { 0x02400000, 0x00000004 },
+    { 0x4000e000, 0000000000 },
+    { 0x00100000, 0x0000002c },
+    { 0x00004000, 0000000000 },
+    { 0x080045c8, 0x00000004 },
+    { 0x00240005, 0x00000004 },
+    { 0x08004d0b, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0240e51b, 0x00000004 },
+    { 0x0080e50a, 0x00000005 },
+    { 0x0080e50b, 0x00000005 },
+    { 0x00220000, 0x00000004 },
+    { 0x000700cb, 0x00000004 },
+    { 0x000000b7, 0x00000038 },
+    { 0x000c2087, 0x00000030 },
+    { 0x0880e5bd, 0x00000005 },
+    { 0x000c2086, 0x00000030 },
+    { 0x0800e5bb, 0x00000005 },
+    { 0x000c2087, 0x00000030 },
+    { 0x0880e5bc, 0x00000005 },
+    { 0x000000ba, 0x00000008 },
+    { 0x0080e5bd, 0x00000005 },
+    { 0x0000e5bb, 0x00000005 },
+    { 0x0080e5bc, 0x00000005 },
+    { 0x00210000, 0x00000004 },
+    { 0x02800000, 0x00000004 },
+    { 0x00c000be, 0x00000018 },
+    { 0x4180e000, 0x00000040 },
+    { 0x000000c0, 0x00000024 },
+    { 0x01000000, 0x0000000c },
+    { 0x0100e51d, 0x0000000c },
+    { 0x000045bb, 0x00000004 },
+    { 0x000080ba, 0x00000008 },
+    { 0x03c00830, 0x00000004 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x200045e0, 0x00000004 },
+    { 0x0000e5e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000700c8, 0x00000004 },
+    { 0x0800e394, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x0000e8c4, 0x00000004 },
+    { 0x0000e8c5, 0x00000004 },
+    { 0x0000e8c6, 0x00000004 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000cc, 0x00000008 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000d3, 0x00000008 },
+    { 0x02c02000, 0x00000004 },
+    { 0x00060000, 0x00000004 },
+    { 0x000000db, 0x00000034 },
+    { 0x000000d8, 0x00000008 },
+    { 0x00008000, 0x00000004 },
+    { 0xc000e000, 0000000000 },
+    { 0x000000e1, 0x00000030 },
+    { 0x4200e000, 0000000000 },
+    { 0x000000e1, 0x00000030 },
+    { 0x4000e000, 0000000000 },
+    { 0x0025001b, 0x00000004 },
+    { 0x00230000, 0x00000004 },
+    { 0x00250005, 0x00000004 },
+    { 0x000000e6, 0x00000034 },
+    { 0000000000, 0x0000000c },
+    { 0x00244000, 0x00000004 },
+    { 0x080045c8, 0x00000004 },
+    { 0x00240005, 0x00000004 },
+    { 0x08004d0b, 0x0000000c },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x001d0018, 0x00000004 },
+    { 0x001a0001, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0x0500a04a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+static const u32 R520_cp_microcode[][2] = {
+    { 0x4200e000, 0000000000 },
+    { 0x4000e000, 0000000000 },
+    { 0x00000099, 0x00000008 },
+    { 0x0000009d, 0x00000008 },
+    { 0x4a554b4a, 0000000000 },
+    { 0x4a4a4467, 0000000000 },
+    { 0x55526f75, 0000000000 },
+    { 0x4a7e7d65, 0000000000 },
+    { 0xe0dae6f6, 0000000000 },
+    { 0x4ac54a4a, 0000000000 },
+    { 0xc8828282, 0000000000 },
+    { 0xbf4acfc1, 0000000000 },
+    { 0x87b04ad5, 0000000000 },
+    { 0xb5838383, 0000000000 },
+    { 0x4a0f85ba, 0000000000 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000d0012, 0x00000038 },
+    { 0x0000e8b4, 0x00000004 },
+    { 0x000d0014, 0x00000038 },
+    { 0x0000e8b6, 0x00000004 },
+    { 0x000d0016, 0x00000038 },
+    { 0x0000e854, 0x00000004 },
+    { 0x000d0018, 0x00000038 },
+    { 0x0000e855, 0x00000004 },
+    { 0x000d001a, 0x00000038 },
+    { 0x0000e856, 0x00000004 },
+    { 0x000d001c, 0x00000038 },
+    { 0x0000e857, 0x00000004 },
+    { 0x000d001e, 0x00000038 },
+    { 0x0000e824, 0x00000004 },
+    { 0x000d0020, 0x00000038 },
+    { 0x0000e825, 0x00000004 },
+    { 0x000d0022, 0x00000038 },
+    { 0x0000e830, 0x00000004 },
+    { 0x000d0024, 0x00000038 },
+    { 0x0000f0c0, 0x00000004 },
+    { 0x000d0026, 0x00000038 },
+    { 0x0000f0c1, 0x00000004 },
+    { 0x000d0028, 0x00000038 },
+    { 0x0000e000, 0x00000004 },
+    { 0x000d002a, 0x00000038 },
+    { 0x0000e000, 0x00000004 },
+    { 0x000d002c, 0x00000038 },
+    { 0x0000e000, 0x00000004 },
+    { 0x000d002e, 0x00000038 },
+    { 0x0000e000, 0x00000004 },
+    { 0x000d0030, 0x00000038 },
+    { 0x0000e000, 0x00000004 },
+    { 0x000d0032, 0x00000038 },
+    { 0x0000f180, 0x00000004 },
+    { 0x000d0034, 0x00000038 },
+    { 0x0000f393, 0x00000004 },
+    { 0x000d0036, 0x00000038 },
+    { 0x0000f38a, 0x00000004 },
+    { 0x000d0038, 0x00000038 },
+    { 0x0000f38e, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000043, 0x00000018 },
+    { 0x00cce800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x08004800, 0x00000004 },
+    { 0x0000003a, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x2000451d, 0x00000004 },
+    { 0x0000e580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x08004580, 0x00000004 },
+    { 0x000ce581, 0x00000004 },
+    { 0x00000047, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x00032000, 0x00000004 },
+    { 0x00022051, 0x00000028 },
+    { 0x00000051, 0x00000024 },
+    { 0x0800450f, 0x00000004 },
+    { 0x0000a04b, 0x00000008 },
+    { 0x0000e565, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000052, 0x00000008 },
+    { 0x03cca5b4, 0x00000004 },
+    { 0x05432000, 0x00000004 },
+    { 0x00022000, 0x00000004 },
+    { 0x4ccce05e, 0x00000030 },
+    { 0x08274565, 0x00000004 },
+    { 0x0000005e, 0x00000030 },
+    { 0x08004564, 0x00000004 },
+    { 0x0000e566, 0x00000004 },
+    { 0x00000055, 0x00000008 },
+    { 0x00802061, 0x00000010 },
+    { 0x00202000, 0x00000004 },
+    { 0x001b00ff, 0x00000004 },
+    { 0x01000064, 0x00000010 },
+    { 0x001f2000, 0x00000004 },
+    { 0x001c00ff, 0x00000004 },
+    { 0000000000, 0x0000000c },
+    { 0x00000072, 0x00000030 },
+    { 0x00000055, 0x00000008 },
+    { 0x0000e576, 0x00000004 },
+    { 0x0000e577, 0x00000004 },
+    { 0x0000e50e, 0x00000004 },
+    { 0x0000e50f, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00000069, 0x00000018 },
+    { 0x00c0e5f9, 0x000000c2 },
+    { 0x00000069, 0x00000008 },
+    { 0x0014e50e, 0x00000004 },
+    { 0x0040e50f, 0x00000004 },
+    { 0x00c0006c, 0x00000008 },
+    { 0x0000e570, 0x00000004 },
+    { 0x0000e571, 0x00000004 },
+    { 0x0000e572, 0x0000000c },
+    { 0x0000a000, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x0000e568, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00000076, 0x00000018 },
+    { 0x000b0000, 0x00000004 },
+    { 0x18c0e562, 0x00000004 },
+    { 0x00000078, 0x00000008 },
+    { 0x00c00077, 0x00000008 },
+    { 0x000700c7, 0x00000004 },
+    { 0x00000080, 0x00000038 },
+    { 0x0000e5bb, 0x00000004 },
+    { 0x0000e5bc, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e800, 0000000000 },
+    { 0x0000e821, 0x00000004 },
+    { 0x0000e82e, 0000000000 },
+    { 0x02cca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000ce1cc, 0x00000004 },
+    { 0x050de1cd, 0x00000004 },
+    { 0x00400000, 0x00000004 },
+    { 0x0000008f, 0x00000018 },
+    { 0x00c0a000, 0x00000004 },
+    { 0x0000008c, 0x00000008 },
+    { 0x00000091, 0x00000020 },
+    { 0x4200e000, 0000000000 },
+    { 0x00000098, 0x00000038 },
+    { 0x000ca000, 0x00000004 },
+    { 0x00140000, 0x00000004 },
+    { 0x000c2000, 0x00000004 },
+    { 0x00160000, 0x00000004 },
+    { 0x700ce000, 0x00000004 },
+    { 0x00140094, 0x00000008 },
+    { 0x4000e000, 0000000000 },
+    { 0x02400000, 0x00000004 },
+    { 0x400ee000, 0x00000004 },
+    { 0x02400000, 0x00000004 },
+    { 0x4000e000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x0240e51b, 0x00000004 },
+    { 0x0080e50a, 0x00000005 },
+    { 0x0080e50b, 0x00000005 },
+    { 0x00220000, 0x00000004 },
+    { 0x000700c7, 0x00000004 },
+    { 0x000000a4, 0x00000038 },
+    { 0x0080e5bd, 0x00000005 },
+    { 0x0000e5bb, 0x00000005 },
+    { 0x0080e5bc, 0x00000005 },
+    { 0x00210000, 0x00000004 },
+    { 0x02800000, 0x00000004 },
+    { 0x00c000ab, 0x00000018 },
+    { 0x4180e000, 0x00000040 },
+    { 0x000000ad, 0x00000024 },
+    { 0x01000000, 0x0000000c },
+    { 0x0100e51d, 0x0000000c },
+    { 0x000045bb, 0x00000004 },
+    { 0x000080a7, 0x00000008 },
+    { 0x0000f3ce, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053cf, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f3d2, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c053d3, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x0000f39d, 0x00000004 },
+    { 0x0140a000, 0x00000004 },
+    { 0x00cc2000, 0x00000004 },
+    { 0x08c0539e, 0x00000040 },
+    { 0x00008000, 0000000000 },
+    { 0x03c00830, 0x00000004 },
+    { 0x4200e000, 0000000000 },
+    { 0x0000a000, 0x00000004 },
+    { 0x200045e0, 0x00000004 },
+    { 0x0000e5e1, 0000000000 },
+    { 0x00000001, 0000000000 },
+    { 0x000700c4, 0x00000004 },
+    { 0x0800e394, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x0000e8c4, 0x00000004 },
+    { 0x0000e8c5, 0x00000004 },
+    { 0x0000e8c6, 0x00000004 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000c8, 0x00000008 },
+    { 0x0000e928, 0x00000004 },
+    { 0x0000e929, 0x00000004 },
+    { 0x0000e92a, 0x00000004 },
+    { 0x000000cf, 0x00000008 },
+    { 0xdeadbeef, 0000000000 },
+    { 0x00000116, 0000000000 },
+    { 0x000700d3, 0x00000004 },
+    { 0x080050e7, 0x00000004 },
+    { 0x000700d4, 0x00000004 },
+    { 0x0800401c, 0x00000004 },
+    { 0x0000e01d, 0000000000 },
+    { 0x02c02000, 0x00000004 },
+    { 0x00060000, 0x00000004 },
+    { 0x000000de, 0x00000034 },
+    { 0x000000db, 0x00000008 },
+    { 0x00008000, 0x00000004 },
+    { 0xc000e000, 0000000000 },
+    { 0x0000e1cc, 0x00000004 },
+    { 0x0500e1cd, 0x00000004 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000000e5, 0x00000034 },
+    { 0x000000e1, 0x00000008 },
+    { 0x0000a000, 0000000000 },
+    { 0x0019e1cc, 0x00000004 },
+    { 0x001b0001, 0x00000004 },
+    { 0x0500a000, 0x00000004 },
+    { 0x080041cd, 0x00000004 },
+    { 0x000ca000, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0x000c2000, 0x00000004 },
+    { 0x001d0018, 0x00000004 },
+    { 0x001a0001, 0x00000004 },
+    { 0x000000fb, 0x00000034 },
+    { 0x0000004a, 0x00000008 },
+    { 0x0500a04a, 0x00000008 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+    { 0000000000, 0000000000 },
+};
+
+
+#endif
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 6f75512..11c146b 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -1662,7 +1662,7 @@
 	u32 height;
 	int i;
 	u32 texpitch, microtile;
-	u32 offset;
+	u32 offset, byte_offset;
 	RING_LOCALS;
 
 	if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
@@ -1727,6 +1727,13 @@
 	} else
 		microtile = 0;
 
+	/* this might fail for zero-sized uploads - are those illegal? */
+	if (!radeon_check_offset(dev_priv, tex->offset + image->height *
+				blit_width - 1)) {
+		DRM_ERROR("Invalid final destination offset\n");
+		return -EINVAL;
+	}
+
 	DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
 
 	do {
@@ -1840,6 +1847,7 @@
 		}
 
 #undef RADEON_COPY_MT
+		byte_offset = (image->y & ~2047) * blit_width;
 		buf->file_priv = file_priv;
 		buf->used = size;
 		offset = dev_priv->gart_buffers_offset + buf->offset;
@@ -1854,9 +1862,9 @@
 			 RADEON_DP_SRC_SOURCE_MEMORY |
 			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
 		OUT_RING((spitch << 22) | (offset >> 10));
-		OUT_RING((texpitch << 22) | (tex->offset >> 10));
+		OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10)));
 		OUT_RING(0);
-		OUT_RING((image->x << 16) | image->y);
+		OUT_RING((image->x << 16) | (image->y % 2048));
 		OUT_RING((image->width << 16) | height);
 		RADEON_WAIT_UNTIL_2D_IDLE();
 		ADVANCE_RING();
@@ -3037,6 +3045,9 @@
 	case RADEON_PARAM_FB_LOCATION:
 		value = radeon_read_fb_location(dev_priv);
 		break;
+	case RADEON_PARAM_NUM_GB_PIPES:
+		value = dev_priv->num_gb_pipes;
+		break;
 	default:
 		DRM_DEBUG("Invalid parameter %d\n", param->param);
 		return -EINVAL;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index e94bee0..7501310 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3322,7 +3322,7 @@
 		msleep_interruptible(duration);
 	tty->ops->break_ctl(tty, 0);
 	tty_write_unlock(tty);
-	if (!signal_pending(current))
+	if (signal_pending(current))
 		return -EINTR;
 	return 0;
 }
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index b1a757a..8f81139 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -981,16 +981,9 @@
 int n_tty_ioctl(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
-	struct tty_struct *real_tty;
 	unsigned long flags;
 	int retval;
 
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-		real_tty = tty->link;
-	else
-		real_tty = tty;
-
 	switch (cmd) {
 	case TCXONC:
 		retval = tty_check_change(tty);
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 85e2ba7..bf48300 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -27,6 +27,8 @@
 #include <linux/moduleparam.h>
 #include <linux/connector.h>
 #include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 
 #include <net/sock.h>
 
@@ -403,6 +405,40 @@
 	mutex_unlock(&notify_lock);
 }
 
+static int cn_proc_show(struct seq_file *m, void *v)
+{
+	struct cn_queue_dev *dev = cdev.cbdev;
+	struct cn_callback_entry *cbq;
+
+	seq_printf(m, "Name            ID\n");
+
+	spin_lock_bh(&dev->queue_lock);
+
+	list_for_each_entry(cbq, &dev->queue_list, callback_entry) {
+		seq_printf(m, "%-15s %u:%u\n",
+			   cbq->id.name,
+			   cbq->id.id.idx,
+			   cbq->id.id.val);
+	}
+
+	spin_unlock_bh(&dev->queue_lock);
+
+	return 0;
+}
+
+static int cn_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cn_proc_show, NULL);
+}
+
+static const struct file_operations cn_file_ops = {
+	.owner   = THIS_MODULE,
+	.open    = cn_proc_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release
+};
+
 static int __devinit cn_init(void)
 {
 	struct cn_dev *dev = &cdev;
@@ -434,6 +470,8 @@
 		return -EINVAL;
 	}
 
+	proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
+
 	return 0;
 }
 
@@ -443,6 +481,8 @@
 
 	cn_already_initialized = 0;
 
+	proc_net_remove(&init_net, "connector");
+
 	cn_del_callback(&dev->id);
 	cn_queue_free_dev(dev->cbdev);
 	netlink_kernel_release(dev->nls);
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index fb4d391..76f26710 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -1,28 +1,26 @@
-comment "An alternative FireWire stack is available with EXPERIMENTAL=y"
+comment "A new alternative FireWire stack is available with EXPERIMENTAL=y"
 	depends on EXPERIMENTAL=n
 
+comment "Enable only one of the two stacks, unless you know what you are doing"
+	depends on EXPERIMENTAL
+
 config FIREWIRE
-	tristate "IEEE 1394 (FireWire) support - alternative stack, EXPERIMENTAL"
+	tristate "New FireWire stack, EXPERIMENTAL"
 	depends on EXPERIMENTAL
 	select CRC_ITU_T
 	help
 	  This is the "Juju" FireWire stack, a new alternative implementation
 	  designed for robustness and simplicity.  You can build either this
-	  stack, or the classic stack (the ieee1394 driver, ohci1394 etc.)
-	  or both.  Please read http://wiki.linux1394.org/JujuMigration before
-	  you enable the new stack.
+	  stack, or the old stack (the ieee1394 driver, ohci1394 etc.) or both.
+	  Please read http://wiki.linux1394.org/JujuMigration before you
+	  enable the new stack.
 
 	  To compile this driver as a module, say M here: the module will be
 	  called firewire-core.  It functionally replaces ieee1394, raw1394,
 	  and video1394.
 
-          NOTE:
-
-	  You should only build ONE of the stacks, unless you REALLY know what
-	  you are doing.
-
 config FIREWIRE_OHCI
-	tristate "Support for OHCI FireWire host controllers"
+	tristate "OHCI-1394 controllers"
 	depends on PCI && FIREWIRE
 	help
 	  Enable this driver if you have a FireWire controller based
@@ -33,12 +31,12 @@
 	  called firewire-ohci.  It replaces ohci1394 of the classic IEEE 1394
 	  stack.
 
-          NOTE:
+	  NOTE:
 
-	  You should only build ohci1394 or firewire-ohci, but not both.
-	  If you nevertheless want to install both, you should configure them
-	  only as modules and blacklist the driver(s) which you don't want to
-	  have auto-loaded.  Add either
+	  You should only build either firewire-ohci or the old ohci1394 driver,
+	  but not both.  If you nevertheless want to install both, you should
+	  configure them only as modules and blacklist the driver(s) which you
+	  don't want to have auto-loaded.  Add either
 
 	      blacklist firewire-ohci
 	  or
@@ -60,7 +58,7 @@
 	default y
 
 config FIREWIRE_SBP2
-	tristate "Support for storage devices (SBP-2 protocol driver)"
+	tristate "Storage devices (SBP-2 protocol)"
 	depends on FIREWIRE && SCSI
 	help
 	  This option enables you to use SBP-2 devices connected to a
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index dda1401..c639915 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -205,6 +205,7 @@
 	return dequeue_event(client, buffer, count);
 }
 
+/* caller must hold card->lock so that node pointers can be dereferenced here */
 static void
 fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
 		     struct client *client)
@@ -214,7 +215,6 @@
 	event->closure	     = client->bus_reset_closure;
 	event->type          = FW_CDEV_EVENT_BUS_RESET;
 	event->generation    = client->device->generation;
-	smp_rmb();           /* node_id must not be older than generation */
 	event->node_id       = client->device->node_id;
 	event->local_node_id = card->local_node->node_id;
 	event->bm_node_id    = 0; /* FIXME: We don't track the BM. */
@@ -274,6 +274,7 @@
 {
 	struct fw_cdev_get_info *get_info = buffer;
 	struct fw_cdev_event_bus_reset bus_reset;
+	struct fw_card *card = client->device->card;
 	unsigned long ret = 0;
 
 	client->version = get_info->version;
@@ -299,13 +300,17 @@
 	client->bus_reset_closure = get_info->bus_reset_closure;
 	if (get_info->bus_reset != 0) {
 		void __user *uptr = u64_to_uptr(get_info->bus_reset);
+		unsigned long flags;
 
+		spin_lock_irqsave(&card->lock, flags);
 		fill_bus_reset_event(&bus_reset, client);
+		spin_unlock_irqrestore(&card->lock, flags);
+
 		if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
 			return -EFAULT;
 	}
 
-	get_info->card = client->device->card->index;
+	get_info->card = card->index;
 
 	return 0;
 }
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 4f02c55..0b66306 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -265,27 +265,25 @@
 	    !(evt & OHCI1394_busReset))
 		return;
 
-	printk(KERN_DEBUG KBUILD_MODNAME ": IRQ "
-	       "%08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
-	       evt,
-	       evt & OHCI1394_selfIDComplete	? " selfID"		: "",
-	       evt & OHCI1394_RQPkt		? " AR_req"		: "",
-	       evt & OHCI1394_RSPkt		? " AR_resp"		: "",
-	       evt & OHCI1394_reqTxComplete	? " AT_req"		: "",
-	       evt & OHCI1394_respTxComplete	? " AT_resp"		: "",
-	       evt & OHCI1394_isochRx		? " IR"			: "",
-	       evt & OHCI1394_isochTx		? " IT"			: "",
-	       evt & OHCI1394_postedWriteErr	? " postedWriteErr"	: "",
-	       evt & OHCI1394_cycleTooLong	? " cycleTooLong"	: "",
-	       evt & OHCI1394_cycle64Seconds	? " cycle64Seconds"	: "",
-	       evt & OHCI1394_regAccessFail	? " regAccessFail"	: "",
-	       evt & OHCI1394_busReset		? " busReset"		: "",
-	       evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
-		       OHCI1394_RSPkt | OHCI1394_reqTxComplete |
-		       OHCI1394_respTxComplete | OHCI1394_isochRx |
-		       OHCI1394_isochTx | OHCI1394_postedWriteErr |
-		       OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
-		       OHCI1394_regAccessFail | OHCI1394_busReset)
+	fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+	    evt & OHCI1394_selfIDComplete	? " selfID"		: "",
+	    evt & OHCI1394_RQPkt		? " AR_req"		: "",
+	    evt & OHCI1394_RSPkt		? " AR_resp"		: "",
+	    evt & OHCI1394_reqTxComplete	? " AT_req"		: "",
+	    evt & OHCI1394_respTxComplete	? " AT_resp"		: "",
+	    evt & OHCI1394_isochRx		? " IR"			: "",
+	    evt & OHCI1394_isochTx		? " IT"			: "",
+	    evt & OHCI1394_postedWriteErr	? " postedWriteErr"	: "",
+	    evt & OHCI1394_cycleTooLong		? " cycleTooLong"	: "",
+	    evt & OHCI1394_cycle64Seconds	? " cycle64Seconds"	: "",
+	    evt & OHCI1394_regAccessFail	? " regAccessFail"	: "",
+	    evt & OHCI1394_busReset		? " busReset"		: "",
+	    evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
+		    OHCI1394_RSPkt | OHCI1394_reqTxComplete |
+		    OHCI1394_respTxComplete | OHCI1394_isochRx |
+		    OHCI1394_isochTx | OHCI1394_postedWriteErr |
+		    OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
+		    OHCI1394_regAccessFail | OHCI1394_busReset)
 						? " ?"			: "");
 }
 
@@ -308,23 +306,22 @@
 	if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS)))
 		return;
 
-	printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d, "
-	       "local node ID %04x\n", self_id_count, generation, node_id);
+	fw_notify("%d selfIDs, generation %d, local node ID %04x\n",
+		  self_id_count, generation, node_id);
 
 	for (; self_id_count--; ++s)
 		if ((*s & 1 << 23) == 0)
-			printk(KERN_DEBUG "selfID 0: %08x, phy %d [%c%c%c] "
-			       "%s gc=%d %s %s%s%s\n",
-			       *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2),
-			       speed[*s >> 14 & 3], *s >> 16 & 63,
-			       power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "",
-			       *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : "");
+			fw_notify("selfID 0: %08x, phy %d [%c%c%c] "
+			    "%s gc=%d %s %s%s%s\n",
+			    *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2),
+			    speed[*s >> 14 & 3], *s >> 16 & 63,
+			    power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "",
+			    *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : "");
 		else
-			printk(KERN_DEBUG "selfID n: %08x, phy %d "
-			       "[%c%c%c%c%c%c%c%c]\n",
-			       *s, *s >> 24 & 63,
-			       _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10),
-			       _p(s,  8), _p(s,  6), _p(s,  4), _p(s,  2));
+			fw_notify("selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n",
+			    *s, *s >> 24 & 63,
+			    _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10),
+			    _p(s,  8), _p(s,  6), _p(s,  4), _p(s,  2));
 }
 
 static const char *evts[] = {
@@ -373,15 +370,14 @@
 			evt = 0x1f;
 
 	if (evt == OHCI1394_evt_bus_reset) {
-		printk(KERN_DEBUG "A%c evt_bus_reset, generation %d\n",
-		       dir, (header[2] >> 16) & 0xff);
+		fw_notify("A%c evt_bus_reset, generation %d\n",
+		    dir, (header[2] >> 16) & 0xff);
 		return;
 	}
 
 	if (header[0] == ~header[1]) {
-		printk(KERN_DEBUG "A%c %s, %s, %08x\n",
-		       dir, evts[evt], phys[header[0] >> 30 & 0x3],
-		       header[0]);
+		fw_notify("A%c %s, %s, %08x\n",
+		    dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]);
 		return;
 	}
 
@@ -400,24 +396,23 @@
 
 	switch (tcode) {
 	case 0xe: case 0xa:
-		printk(KERN_DEBUG "A%c %s, %s\n",
-		       dir, evts[evt], tcodes[tcode]);
+		fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
 		break;
 	case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
-		printk(KERN_DEBUG "A%c spd %x tl %02x, "
-		       "%04x -> %04x, %s, "
-		       "%s, %04x%08x%s\n",
-		       dir, speed, header[0] >> 10 & 0x3f,
-		       header[1] >> 16, header[0] >> 16, evts[evt],
-		       tcodes[tcode], header[1] & 0xffff, header[2], specific);
+		fw_notify("A%c spd %x tl %02x, "
+		    "%04x -> %04x, %s, "
+		    "%s, %04x%08x%s\n",
+		    dir, speed, header[0] >> 10 & 0x3f,
+		    header[1] >> 16, header[0] >> 16, evts[evt],
+		    tcodes[tcode], header[1] & 0xffff, header[2], specific);
 		break;
 	default:
-		printk(KERN_DEBUG "A%c spd %x tl %02x, "
-		       "%04x -> %04x, %s, "
-		       "%s%s\n",
-		       dir, speed, header[0] >> 10 & 0x3f,
-		       header[1] >> 16, header[0] >> 16, evts[evt],
-		       tcodes[tcode], specific);
+		fw_notify("A%c spd %x tl %02x, "
+		    "%04x -> %04x, %s, "
+		    "%s%s\n",
+		    dir, speed, header[0] >> 10 & 0x3f,
+		    header[1] >> 16, header[0] >> 16, evts[evt],
+		    tcodes[tcode], specific);
 	}
 }
 
@@ -548,6 +543,11 @@
 		p.header_length = 12;
 		p.payload_length = 0;
 		break;
+
+	default:
+		/* FIXME: Stop context, discard everything, and restart? */
+		p.header_length = 0;
+		p.payload_length = 0;
 	}
 
 	p.payload = (void *) buffer + p.header_length;
@@ -1468,6 +1468,9 @@
 	reg_write(ohci, OHCI1394_HCControlClear,
 		  OHCI1394_HCControl_noByteSwapData);
 
+	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
+	reg_write(ohci, OHCI1394_LinkControlClear,
+		  OHCI1394_LinkControl_rcvPhyPkt);
 	reg_write(ohci, OHCI1394_LinkControlSet,
 		  OHCI1394_LinkControl_rcvSelfID |
 		  OHCI1394_LinkControl_cycleTimerEnable |
@@ -1481,7 +1484,6 @@
 	ar_context_run(&ohci->ar_request_ctx);
 	ar_context_run(&ohci->ar_response_ctx);
 
-	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
 	reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
 	reg_write(ohci, OHCI1394_IntEventClear, ~0);
 	reg_write(ohci, OHCI1394_IntMaskClear, ~0);
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index b2458bb..227d2e0 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -1051,7 +1051,8 @@
 			break;
 
 		case SBP2_CSR_LOGICAL_UNIT_DIRECTORY:
-			if (sbp2_scan_logical_unit_dir(tgt, ci.p + value) < 0)
+			/* Adjust for the increment in the iterator */
+			if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0)
 				return -ENOMEM;
 			break;
 		}
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index ccf0e4c..03ae8a7 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -20,6 +20,7 @@
 
 #include <linux/completion.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -297,37 +298,55 @@
 struct fw_phy_packet {
 	struct fw_packet packet;
 	struct completion done;
+	struct kref kref;
 };
 
-static void
-transmit_phy_packet_callback(struct fw_packet *packet,
-			     struct fw_card *card, int status)
+static void phy_packet_release(struct kref *kref)
+{
+	struct fw_phy_packet *p =
+			container_of(kref, struct fw_phy_packet, kref);
+	kfree(p);
+}
+
+static void transmit_phy_packet_callback(struct fw_packet *packet,
+					 struct fw_card *card, int status)
 {
 	struct fw_phy_packet *p =
 			container_of(packet, struct fw_phy_packet, packet);
 
 	complete(&p->done);
+	kref_put(&p->kref, phy_packet_release);
 }
 
 void fw_send_phy_config(struct fw_card *card,
 			int node_id, int generation, int gap_count)
 {
-	struct fw_phy_packet p;
+	struct fw_phy_packet *p;
+	long timeout = DIV_ROUND_UP(HZ, 10);
 	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
 		   PHY_CONFIG_ROOT_ID(node_id) |
 		   PHY_CONFIG_GAP_COUNT(gap_count);
 
-	p.packet.header[0] = data;
-	p.packet.header[1] = ~data;
-	p.packet.header_length = 8;
-	p.packet.payload_length = 0;
-	p.packet.speed = SCODE_100;
-	p.packet.generation = generation;
-	p.packet.callback = transmit_phy_packet_callback;
-	init_completion(&p.done);
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (p == NULL)
+		return;
 
-	card->driver->send_request(card, &p.packet);
-	wait_for_completion(&p.done);
+	p->packet.header[0] = data;
+	p->packet.header[1] = ~data;
+	p->packet.header_length = 8;
+	p->packet.payload_length = 0;
+	p->packet.speed = SCODE_100;
+	p->packet.generation = generation;
+	p->packet.callback = transmit_phy_packet_callback;
+	init_completion(&p->done);
+	kref_set(&p->kref, 2);
+
+	card->driver->send_request(card, &p->packet);
+	timeout = wait_for_completion_timeout(&p->done, timeout);
+	kref_put(&p->kref, phy_packet_release);
+
+	/* will leak p if the callback is never executed */
+	WARN_ON(timeout == 0);
 }
 
 void fw_flush_transactions(struct fw_card *card)
@@ -572,7 +591,8 @@
 		break;
 
 	default:
-		BUG();
+		fw_error("ERROR - corrupt request received - %08x %08x %08x\n",
+			 p->header[0], p->header[1], p->header[2]);
 		return NULL;
 	}
 
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bbd2834..008c38b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -28,12 +28,18 @@
 comment "I2C GPIO expanders:"
 
 config GPIO_PCA953X
-	tristate "PCA953x I/O ports"
+	tristate "PCA953x, PCA955x, and MAX7310 I/O ports"
 	depends on I2C
 	help
-	  Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
-	  PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
-	  (16-bit) I/O ports. These parts are made by NXP and TI.
+	  Say yes here to provide access to several register-oriented
+	  SMBus I/O expanders, made mostly by NXP or TI.  Compatible
+	  models include:
+
+	  4 bits:	pca9536, pca9537
+
+	  8 bits:	max7310, pca9534, pca9538, pca9554, pca9557
+
+	  16 bits:	pca9535, pca9539, pca9555
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called pca953x.
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 7e40e8a..a380730 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -33,7 +33,7 @@
 	{ "pca9554", 8, },
 	{ "pca9555", 16, },
 	{ "pca9557", 8, },
-	/* REVISIT several pca955x parts should work here too */
+	{ "max7310", 8, },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index ed33fdd..f00f497 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -30,6 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
 #include <asm/io.h>
 
 /* uGuru3 bank addresses */
@@ -323,7 +324,7 @@
 		{ "AUX1 Fan",		36, 2, 60, 1, 0 },
 		{ NULL, 0, 0, 0, 0, 0 } }
 	},
-	{ 0x0013, "unknown", {
+	{ 0x0013, "Abit AW8D", {
 		{ "CPU Core",		 0, 0, 10, 1, 0 },
 		{ "DDR",		 1, 0, 10, 1, 0 },
 		{ "DDR VTT",		 2, 0, 10, 1, 0 },
@@ -349,6 +350,7 @@
 		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
 		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
 		{ "AUX4 Fan",		38, 2, 60, 1, 0 },
+		{ "AUX5 Fan",		39, 2, 60, 1, 0 },
 		{ NULL, 0, 0, 0, 0, 0 } }
 	},
 	{ 0x0014, "Abit AB9 Pro", {
@@ -1111,11 +1113,12 @@
 {
 	/* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
 	   0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
-	   at CMD instead, why is unknown. So we test for 0x05 too. */
+	   or 0x55 at CMD instead, why is unknown. */
 	u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
 	u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
 	if (((data_val == 0x00) || (data_val == 0x08)) &&
-			((cmd_val == 0xAC) || (cmd_val == 0x05)))
+			((cmd_val == 0xAC) || (cmd_val == 0x05) ||
+			 (cmd_val == 0x55)))
 		return ABIT_UGURU3_BASE;
 
 	ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
@@ -1138,6 +1141,15 @@
 	int address, err;
 	struct resource res = { .flags = IORESOURCE_IO };
 
+#ifdef CONFIG_DMI
+	const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+	/* safety check, refuse to load on non Abit motherboards */
+	if (!force && (!board_vendor ||
+			strcmp(board_vendor, "http://www.abit.com.tw/")))
+		return -ENODEV;
+#endif
+
 	address = abituguru3_detect();
 	if (address < 0)
 		return address;
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index c1009d6..93dbf5e 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -309,6 +309,9 @@
 						ADT7473_REG_PWM_BHVR(i));
 	}
 
+	i = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG4);
+	data->max_duty_at_overheat = !!(i & ADT7473_CFG4_MAX_DUTY_AT_OVT);
+
 	data->limits_last_updated = local_jiffies;
 	data->limits_valid = 1;
 
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 26df06f..50f2269 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -516,17 +516,23 @@
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
 	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
 	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
 	{ .ident = NULL }
 };
 
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index fa76969..de698dc 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -251,10 +251,13 @@
    the SMBus standard. */
 static int lm75_read_value(struct i2c_client *client, u8 reg)
 {
+	int value;
+
 	if (reg == LM75_REG_CONF)
 		return i2c_smbus_read_byte_data(client, reg);
-	else
-		return swab16(i2c_smbus_read_word_data(client, reg));
+
+	value = i2c_smbus_read_word_data(client, reg);
+	return (value < 0) ? value : swab16(value);
 }
 
 static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
@@ -287,9 +290,16 @@
 		int i;
 		dev_dbg(&client->dev, "Starting lm75 update\n");
 
-		for (i = 0; i < ARRAY_SIZE(data->temp); i++)
-			data->temp[i] = lm75_read_value(client,
-							LM75_REG_TEMP[i]);
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			int status;
+
+			status = lm75_read_value(client, LM75_REG_TEMP[i]);
+			if (status < 0)
+				dev_dbg(&client->dev, "reg %d, err %d\n",
+						LM75_REG_TEMP[i], status);
+			else
+				data->temp[i] = status;
+		}
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 182fe6a..ee5eca1 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -192,23 +192,20 @@
 {
 	int i;
 
-	if ( range < lm85_range_map[0] ) { 
-		return 0 ;
-	} else if ( range > lm85_range_map[15] ) {
+	if (range >= lm85_range_map[15])
 		return 15 ;
-	} else {  /* find closest match */
-		for ( i = 14 ; i >= 0 ; --i ) {
-			if ( range > lm85_range_map[i] ) { /* range bracketed */
-				if ((lm85_range_map[i+1] - range) < 
-					(range - lm85_range_map[i])) {
-					i++;
-					break;
-				}
-				break;
-			}
+
+	/* Find the closest match */
+	for (i = 14; i >= 0; --i) {
+		if (range >= lm85_range_map[i]) {
+			if ((lm85_range_map[i + 1] - range) <
+					(range - lm85_range_map[i]))
+				return i + 1;
+			return i;
 		}
 	}
-	return( i & 0x0f );
+
+	return 0;
 }
 #define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])
 
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 1305ef1..9e8c875 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -290,12 +290,12 @@
 		 * bus, or started a new i2c message
 		 */
 		
-		if (iicstat  & S3C2410_IICSTAT_LASTBIT &&
+		if (iicstat & S3C2410_IICSTAT_LASTBIT &&
 		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
 			/* ack was not received... */
 
 			dev_dbg(i2c->dev, "ack was not received\n");
-			s3c24xx_i2c_stop(i2c, -EREMOTEIO);
+			s3c24xx_i2c_stop(i2c, -ENXIO);
 			goto out_ack;
 		}
 
@@ -305,7 +305,7 @@
 			i2c->state = STATE_WRITE;
 
 		/* terminate the transfer if there is nothing to do
-		 * (used by the i2c probe to find devices */
+		 * as this is used by the i2c probe to find devices. */
 
 		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
 			s3c24xx_i2c_stop(i2c, 0);
@@ -323,7 +323,17 @@
 		 * end of the message, and if so, work out what to do
 		 */
 
+		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+				dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+				s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+				goto out_ack;
+			}
+		}
+
 	retry_write:
+
 		if (!is_msgend(i2c)) {
 			byte = i2c->msg->buf[i2c->msg_ptr++];
 			writeb(byte, i2c->regs + S3C2410_IICDS);
@@ -377,17 +387,6 @@
 		 * going to do any more read/write
 		 */
 
-		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
-		    !(is_msglast(i2c) && is_lastmsg(i2c))) {
-
-			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
-				dev_dbg(i2c->dev, "READ: No Ack\n");
-
-				s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
-				goto out_ack;
-			}
-		}
-
 		byte = readb(i2c->regs + S3C2410_IICDS);
 		i2c->msg->buf[i2c->msg_ptr++] = byte;
 
@@ -949,3 +948,4 @@
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:s3c2410-i2c");
+MODULE_ALIAS("platform:s3c2440-i2c");
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
index d024ac8..cc24803 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -353,8 +353,8 @@
 	struct clk *clkp;
 	struct resource *mem, *irq;
 	ide_hwif_t *hwif;
-	void __iomem *base;
-	int pribase, i;
+	unsigned long base;
+	int i;
 	hw_regs_t hw;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
@@ -374,22 +374,27 @@
 		printk(KERN_ERR "failed to get memory region resource\n");
 		return -ENODEV;
 	}
+
 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (irq == NULL) {
 		printk(KERN_ERR "failed to get IRQ resource\n");
 		return -ENODEV;
 	}
 
-	base = (void *)mem->start;
+	if (request_mem_region(mem->start, mem->end - mem->start + 1,
+			       "palm_bk3710") == NULL) {
+		printk(KERN_ERR "failed to request memory region\n");
+		return -EBUSY;
+	}
+
+	base = IO_ADDRESS(mem->start);
 
 	/* Configure the Palm Chip controller */
-	palm_bk3710_chipinit(base);
+	palm_bk3710_chipinit((void __iomem *)base);
 
-	pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET;
 	for (i = 0; i < IDE_NR_PORTS - 2; i++)
-		hw.io_ports_array[i] = pribase + i;
-	hw.io_ports.ctl_addr = mem->start +
-			IDE_PALM_ATA_PRI_CTL_OFFSET;
+		hw.io_ports_array[i] = base + IDE_PALM_ATA_PRI_REG_OFFSET + i;
+	hw.io_ports.ctl_addr = base + IDE_PALM_ATA_PRI_CTL_OFFSET;
 	hw.irq = irq->start;
 	hw.chipset = ide_palm3710;
 
@@ -434,4 +439,3 @@
 
 module_init(palm_bk3710_init);
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 55ec7f7..8af88bf 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -76,7 +76,7 @@
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
 	int		len;
 
-	if (hwif && hwif->mate && hwif->mate->present)
+	if (hwif && hwif->mate)
 		len = sprintf(page, "%s\n", hwif->mate->name);
 	else
 		len = sprintf(page, "(none)\n");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 0c908ca..ab545ff 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -225,10 +225,10 @@
 	u8 stat;
 
 	/*
-	 * Last sector was transfered, wait until drive is ready.
-	 * This can take up to 10 usec, but we will wait max 1 ms.
+	 * Last sector was transfered, wait until device is ready.  This can
+	 * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
 	 */
-	for (retries = 0; retries < 100; retries++) {
+	for (retries = 0; retries < 1000; retries++) {
 		stat = ide_read_status(drive);
 
 		if (stat & BUSY_STAT)
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index f633b6b..3381424 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -410,6 +410,7 @@
 	PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),	/* Mitsubishi CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
 	PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),	/* SanDisk CFA */
+	PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),	/* Kingston */
 	PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),	/* Toshiba */
 	PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
 	PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),	/* Samsung */
@@ -439,6 +440,7 @@
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
 	PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
+	PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
 	PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
 	PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
@@ -449,6 +451,7 @@
 	PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
 	PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
+	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 545663e..95f45f9 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -4,7 +4,7 @@
 source "drivers/firewire/Kconfig"
 
 config IEEE1394
-	tristate "IEEE 1394 (FireWire) support"
+	tristate "Stable FireWire stack"
 	depends on PCI || BROKEN
 	help
 	  IEEE 1394 describes a high performance serial bus, which is also
@@ -19,30 +19,45 @@
 	  To compile this driver as a module, say M here: the
 	  module will be called ieee1394.
 
-comment "Subsystem Options"
-	depends on IEEE1394
-
-config IEEE1394_VERBOSEDEBUG
-	bool "Excessive debugging output"
-	depends on IEEE1394
+config IEEE1394_OHCI1394
+	tristate "OHCI-1394 controllers"
+	depends on PCI && IEEE1394
 	help
-	  If you say Y here, you will get very verbose debugging logs from
-	  the subsystem which includes a dump of the header of every sent
-	  and received packet.  This can amount to a high amount of data
-	  collected in a very short time which is usually also saved to
-	  disk by the system logging daemons.
+	  Enable this driver if you have an IEEE 1394 controller based on the
+	  OHCI-1394 specification. The current driver is only tested with OHCI
+	  chipsets made by Texas Instruments and NEC. Most third-party vendors
+	  use one of these chipsets.  It should work with any OHCI-1394
+	  compliant card, however.
 
-	  Say Y if you really want or need the debugging output, everyone
-	  else says N.
+	  To compile this driver as a module, say M here: the
+	  module will be called ohci1394.
 
-comment "Controllers"
-	depends on IEEE1394
+	  NOTE:
 
-comment "Texas Instruments PCILynx requires I2C"
+	  You should only build either ohci1394 or the new firewire-ohci driver,
+	  but not both.  If you nevertheless want to install both, you should
+	  configure them only as modules and blacklist the driver(s) which you
+	  don't want to have auto-loaded.  Add either
+
+	      blacklist firewire-ohci
+	  or
+	      blacklist ohci1394
+	      blacklist video1394
+	      blacklist dv1394
+
+	  to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
+	  depending on your distribution.  The latter two modules should be
+	  blacklisted together with ohci1394 because they depend on ohci1394.
+
+	  If you have an old modprobe which doesn't implement the blacklist
+	  directive, use "install modulename /bin/true" for the modules to be
+	  blacklisted.
+
+comment "PCILynx controller requires I2C"
 	depends on IEEE1394 && I2C=n
 
 config IEEE1394_PCILYNX
-	tristate "Texas Instruments PCILynx support"
+	tristate "PCILynx controller"
 	depends on PCI && IEEE1394 && I2C
 	select I2C_ALGOBIT
 	help
@@ -57,35 +72,11 @@
 	  PowerMacs G3 B&W contain the PCILynx controller.  Therefore
 	  almost everybody can say N here.
 
-config IEEE1394_OHCI1394
-	tristate "OHCI-1394 support"
-	depends on PCI && IEEE1394
-	help
-	  Enable this driver if you have an IEEE 1394 controller based on the
-	  OHCI-1394 specification. The current driver is only tested with OHCI
-	  chipsets made by Texas Instruments and NEC. Most third-party vendors
-	  use one of these chipsets.  It should work with any OHCI-1394
-	  compliant card, however.
-
-	  To compile this driver as a module, say M here: the
-	  module will be called ohci1394.
-
-comment "Protocols"
-	depends on IEEE1394
-
-config IEEE1394_VIDEO1394
-	tristate "OHCI-1394 Video support"
-	depends on IEEE1394 && IEEE1394_OHCI1394
-	help
-	  This option enables video device usage for OHCI-1394 cards.  Enable
-	  this option only if you have an IEEE 1394 video device connected to
-	  an OHCI-1394 card.
-
 comment "SBP-2 support (for storage devices) requires SCSI"
 	depends on IEEE1394 && SCSI=n
 
 config IEEE1394_SBP2
-	tristate "SBP-2 support (Harddisks etc.)"
+	tristate "Storage devices (SBP-2 protocol)"
 	depends on IEEE1394 && SCSI
 	help
 	  This option enables you to use SBP-2 devices connected to an IEEE
@@ -127,24 +118,47 @@
 
 	  The module is called eth1394 although it does not emulate Ethernet.
 
+config IEEE1394_RAWIO
+	tristate "raw1394 userspace interface"
+	depends on IEEE1394
+	help
+	  This option adds support for the raw1394 device file which enables
+	  direct communication of user programs with IEEE 1394 devices
+	  (isochronous and asynchronous).  Almost all application programs
+	  which access FireWire require this option.
+
+	  To compile this driver as a module, say M here: the module will be
+	  called raw1394.
+
+config IEEE1394_VIDEO1394
+	tristate "video1394 userspace interface"
+	depends on IEEE1394 && IEEE1394_OHCI1394
+	help
+	  This option adds support for the video1394 device files which enable
+	  isochronous communication of user programs with IEEE 1394 devices,
+	  especially video capture or export.  This interface is used by all
+	  libdc1394 based programs and by several other programs, in addition to
+	  the raw1394 interface.  It is generally not required for DV capture.
+
+	  To compile this driver as a module, say M here: the module will be
+	  called video1394.
+
 config IEEE1394_DV1394
-	tristate "OHCI-DV I/O support (deprecated)"
+	tristate "dv1394 userspace interface (deprecated)"
 	depends on IEEE1394 && IEEE1394_OHCI1394
 	help
 	  The dv1394 driver is unsupported and may be removed from Linux in a
 	  future release.  Its functionality is now provided by raw1394 together
 	  with libraries such as libiec61883.
 
-config IEEE1394_RAWIO
-	tristate "Raw IEEE1394 I/O support"
+config IEEE1394_VERBOSEDEBUG
+	bool "Excessive debugging output"
 	depends on IEEE1394
 	help
-	  This option adds support for the raw1394 device file which enables
-	  direct communication of user programs with the IEEE 1394 bus and thus
-	  with the attached peripherals.  Almost all application programs which
-	  access FireWire require this option.
+	  If you say Y here, you will get very verbose debugging logs from the
+	  ieee1394 drivers, including sent and received packet headers.  This
+	  will quickly result in large amounts of data sent to the system log.
 
-	  To compile this driver as a module, say M here: the module will be
-	  called raw1394.
+	  Say Y if you really need the debugging output.  Everyone else says N.
 
 endmenu
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index b224079..d5862e5 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -109,7 +109,11 @@
 {
 	struct page *page;
 
-	page = alloc_pages(gfp_mask, order);
+	/*
+	 * Use __GFP_ZERO because buggy firmware assumes ICM pages are
+	 * cleared, and subtle failures are seen if they aren't.
+	 */
+	page = alloc_pages(gfp_mask | __GFP_ZERO, order);
 	if (!page)
 		return -ENOMEM;
 
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index eebc724..72c63e5 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -28,6 +28,7 @@
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/sched.h>
 
 /*
  * Check that the effect_id is a valid effect and whether the user
@@ -166,8 +167,10 @@
 	if (ret)
 		goto out;
 
+	spin_lock_irq(&dev->event_lock);
 	ff->effects[id] = *effect;
 	ff->effect_owners[id] = file;
+	spin_unlock_irq(&dev->event_lock);
 
  out:
 	mutex_unlock(&ff->mutex);
@@ -189,15 +192,21 @@
 	if (error)
 		return error;
 
+	spin_lock_irq(&dev->event_lock);
 	ff->playback(dev, effect_id, 0);
+	ff->effect_owners[effect_id] = NULL;
+	spin_unlock_irq(&dev->event_lock);
 
 	if (ff->erase) {
 		error = ff->erase(dev, effect_id);
-		if (error)
-			return error;
-	}
+		if (error) {
+			spin_lock_irq(&dev->event_lock);
+			ff->effect_owners[effect_id] = file;
+			spin_unlock_irq(&dev->event_lock);
 
-	ff->effect_owners[effect_id] = NULL;
+			return error;
+		}
+	}
 
 	return 0;
 }
@@ -263,8 +272,6 @@
 	if (type != EV_FF)
 		return 0;
 
-	mutex_lock(&ff->mutex);
-
 	switch (code) {
 	case FF_GAIN:
 		if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
@@ -286,7 +293,6 @@
 		break;
 	}
 
-	mutex_unlock(&ff->mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(input_ff_event);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 835def1..ab6a61d 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -432,6 +432,7 @@
 		case 0:
 			atomic_dec(&ctx->pending);
 			ctx->sector++;
+			cond_resched();
 			continue;
 
 		/* error */
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 7cf512a..2580ac1 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3897,8 +3897,10 @@
 
 		md_probe(dev, NULL, NULL);
 		mddev = mddev_find(dev);
-		if (!mddev) {
-			printk(KERN_ERR 
+		if (!mddev || !mddev->gendisk) {
+			if (mddev)
+				mddev_put(mddev);
+			printk(KERN_ERR
 				"md: cannot allocate memory for md drive.\n");
 			break;
 		}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1de17da..a71277b 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2137,6 +2137,8 @@
 		    !test_bit(In_sync, &disk->rdev->flags)) {
 			disk->head_position = 0;
 			mddev->degraded++;
+			if (disk->rdev)
+				conf->fullsync = 1;
 		}
 	}
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c37e256..54c8ee2 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2898,6 +2898,8 @@
 
 		for (i = conf->raid_disks; i--; ) {
 			set_bit(R5_Wantwrite, &sh->dev[i].flags);
+			set_bit(R5_LOCKED, &dev->flags);
+			s.locked++;
 			if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
 				sh->ops.count++;
 		}
@@ -2911,6 +2913,7 @@
 			conf->raid_disks);
 		s.locked += handle_write_operations5(sh, 1, 1);
 	} else if (s.expanded &&
+		   s.locked == 0 &&
 		!test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
 		clear_bit(STRIPE_EXPAND_READY, &sh->state);
 		atomic_dec(&conf->reshape_stripes);
@@ -4305,7 +4308,9 @@
 				" disk %d\n", bdevname(rdev->bdev,b),
 				raid_disk);
 			working_disks++;
-		}
+		} else
+			/* Cannot rely on bitmap to complete recovery */
+			conf->fullsync = 1;
 	}
 
 	/*
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index a348581..8fa91f8 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -2201,3 +2201,41 @@
 	[0x25] = KEY_POWER,		/* power */
 };
 EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
+
+IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
+	[0x20] = KEY_LIST,
+	[0x00] = KEY_POWER,
+	[0x28] = KEY_1,
+	[0x18] = KEY_2,
+	[0x38] = KEY_3,
+	[0x24] = KEY_4,
+	[0x14] = KEY_5,
+	[0x34] = KEY_6,
+	[0x2c] = KEY_7,
+	[0x1c] = KEY_8,
+	[0x3c] = KEY_9,
+	[0x12] = KEY_SUBTITLE,
+	[0x22] = KEY_0,
+	[0x32] = KEY_REWIND,
+	[0x3a] = KEY_SHUFFLE,
+	[0x02] = KEY_PRINT,
+	[0x11] = KEY_CHANNELDOWN,
+	[0x31] = KEY_CHANNELUP,
+	[0x0c] = KEY_ZOOM,
+	[0x1e] = KEY_VOLUMEDOWN,
+	[0x3e] = KEY_VOLUMEUP,
+	[0x0a] = KEY_MUTE,
+	[0x04] = KEY_AUDIO,
+	[0x26] = KEY_RECORD,
+	[0x06] = KEY_PLAY,
+	[0x36] = KEY_STOP,
+	[0x16] = KEY_PAUSE,
+	[0x2e] = KEY_REWIND,
+	[0x0e] = KEY_FASTFORWARD,
+	[0x30] = KEY_TEXT,
+	[0x21] = KEY_GREEN,
+	[0x01] = KEY_BLUE,
+	[0x08] = KEY_EPG,
+	[0x2a] = KEY_MENU,
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index f1894fe..6fb5b45 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -649,9 +649,17 @@
 	u8 val;
 
 	int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val);
+	/* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range
+	 * for frequencies above 61.1 MHz.  In these cases, the internal RF
+	 * tracking filters calibration mechanism is used.
+	 *
+	 * There is no need to warn the user about this.
+	 */
+	if (ret < 0)
+		goto fail;
 
 	regs[R_EB14] = val;
-
+fail:
 	return ret;
 }
 
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 89c01fb..93063c6 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -45,6 +45,21 @@
 					   TDA18271_MAIN_PLL, force);
 }
 
+static inline void tda18271_set_if_notch(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
+		break;
+	}
+}
+
 static int tda18271_channel_configuration(struct dvb_frontend *fe,
 					  struct tda18271_std_map_item *map,
 					  u32 freq, u32 bw)
@@ -60,25 +75,18 @@
 	regs[R_EP3]  &= ~0x1f; /* clear std bits */
 	regs[R_EP3]  |= (map->agc_mode << 3) | map->std;
 
-	/* set rfagc to high speed mode */
-	regs[R_EP3] &= ~0x04;
+	if (priv->id == TDA18271HDC2) {
+		/* set rfagc to high speed mode */
+		regs[R_EP3] &= ~0x04;
+	}
 
 	/* set cal mode to normal */
 	regs[R_EP4]  &= ~0x03;
 
-	/* update IF output level & IF notch frequency */
+	/* update IF output level */
 	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
 	regs[R_EP4]  |= (map->if_lvl << 2);
 
-	switch (priv->mode) {
-	case TDA18271_ANALOG:
-		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
-		break;
-	case TDA18271_DIGITAL:
-		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
-		break;
-	}
-
 	/* update FM_RFn */
 	regs[R_EP4]  &= ~0x80;
 	regs[R_EP4]  |= map->fm_rfn << 7;
@@ -95,6 +103,9 @@
 	/* disable Power Level Indicator */
 	regs[R_EP1]  |= 0x40;
 
+	/* make sure thermometer is off */
+	regs[R_TM]   &= ~0x10;
+
 	/* frequency dependent parameters */
 
 	tda18271_calc_ir_measure(fe, &freq);
@@ -135,6 +146,7 @@
 	switch (priv->role) {
 	case TDA18271_MASTER:
 		tda18271_calc_main_pll(fe, N);
+		tda18271_set_if_notch(fe);
 		tda18271_write_regs(fe, R_MPD, 4);
 		break;
 	case TDA18271_SLAVE:
@@ -142,6 +154,7 @@
 		tda18271_write_regs(fe, R_CPD, 4);
 
 		regs[R_MPD] = regs[R_CPD] & 0x7f;
+		tda18271_set_if_notch(fe);
 		tda18271_write_regs(fe, R_MPD, 1);
 		break;
 	}
@@ -160,12 +173,14 @@
 
 	msleep(20);
 
-	/* set rfagc to normal speed mode */
-	if (map->fm_rfn)
-		regs[R_EP3] &= ~0x04;
-	else
-		regs[R_EP3] |= 0x04;
-	ret = tda18271_write_regs(fe, R_EP3, 1);
+	if (priv->id == TDA18271HDC2) {
+		/* set rfagc to normal speed mode */
+		if (map->fm_rfn)
+			regs[R_EP3] &= ~0x04;
+		else
+			regs[R_EP3] |= 0x04;
+		ret = tda18271_write_regs(fe, R_EP3, 1);
+	}
 fail:
 	return ret;
 }
@@ -507,7 +522,7 @@
 	/* set cal mode to normal */
 	regs[R_EP4]  &= ~0x03;
 
-	/* update IF output level & IF notch frequency */
+	/* update IF output level */
 	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
 
 	ret = tda18271_write_regs(fe, R_EP3, 2);
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index ceae6db..7cf4f5b 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -177,6 +177,7 @@
 	{"FM Radio-INPUT1",   0x0208, 0x9002}
 };
 
+static int  xc5000_is_firmware_loaded(struct dvb_frontend *fe);
 static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
 static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
 static void xc5000_TunerReset(struct dvb_frontend *fe);
@@ -352,7 +353,7 @@
 
 static int xc_shutdown(struct xc5000_priv *priv)
 {
-	return 0;
+	return XC_RESULT_SUCCESS;
 	/* Fixme: cannot bring tuner back alive once shutdown
 	 *        without reloading the driver modules.
 	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
@@ -685,6 +686,25 @@
 	return 0;
 }
 
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+	u16 id;
+
+	ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
+	if (ret == XC_RESULT_SUCCESS) {
+		if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
+			ret = XC_RESULT_RESET_FAILURE;
+		else
+			ret = XC_RESULT_SUCCESS;
+	}
+
+	dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
+		ret == XC_RESULT_SUCCESS ? "True" : "False", id);
+	return ret;
+}
+
 static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
 
 static int xc5000_set_analog_params(struct dvb_frontend *fe,
@@ -693,7 +713,7 @@
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 
-	if(priv->fwloaded == 0)
+	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
 		xc_load_fw_and_init_tuner(fe);
 
 	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
@@ -808,11 +828,10 @@
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret = 0;
 
-	if (priv->fwloaded == 0) {
+	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
 		ret = xc5000_fwupload(fe);
 		if (ret != XC_RESULT_SUCCESS)
 			return ret;
-		priv->fwloaded = 1;
 	}
 
 	/* Start the tuner self-calibration process */
@@ -852,7 +871,6 @@
 		return -EREMOTEIO;
 	}
 	else {
-		/* priv->fwloaded = 0; */
 		return XC_RESULT_SUCCESS;
 	}
 }
@@ -933,7 +951,6 @@
 			cfg->i2c_address);
 		printk(KERN_INFO
 			"xc5000: Firmware has been loaded previously\n");
-		priv->fwloaded = 1;
 		break;
 	case XC_PRODUCT_ID_FW_NOT_LOADED:
 		printk(KERN_INFO
@@ -941,7 +958,6 @@
 			cfg->i2c_address);
 		printk(KERN_INFO
 			"xc5000: Firmware has not been loaded previously\n");
-		priv->fwloaded = 0;
 		break;
 	default:
 		printk(KERN_ERR
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
index ecebfe4..a72a988 100644
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ b/drivers/media/common/tuners/xc5000_priv.h
@@ -30,7 +30,6 @@
 	u32 bandwidth;
 	u8  video_standard;
 	u8  rf_mode;
-	u8  fwloaded;
 
 	void *devptr;
 };
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index 0a8ac64..037f7ff 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -47,6 +47,8 @@
 		return -EINVAL;
 	}
 
+	msleep(1); /* avoid I2C errors */
+
 	return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
 			       value, index, rbuf, rlen, 2000);
 }
@@ -92,16 +94,6 @@
 };
 
 /* Callbacks for DVB USB */
-static int gl861_identify_state(struct usb_device *udev,
-				struct dvb_usb_device_properties *props,
-				struct dvb_usb_device_description **desc,
-				int *cold)
-{
-	*cold = 0;
-
-	return 0;
-}
-
 static struct zl10353_config gl861_zl10353_config = {
 	.demod_address = 0x0f,
 	.no_tuner = 1,
@@ -172,7 +164,6 @@
 
 	.size_of_priv     = 0,
 
-	.identify_state   = gl861_identify_state,
 	.num_adapters = 1,
 	.adapter = {{
 
@@ -194,13 +185,15 @@
 
 	.num_device_descs = 2,
 	.devices = {
-		{   "MSI Mega Sky 55801 DVB-T USB2.0",
-			{ &gl861_table[0], NULL },
-			{ NULL },
+		{
+			.name = "MSI Mega Sky 55801 DVB-T USB2.0",
+			.cold_ids = { NULL },
+			.warm_ids = { &gl861_table[0], NULL },
 		},
-		{   "A-LINK DTU DVB-T USB2.0",
-			{ &gl861_table[1], NULL },
-			{ NULL },
+		{
+			.name = "A-LINK DTU DVB-T USB2.0",
+			.cold_ids = { NULL },
+			.warm_ids = { &gl861_table[1], NULL },
 		},
 	}
 };
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 9e7653b..118aab1 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -107,7 +107,7 @@
 			/* parameter for the MPEG2-data transfer */
 			.stream = {
 				.type = USB_BULK,
-				.count = 20,
+				.count = MAX_NO_URBS_FOR_DATA_STREAM,
 				.endpoint = 0x06,
 				.u = {
 					.bulk = {
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 084a280..03900d2 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -463,10 +463,13 @@
 			       struct dvb_frontend_parameters *p)
 {
 	struct au8522_state *state = fe->demodulator_priv;
+	int ret = -EINVAL;
 
 	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
 
-	state->current_frequency = p->frequency;
+	if ((state->current_frequency == p->frequency) &&
+	    (state->current_modulation == p->u.vsb.modulation))
+		return 0;
 
 	au8522_enable_modulation(fe, p->u.vsb.modulation);
 
@@ -476,11 +479,16 @@
 	if (fe->ops.tuner_ops.set_params) {
 		if (fe->ops.i2c_gate_ctrl)
 			fe->ops.i2c_gate_ctrl(fe, 1);
-		fe->ops.tuner_ops.set_params(fe, p);
+		ret = fe->ops.tuner_ops.set_params(fe, p);
 		if (fe->ops.i2c_gate_ctrl)
 			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
+	if (ret < 0)
+		return ret;
+
+	state->current_frequency = p->frequency;
+
 	return 0;
 }
 
@@ -498,6 +506,16 @@
 	return 0;
 }
 
+static int au8522_sleep(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	state->current_frequency = 0;
+
+	return 0;
+}
+
 static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
 	struct au8522_state *state = fe->demodulator_priv;
@@ -509,10 +527,8 @@
 	if (state->current_modulation == VSB_8) {
 		dprintk("%s() Checking VSB_8\n", __func__);
 		reg = au8522_readreg(state, 0x4088);
-		if (reg & 0x01)
-			*status |= FE_HAS_VITERBI;
-		if (reg & 0x02)
-			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+		if ((reg & 0x03) == 0x03)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
 	} else {
 		dprintk("%s() Checking QAM\n", __func__);
 		reg = au8522_readreg(state, 0x4541);
@@ -672,6 +688,7 @@
 	},
 
 	.init                 = au8522_init,
+	.sleep                = au8522_sleep,
 	.i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
 	.set_frontend         = au8522_set_frontend,
 	.get_frontend         = au8522_get_frontend,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 1755618..35435be 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -63,6 +63,7 @@
 	u32 symbol_rate;
 	fe_code_rate_t fec_inner;
 	int errmode;
+	u32 ucblocks;
 };
 
 #define STATUS_BER 0
@@ -501,8 +502,10 @@
 {
 	struct stv0299_state* state = fe->demodulator_priv;
 
-	if (state->errmode != STATUS_BER) return 0;
-	*ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+	if (state->errmode != STATUS_BER)
+		return -ENOSYS;
+
+	*ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8);
 
 	return 0;
 }
@@ -540,8 +543,12 @@
 {
 	struct stv0299_state* state = fe->demodulator_priv;
 
-	if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
-	else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+	if (state->errmode != STATUS_UCBLOCKS)
+		return -ENOSYS;
+
+	state->ucblocks += stv0299_readreg(state, 0x1e);
+	state->ucblocks += (stv0299_readreg(state, 0x1d) << 8);
+	*ucblocks = state->ucblocks;
 
 	return 0;
 }
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index 0727b80..c6ff5b8 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -116,9 +116,12 @@
 	int ret;
 
 	ret = i2c_transfer (state->i2c, msg, 2);
-	if (ret != 2)
-		printk("DVB: TDA10023: %s: readreg error (ret == %i)\n",
-				 __func__, ret);
+	if (ret != 2) {
+		int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
+		printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error "
+			"(reg == 0x%02x, ret == %i)\n",
+			num, __func__, reg, ret);
+	}
 	return b1[0];
 }
 
@@ -129,11 +132,12 @@
 	int ret;
 
 	ret = i2c_transfer (state->i2c, &msg, 1);
-	if (ret != 1)
-		printk("DVB: TDA10023(%d): %s, writereg error "
+	if (ret != 1) {
+		int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
+		printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error "
 			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
-			state->frontend.dvb->num, __func__, reg, data, ret);
-
+			num, __func__, reg, data, ret);
+	}
 	return (ret != 1) ? -EREMOTEIO : 0;
 }
 
@@ -464,7 +468,7 @@
 	int i;
 
 	/* allocate memory for the internal state */
-	state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL);
+	state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
 	if (state == NULL) goto error;
 
 	/* setup the state */
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 4997384..a0d6386 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -1248,11 +1248,14 @@
 				     struct i2c_adapter* i2c)
 {
 	struct tda1004x_state *state;
+	int id;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-	if (!state)
+	if (!state) {
+		printk(KERN_ERR "Can't alocate memory for tda10045 state\n");
 		return NULL;
+	}
 
 	/* setup the state */
 	state->config = config;
@@ -1260,7 +1263,15 @@
 	state->demod_type = TDA1004X_DEMOD_TDA10045;
 
 	/* check if the demod is there */
-	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) {
+	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
+	if (id < 0) {
+		printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
+		kfree(state);
+		return NULL;
+	}
+
+	if (id != 0x25) {
+		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
 		kfree(state);
 		return NULL;
 	}
@@ -1307,11 +1318,14 @@
 				     struct i2c_adapter* i2c)
 {
 	struct tda1004x_state *state;
+	int id;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
-	if (!state)
+	if (!state) {
+		printk(KERN_ERR "Can't alocate memory for tda10046 state\n");
 		return NULL;
+	}
 
 	/* setup the state */
 	state->config = config;
@@ -1319,7 +1333,14 @@
 	state->demod_type = TDA1004X_DEMOD_TDA10046;
 
 	/* check if the demod is there */
-	if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
+	id = tda1004x_read_byte(state, TDA1004X_CHIPID);
+	if (id < 0) {
+		printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
+		kfree(state);
+		return NULL;
+	}
+	if (id != 0x46) {
+		printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
 		kfree(state);
 		return NULL;
 	}
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index d4339b1..07643e0 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -101,6 +101,7 @@
 config DVB_BUDGET_CI
 	tristate "Budget cards with onboard CI connector"
 	depends on DVB_BUDGET_CORE && I2C
+	depends on INPUT # due to IR
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 9d81074..3a3f527 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -427,6 +427,7 @@
 			if (err) {
 				printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
 					__func__, type);
+				av7110->arm_errors++;
 				return -ETIMEDOUT;
 			}
 			msleep(1);
@@ -853,10 +854,8 @@
 
 static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
 {
-	int ret = wait_event_interruptible_timeout(av7110->bmpq,
+	int ret = wait_event_timeout(av7110->bmpq,
 				av7110->bmp_state != BMP_LOADING, 10*HZ);
-	if (ret == -ERESTARTSYS)
-		return ret;
 	if (ret == 0) {
 		printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
 		       ret, av7110->bmp_state);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 3b26fbd3..5ccb0ae 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -793,6 +793,14 @@
 
 if V4L_USB_DRIVERS && USB
 
+config USB_VIDEO_CLASS
+	tristate "USB Video Class (UVC)"
+	---help---
+	  Support for the USB Video Class (UVC).  Currently only video
+	  input devices, such as webcams, are supported.
+
+	  For more information see: <http://linux-uvc.berlios.de/>
+
 source "drivers/media/video/pvrusb2/Kconfig"
 
 source "drivers/media/video/em28xx/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index dff0d6a..ecbbfaa 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -136,6 +136,8 @@
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
+obj-$(CONFIG_USB_VIDEO_CLASS)	+= uvc/
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index a2a6983..898e123 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -77,8 +77,14 @@
 
 	/* Make sure we support the board model */
 	switch (tv.model) {
+	case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
 	case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+	case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+	case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+	case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+	case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
 	case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+	case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
 		break;
 	default:
 		printk(KERN_WARNING "%s: warning: "
@@ -175,6 +181,18 @@
 		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
 	{ USB_DEVICE(0x0fe9, 0xd620),
 		.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+	{ USB_DEVICE(0x2040, 0x7210),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7217),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721b),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721f),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7280),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x0fd9, 0x0008),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 	{ },
 };
 
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index 5f94269..9aefdc5 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -10,8 +10,8 @@
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
 	select VIDEO_CS5345
-	select DVB_S5H1409
-	select MEDIA_TUNER_MXL5005S
+	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
 	---help---
 	  This is a video4linux driver for Conexant cx23418 based
 	  PCI combo video recorder devices.
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 9a26751..faca43e 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -69,6 +69,58 @@
 			     or_value);
 }
 
+int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask)
+{
+	int retval;
+	u32 saved_reg[8] = {0};
+
+	if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
+		saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL);
+		saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+	}
+
+	if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
+		saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1);
+		saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC);
+	}
+
+	if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
+		saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL);
+		saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL);
+		saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG);
+		saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG);
+	}
+
+	retval = cx18_av_write(cx, addr, value);
+
+	if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
+		cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]);
+		cx18_av_write4(cx, CXADEC_AFE_CTRL,  saved_reg[1]);
+	}
+
+	if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
+		cx18_av_write4(cx, CXADEC_PLL_CTRL1,    saved_reg[2]);
+		cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]);
+	}
+
+	if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
+		cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL,    saved_reg[4]);
+		cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL,     saved_reg[5]);
+		cx18_av_write4(cx, CXADEC_SRC_COMB_CFG,      saved_reg[6]);
+		cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]);
+	}
+
+	return retval;
+}
+
+int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask,
+			   u8 or_value, int no_acfg_mask)
+{
+	return cx18_av_write_no_acfg(cx, addr,
+				     (cx18_av_read(cx, addr) & and_mask) |
+				     or_value, no_acfg_mask);
+}
+
 /* ----------------------------------------------------------------------- */
 
 static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
@@ -170,13 +222,15 @@
 
 	/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
 	if (std & V4L2_STD_SECAM)
-		cx18_av_write(cx, 0x402, 0);
+		cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL);
 	else {
-		cx18_av_write(cx, 0x402, 0x04);
+		cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL);
 		cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
 	}
-	cx18_av_and_or(cx, 0x401, ~0x60, 0);
-	cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
+	cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0,
+				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+	cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60,
+				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
 
 	if (std & V4L2_STD_525_60) {
 		if (std == V4L2_STD_NTSC_M_JP) {
@@ -228,7 +282,7 @@
 
 		if ((vid_input & ~0xff0) ||
 		    luma < CX18_AV_SVIDEO_LUMA1 ||
-		    luma > CX18_AV_SVIDEO_LUMA4 ||
+		    luma > CX18_AV_SVIDEO_LUMA8 ||
 		    chroma < CX18_AV_SVIDEO_CHROMA4 ||
 		    chroma > CX18_AV_SVIDEO_CHROMA8) {
 			CX18_ERR("0x%04x is not a valid video input!\n",
@@ -262,7 +316,8 @@
 
 	cx18_av_write(cx, 0x103, reg);
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
-	cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+	cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02,
+				CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 	cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
 	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
@@ -318,12 +373,12 @@
 	   This happens for example with the Yuan MPC622. */
 	if (fmt >= 4 && fmt < 8) {
 		/* Set format to NTSC-M */
-		cx18_av_and_or(cx, 0x400, ~0xf, 1);
+		cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE);
 		/* Turn off LCOMB */
 		cx18_av_and_or(cx, 0x47b, ~6, 0);
 	}
-	cx18_av_and_or(cx, 0x400, ~0xf, fmt);
-	cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+	cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE);
+	cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL);
 	cx18_av_vbi_setup(cx);
 	input_change(cx);
 	return 0;
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index 786901d..c172823 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -37,12 +37,16 @@
 	CX18_AV_COMPOSITE7,
 	CX18_AV_COMPOSITE8,
 
-	/* S-Video inputs consist of one luma input (In1-In4) ORed with one
+	/* S-Video inputs consist of one luma input (In1-In8) ORed with one
 	   chroma input (In5-In8) */
 	CX18_AV_SVIDEO_LUMA1 = 0x10,
 	CX18_AV_SVIDEO_LUMA2 = 0x20,
 	CX18_AV_SVIDEO_LUMA3 = 0x30,
 	CX18_AV_SVIDEO_LUMA4 = 0x40,
+	CX18_AV_SVIDEO_LUMA5 = 0x50,
+	CX18_AV_SVIDEO_LUMA6 = 0x60,
+	CX18_AV_SVIDEO_LUMA7 = 0x70,
+	CX18_AV_SVIDEO_LUMA8 = 0x80,
 	CX18_AV_SVIDEO_CHROMA4 = 0x400,
 	CX18_AV_SVIDEO_CHROMA5 = 0x500,
 	CX18_AV_SVIDEO_CHROMA6 = 0x600,
@@ -291,14 +295,24 @@
 #define CXADEC_SELECT_AUDIO_STANDARD_FM    0xF9  /* FM radio */
 #define CXADEC_SELECT_AUDIO_STANDARD_AUTO  0xFF  /* Auto detect */
 
+/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/
+#define CXADEC_NO_ACFG_AFE	0x01 /* Preserve 0x100-0x107 */
+#define CXADEC_NO_ACFG_PLL	0x02 /* Preserve 0x108-0x10f */
+#define CXADEC_NO_ACFG_VID	0x04 /* Preserve 0x470-0x47f */
+#define CXADEC_NO_ACFG_ALL	0x07
+
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c 							   */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value,
+				int no_acfg_mask);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value,
+				int no_acfg_mask);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index baccd07..c26e0ef 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -23,6 +23,7 @@
 
 #include "cx18-driver.h"
 #include "cx18-cards.h"
+#include "cx18-av-core.h"
 #include "cx18-i2c.h"
 #include <media/cs5345.h>
 
@@ -54,22 +55,22 @@
 	.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
 		  CX18_HW_CS5345 | CX18_HW_DVB,
 	.video_inputs = {
-		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE7 },
-		{ CX18_CARD_INPUT_SVIDEO1,    1, CX23418_SVIDEO1    },
-		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
-		{ CX18_CARD_INPUT_SVIDEO2,    2, CX23418_SVIDEO2    },
-		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2, CX18_AV_SVIDEO2    },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
-		  CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
 		{ CX18_CARD_INPUT_LINE_IN2,
-		  CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX23418_AUDIO_SERIAL, 0 },
+			 CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
 	.ddr = {
 		/* ESMT M13S128324A-5B memory */
 		.chip_config = 0x003,
@@ -81,6 +82,11 @@
 	},
 	.gpio_init.initial_value = 0x3001,
 	.gpio_init.direction = 0x3001,
+	.gpio_i2c_slave_reset = {
+		.active_lo_mask = 0x3001,
+		.msecs_asserted = 10,
+		.msecs_recovery = 40,
+	},
 	.i2c = &cx18_i2c_std,
 };
 
@@ -94,22 +100,22 @@
 	.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
 		  CX18_HW_CS5345 | CX18_HW_DVB,
 	.video_inputs = {
-		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE7 },
-		{ CX18_CARD_INPUT_SVIDEO1,    1, CX23418_SVIDEO1    },
-		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
-		{ CX18_CARD_INPUT_SVIDEO2,    2, CX23418_SVIDEO2    },
-		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2, CX18_AV_SVIDEO2    },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
-		  CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+		  CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
 		{ CX18_CARD_INPUT_LINE_IN2,
-		  CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+		  CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX23418_AUDIO_SERIAL, 0 },
+			 CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
 	.ddr = {
 		/* Samsung K4D263238G-VC33 memory */
 		.chip_config = 0x003,
@@ -121,6 +127,11 @@
 	},
 	.gpio_init.initial_value = 0x3001,
 	.gpio_init.direction = 0x3001,
+	.gpio_i2c_slave_reset = {
+		.active_lo_mask = 0x3001,
+		.msecs_asserted = 10,
+		.msecs_recovery = 40,
+	},
 	.i2c = &cx18_i2c_std,
 };
 
@@ -141,19 +152,19 @@
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_all = CX18_HW_TUNER,
 	.video_inputs = {
-		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE2 },
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
 		{ CX18_CARD_INPUT_SVIDEO1,    1,
-			CX23418_SVIDEO_LUMA3 | CX23418_SVIDEO_CHROMA4 },
-		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE1 },
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
 	},
 	.audio_inputs = {
 		{ CX18_CARD_INPUT_AUD_TUNER,
-		  CX23418_AUDIO8, 0 },
+		  CX18_AV_AUDIO8, 0 },
 		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX23418_AUDIO_SERIAL, 0 },
+		  CX18_AV_AUDIO_SERIAL, 0 },
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX23418_AUDIO_SERIAL, 0 },
+			 CX18_AV_AUDIO_SERIAL, 0 },
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
@@ -183,23 +194,26 @@
 static const struct cx18_card cx18_card_mpc718 = {
 	.type = CX18_CARD_YUAN_MPC718,
 	.name = "Yuan MPC718",
-	.comment = "Not yet supported!\n",
-	.v4l2_capabilities = 0,
+	.comment = "Some Composite and S-Video inputs are currently working.\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.hw_audio_ctrl = CX18_HW_CX23418,
 	.hw_all = CX18_HW_TUNER,
 	.video_inputs = {
-		{ CX18_CARD_INPUT_VID_TUNER,  0, CX23418_COMPOSITE7 },
-		{ CX18_CARD_INPUT_SVIDEO1,    1, CX23418_SVIDEO1    },
-		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+				CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+		{ CX18_CARD_INPUT_SVIDEO2,    2,
+				CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+		{ CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+		{ CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
 	},
 	.audio_inputs = {
-		{ CX18_CARD_INPUT_AUD_TUNER,
-		  CX23418_AUDIO8, 0 },
-		{ CX18_CARD_INPUT_LINE_IN1,
-		  CX23418_AUDIO_SERIAL, 0 },
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,       0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL, 0 },
+		{ CX18_CARD_INPUT_LINE_IN2,  CX18_AV_AUDIO_SERIAL, 0 },
 	},
-	.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
-			 CX23418_AUDIO_SERIAL, 0 },
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 },
 	.tuners = {
 		/* XC3028 tuner */
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index bccb67f..dc2dd94 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -36,36 +36,6 @@
 #define	CX18_CARD_INPUT_COMPOSITE2 	5
 #define	CX18_CARD_INPUT_COMPOSITE3 	6
 
-enum cx34180_video_input {
-	/* Composite video inputs In1-In8 */
-	CX23418_COMPOSITE1 = 1,
-	CX23418_COMPOSITE2,
-	CX23418_COMPOSITE3,
-	CX23418_COMPOSITE4,
-	CX23418_COMPOSITE5,
-	CX23418_COMPOSITE6,
-	CX23418_COMPOSITE7,
-	CX23418_COMPOSITE8,
-
-	/* S-Video inputs consist of one luma input (In1-In4) ORed with one
-	   chroma input (In5-In8) */
-	CX23418_SVIDEO_LUMA1 = 0x10,
-	CX23418_SVIDEO_LUMA2 = 0x20,
-	CX23418_SVIDEO_LUMA3 = 0x30,
-	CX23418_SVIDEO_LUMA4 = 0x40,
-	CX23418_SVIDEO_CHROMA4 = 0x400,
-	CX23418_SVIDEO_CHROMA5 = 0x500,
-	CX23418_SVIDEO_CHROMA6 = 0x600,
-	CX23418_SVIDEO_CHROMA7 = 0x700,
-	CX23418_SVIDEO_CHROMA8 = 0x800,
-
-	/* S-Video aliases for common luma/chroma combinations */
-	CX23418_SVIDEO1 = 0x510,
-	CX23418_SVIDEO2 = 0x620,
-	CX23418_SVIDEO3 = 0x730,
-	CX23418_SVIDEO4 = 0x840,
-};
-
 /* audio inputs */
 #define	CX18_CARD_INPUT_AUD_TUNER	1
 #define	CX18_CARD_INPUT_LINE_IN1 	2
@@ -75,16 +45,6 @@
 #define CX18_CARD_MAX_AUDIO_INPUTS 3
 #define CX18_CARD_MAX_TUNERS  	   2
 
-enum cx23418_audio_input {
-	/* Audio inputs: serial or In4-In8 */
-	CX23418_AUDIO_SERIAL,
-	CX23418_AUDIO4 = 4,
-	CX23418_AUDIO5,
-	CX23418_AUDIO6,
-	CX23418_AUDIO7,
-	CX23418_AUDIO8,
-};
-
 /* V4L2 capability aliases */
 #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
 			  V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
@@ -118,6 +78,13 @@
 	u32 initial_value;
 };
 
+struct cx18_gpio_i2c_slave_reset {
+	u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */
+	u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
+	int msecs_asserted; /* time period reset must remain asserted */
+	int msecs_recovery; /* time after deassert for chips to be ready */
+};
+
 struct cx18_card_tuner {
 	v4l2_std_id std; 	/* standard for which the tuner is suitable */
 	int 	    tuner; 	/* tuner ID (from tuner.h) */
@@ -154,7 +121,8 @@
 
 	/* GPIO card-specific settings */
 	u8 xceive_pin; 		/* XCeive tuner GPIO reset pin */
-	struct cx18_gpio_init 		gpio_init;
+	struct cx18_gpio_init 		 gpio_init;
+	struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
 
 	struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
 	struct cx18_card_tuner_i2c *i2c;
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index c974417..cae3898 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -69,11 +69,21 @@
 	struct dvb_demux *demux = feed->demux;
 	struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
 	struct cx18 *cx = stream->cx;
-	int ret = -EINVAL;
+	int ret;
 	u32 v;
 
 	CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
 			feed->pid, feed->index);
+
+	mutex_lock(&cx->serialize_lock);
+	ret = cx18_init_on_first_open(cx);
+	mutex_unlock(&cx->serialize_lock);
+	if (ret) {
+		CX18_ERR("Failed to initialize firmware starting DVB feed\n");
+		return ret;
+	}
+	ret = -EINVAL;
+
 	switch (cx->card->type) {
 	case CX18_CARD_HVR_1600_ESMT:
 	case CX18_CARD_HVR_1600_SAMSUNG:
@@ -101,6 +111,11 @@
 		if (stream->dvb.feeding++ == 0) {
 			CX18_DEBUG_INFO("Starting Transport DMA\n");
 			ret = cx18_start_v4l2_encode_stream(stream);
+			if (ret < 0) {
+				CX18_DEBUG_INFO(
+					"Failed to start Transport DMA\n");
+				stream->dvb.feeding--;
+			}
 		} else
 			ret = 0;
 		mutex_unlock(&stream->dvb.feedlock);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index ceb6365..b302833 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -53,10 +53,34 @@
 	write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
 			CX18_REG_GPIO_OUT1);
 	write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
-	write_reg((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
+	write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
 			CX18_REG_GPIO_OUT2);
 }
 
+void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
+{
+	const struct cx18_gpio_i2c_slave_reset *p;
+
+	p = &cx->card->gpio_i2c_slave_reset;
+
+	if ((p->active_lo_mask | p->active_hi_mask) == 0)
+		return;
+
+	/* Assuming that the masks are a subset of the bits in gpio_dir */
+
+	/* Assert */
+	cx->gpio_val =
+		(cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
+	gpio_write(cx);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+	/* Deassert */
+	cx->gpio_val =
+		(cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
+	gpio_write(cx);
+	schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+
 void cx18_gpio_init(struct cx18 *cx)
 {
 	cx->gpio_dir = cx->card->gpio_init.direction;
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index 41bac88..525c328 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -21,4 +21,5 @@
  */
 
 void cx18_gpio_init(struct cx18 *cx);
+void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
 int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 1d6c51a..680bc4e 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -405,6 +405,8 @@
 	cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
 	cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 
+	cx18_reset_i2c_slaves_gpio(cx);
+
 	return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
 		i2c_bit_add_bus(&cx->i2c_adap[1]);
 }
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 607efdc..1da6f13 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -433,7 +433,7 @@
 		int chroma = vid_input & 0xf00;
 
 		if ((vid_input & ~0xff0) ||
-		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
 		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
 			v4l_err(client, "0x%04x is not a valid video input!\n",
 				vid_input);
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index e976fc6..80c8883 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -332,6 +332,12 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 
+	if (!chip) {
+		printk(KERN_ERR "BUG: cx88 can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+
 	err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
 	if (err < 0)
 		goto _error;
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 92b2a6d..3c00610 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -268,6 +268,12 @@
 
 	dprintk("opening device and trying to acquire exclusive lock\n");
 
+	if (!dev) {
+		printk(KERN_ERR "BUG: em28xx can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+
 	/* Sets volume, mute, etc */
 
 	dev->mute = 0;
@@ -415,6 +421,12 @@
 	static int          devnr;
 	int                 ret, err;
 
+	if (dev->has_audio_class) {
+		/* This device does not support the extension (in this case
+		   the device is expecting the snd-usb-audio module */
+		return 0;
+	}
+
 	printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
 			 "non standard usbaudio\n");
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
@@ -458,6 +470,12 @@
 	if (dev == NULL)
 		return 0;
 
+	if (dev->has_audio_class) {
+		/* This device does not support the extension (in this case
+		   the device is expecting the snd-usb-audio module */
+		return 0;
+	}
+
 	if (dev->adev) {
 		snd_card_free(dev->adev->sndcard);
 		kfree(dev->adev);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3e4f3c7..8cbda43 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -157,6 +157,7 @@
 		.tda9887_conf = TDA9887_PRESENT,
 		.tuner_type   = TUNER_XC2028,
 		.mts_firmware = 1,
+		.has_dvb        = 1,
 		.decoder      = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
@@ -524,6 +525,9 @@
 	rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
 	if (rc > 0) {
 		switch (rc) {
+		case CHIP_ID_EM2860:
+			em28xx_info("chip ID is em2860\n");
+			break;
 		case CHIP_ID_EM2883:
 			em28xx_info("chip ID is em2882/em2883\n");
 			dev->wait_after_write = 0;
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 8cf4983..0b2333e 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -382,6 +382,11 @@
 	int result = 0;
 	struct em28xx_dvb *dvb;
 
+	if (!dev->has_dvb) {
+		/* This device does not support the extension */
+		return 0;
+	}
+
 	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
 
 	if (dvb == NULL) {
@@ -444,6 +449,11 @@
 
 static int dvb_fini(struct em28xx *dev)
 {
+	if (!dev->has_dvb) {
+		/* This device does not support the extension */
+		return 0;
+	}
+
 	if (dev->dvb) {
 		unregister_dvb(dev->dvb);
 		dev->dvb = NULL;
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 9058bed..fac1ab2 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -84,5 +84,6 @@
 
 /* FIXME: Need to be populated with the other chip ID's */
 enum em28xx_chip_id {
+	CHIP_ID_EM2860 = 34,
 	CHIP_ID_EM2883 = 36,
 };
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index fb163ec..285bc62 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1848,32 +1848,28 @@
 
 int em28xx_register_extension(struct em28xx_ops *ops)
 {
-	struct em28xx *h, *dev = NULL;
-
-	list_for_each_entry(h, &em28xx_devlist, devlist)
-		dev = h;
+	struct em28xx *dev = NULL;
 
 	mutex_lock(&em28xx_extension_devlist_lock);
 	list_add_tail(&ops->next, &em28xx_extension_devlist);
-	if (dev)
-		ops->init(dev);
-
+	list_for_each_entry(dev, &em28xx_devlist, devlist) {
+		if (dev)
+			ops->init(dev);
+	}
 	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
 	mutex_unlock(&em28xx_extension_devlist_lock);
-
 	return 0;
 }
 EXPORT_SYMBOL(em28xx_register_extension);
 
 void em28xx_unregister_extension(struct em28xx_ops *ops)
 {
-	struct em28xx *h, *dev = NULL;
+	struct em28xx *dev = NULL;
 
-	list_for_each_entry(h, &em28xx_devlist, devlist)
-		dev = h;
-
-	if (dev)
-		ops->fini(dev);
+	list_for_each_entry(dev, &em28xx_devlist, devlist) {
+		if (dev)
+			ops->fini(dev);
+	}
 
 	mutex_lock(&em28xx_extension_devlist_lock);
 	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 7cc8e9b..5ec5bb9 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1019,12 +1019,12 @@
 	struct pxa_camera_dev *pcdev;
 	struct resource *res;
 	void __iomem *base;
-	unsigned int irq;
+	int irq;
 	int err = 0;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq = platform_get_irq(pdev, 0);
-	if (!res || !irq) {
+	if (!res || irq < 0) {
 		err = -ENODEV;
 		goto exit;
 	}
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ba30824..f118de6 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -613,9 +613,15 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
-	struct saa7134_dev *dev = saa7134->dev;
+	struct saa7134_dev *dev;
 	int amux, err;
 
+	if (!saa7134) {
+		printk(KERN_ERR "BUG: saa7134 can't find device struct."
+				" Can't proceed with open\n");
+		return -ENODEV;
+	}
+	dev = saa7134->dev;
 	mutex_lock(&dev->dmasound.lock);
 
 	dev->dmasound.read_count  = 0;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index b111903..2618cfa 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -4114,11 +4114,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		 /*
-		    TODO:
 		 .mpeg           = SAA7134_MPEG_DVB,
-		 */
-
 		 .inputs         = {{
 			 .name = name_tv,
 			 .vmux = 1,
@@ -4157,7 +4153,7 @@
 		} },
 		.radio = {
 			.name = name_radio,
-			.amux = LINE1,
+			.amux = TV,
 		},
 	},
 	[SAA7134_BOARD_AVERMEDIA_M115] = {
@@ -4167,6 +4163,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
@@ -5351,22 +5348,21 @@
 {
 	switch (command) {
 	case XC2028_TUNER_RESET:
-		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
-		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
-		mdelay(250);
-		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0);
-		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0);
-		mdelay(250);
-		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
-		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
-		mdelay(250);
-		saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
-		saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
-		saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
-		saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
-		saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
-			   0x0001e000, 0x0001e000);
-		return 0;
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00000000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+		switch (dev->board) {
+		case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+			saa7134_set_gpio(dev, 23, 0);
+			msleep(10);
+			saa7134_set_gpio(dev, 23, 1);
+		break;
+		case SAA7134_BOARD_AVERMEDIA_A16D:
+			saa7134_set_gpio(dev, 21, 0);
+			msleep(10);
+			saa7134_set_gpio(dev, 21, 1);
+		break;
+		}
+	return 0;
 	}
 	return -EINVAL;
 }
@@ -5553,9 +5549,7 @@
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
-	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
 	case SAA7134_BOARD_AVERMEDIA_M115:
-	case SAA7134_BOARD_AVERMEDIA_A16D:
 		/* power-down tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0);
@@ -5565,6 +5559,18 @@
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
 		msleep(10);
 		break;
+	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		saa7134_set_gpio(dev, 23, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 23, 1);
+		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		saa7134_set_gpio(dev, 21, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 21, 1);
+		msleep(1);
+		dev->has_remote = SAA7134_REMOTE_GPIO;
+		break;
 	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
 		/* power-down tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x000A8004, 0x000A8004);
@@ -5615,7 +5621,8 @@
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x80040100, 0x80040100);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
 		printk("%s: %s: hybrid analog/dvb card\n"
-		       "%s: Sorry, only the analog inputs are supported for now.\n",
+		       "%s: Sorry, only analog s-video and composite input "
+		       "are supported for now.\n",
 			dev->name, card(dev).name, dev->name);
 		break;
 	}
@@ -5675,6 +5682,7 @@
 
 		switch (dev->board) {
 		case SAA7134_BOARD_AVERMEDIA_A16D:
+		case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
 			ctl.demod = XC3028_FE_ZARLINK456;
 			break;
 		default:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 469f93a..341b101 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -153,12 +153,12 @@
 	return 0;
 }
 
-static int mt352_aver_a16d_init(struct dvb_frontend *fe)
+static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
 {
-	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x2d };
-	static u8 reset []         = { RESET,      0x80 };
-	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
-	static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+	static u8 clock_config []  = { CLOCK_CTL, 0x38, 0x2d };
+	static u8 reset []         = { RESET, 0x80 };
+	static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+	static u8 agc_cfg []       = { AGC_TARGET, 0xe };
 	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
 
 	mt352_write(fe, clock_config,   sizeof(clock_config));
@@ -167,12 +167,9 @@
 	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
 	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
 	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
 	return 0;
 }
 
-
-
 static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
 					   struct dvb_frontend_parameters* params)
 {
@@ -215,14 +212,10 @@
 	.demod_init    = mt352_aver777_init,
 };
 
-static struct mt352_config avermedia_16d = {
-	.demod_address = 0xf,
-	.demod_init    = mt352_aver_a16d_init,
-};
-
-static struct mt352_config avermedia_e506r_mt352_dev = {
+static struct mt352_config avermedia_xc3028_mt352_dev = {
 	.demod_address   = (0x1e >> 1),
 	.no_tuner        = 1,
+	.demod_init      = mt352_avermedia_xc3028_init,
 };
 
 /* ==================================================================
@@ -975,9 +968,10 @@
 		}
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A16D:
-		dprintk("avertv A16D dvb setup\n");
-		dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_16d,
-					       &dev->i2c_adap);
+		dprintk("AverMedia A16D dvb setup\n");
+		dev->dvb.frontend = dvb_attach(mt352_attach,
+						&avermedia_xc3028_mt352_dev,
+						&dev->i2c_adap);
 		attach_xc3028 = 1;
 		break;
 	case SAA7134_BOARD_MD7134:
@@ -1091,7 +1085,8 @@
 					ads_tech_duo_config.tuner_address);
 				goto dettach_frontend;
 			}
-		}
+		} else
+			wprintk("failed to attach tda10046\n");
 		break;
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
 		if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
@@ -1260,11 +1255,14 @@
 			goto dettach_frontend;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+		dprintk("AverMedia E506R dvb setup\n");
+		saa7134_set_gpio(dev, 25, 0);
+		msleep(10);
+		saa7134_set_gpio(dev, 25, 1);
 		dev->dvb.frontend = dvb_attach(mt352_attach,
-					       &avermedia_e506r_mt352_dev,
-					       &dev->i2c_adap);
+						&avermedia_xc3028_mt352_dev,
+						&dev->i2c_adap);
 		attach_xc3028 = 1;
-		break;
 	case SAA7134_BOARD_MD7134_BRIDGE_2:
 		dev->dvb.frontend = dvb_attach(tda10086_attach,
 						&sd1878_4m, &dev->i2c_adap);
@@ -1338,7 +1336,8 @@
 	return ret;
 
 dettach_frontend:
-	dvb_frontend_detach(dev->dvb.frontend);
+	if (dev->dvb.frontend)
+		dvb_frontend_detach(dev->dvb.frontend);
 	dev->dvb.frontend = NULL;
 
 	return -1;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 81431ee..3ae71a3 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -110,9 +110,10 @@
 {
 	struct saa7134_dev *dev = file->private_data;
 
+	mutex_lock(&dev->empress_tsq.vb_lock);
+
 	videobuf_stop(&dev->empress_tsq);
 	videobuf_mmap_free(&dev->empress_tsq);
-	dev->empress_users--;
 
 	/* stop the encoder */
 	ts_reset_encoder(dev);
@@ -121,6 +122,10 @@
 	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
 		saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
 
+	dev->empress_users--;
+
+	mutex_unlock(&dev->empress_tsq.vb_lock);
+
 	return 0;
 }
 
@@ -218,8 +223,7 @@
 static int empress_g_fmt_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
 
@@ -232,8 +236,7 @@
 static int empress_s_fmt_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
 
@@ -247,8 +250,7 @@
 static int empress_reqbufs(struct file *file, void *priv,
 					struct v4l2_requestbuffers *p)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	return videobuf_reqbufs(&dev->empress_tsq, p);
 }
@@ -256,24 +258,21 @@
 static int empress_querybuf(struct file *file, void *priv,
 					struct v4l2_buffer *b)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	return videobuf_querybuf(&dev->empress_tsq, b);
 }
 
 static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	return videobuf_qbuf(&dev->empress_tsq, b);
 }
 
 static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	return videobuf_dqbuf(&dev->empress_tsq, b,
 				file->f_flags & O_NONBLOCK);
@@ -282,8 +281,7 @@
 static int empress_streamon(struct file *file, void *priv,
 					enum v4l2_buf_type type)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	return videobuf_streamon(&dev->empress_tsq);
 }
@@ -291,8 +289,7 @@
 static int empress_streamoff(struct file *file, void *priv,
 					enum v4l2_buf_type type)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	return videobuf_streamoff(&dev->empress_tsq);
 }
@@ -300,8 +297,7 @@
 static int empress_s_ext_ctrls(struct file *file, void *priv,
 			       struct v4l2_ext_controls *ctrls)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	/* count == 0 is abused in saa6752hs.c, so that special
 		case is handled here explicitly. */
@@ -320,8 +316,7 @@
 static int empress_g_ext_ctrls(struct file *file, void *priv,
 			       struct v4l2_ext_controls *ctrls)
 {
-	struct saa7134_fh *fh = priv;
-	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_dev *dev = file->private_data;
 
 	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 919632b..76e6501 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -323,6 +323,15 @@
 		saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
 		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
 		break;
+	case SAA7134_BOARD_AVERMEDIA_A16D:
+		ir_codes     = ir_codes_avermedia_a16d;
+		mask_keycode = 0x02F200;
+		mask_keydown = 0x000400;
+		polling      = 50; /* ms */
+		/* Without this we won't receive key up events */
+		saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+		saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+		break;
 	case SAA7134_BOARD_KWORLD_TERMINATOR:
 		ir_codes     = ir_codes_pixelview;
 		mask_keycode = 0x00001f;
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index a1b9244..d015bfe 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -763,15 +763,6 @@
 	.owner	= THIS_MODULE,
 };
 
-/*
- * Image capture host - this is a host device, not a bus device, so,
- * no bus reference, no probing.
- */
-static struct class soc_camera_host_class = {
-	.owner		= THIS_MODULE,
-	.name		= "camera_host",
-};
-
 static void dummy_release(struct device *dev)
 {
 }
@@ -801,7 +792,6 @@
 
 	/* Number might be equal to the platform device ID */
 	sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
-	ici->dev.class = &soc_camera_host_class;
 
 	mutex_lock(&list_lock);
 	list_for_each_entry(ix, &hosts, list) {
@@ -1003,14 +993,9 @@
 	ret = driver_register(&ic_drv);
 	if (ret)
 		goto edrvr;
-	ret = class_register(&soc_camera_host_class);
-	if (ret)
-		goto eclr;
 
 	return 0;
 
-eclr:
-	driver_unregister(&ic_drv);
 edrvr:
 	bus_unregister(&soc_camera_bus_type);
 	return ret;
@@ -1018,7 +1003,6 @@
 
 static void __exit soc_camera_exit(void)
 {
-	class_unregister(&soc_camera_host_class);
 	driver_unregister(&ic_drv);
 	bus_unregister(&soc_camera_bus_type);
 }
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
new file mode 100644
index 0000000..968c199
--- /dev/null
+++ b/drivers/media/video/uvc/Makefile
@@ -0,0 +1,3 @@
+uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
+		  uvc_status.o uvc_isight.o
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
new file mode 100644
index 0000000..f0ee46d
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -0,0 +1,1256 @@
+/*
+ *      uvc_ctrl.c  --  USB Video Class driver - Controls
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+#define UVC_CTRL_NDATA		2
+#define UVC_CTRL_DATA_CURRENT	0
+#define UVC_CTRL_DATA_BACKUP	1
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_control_info uvc_ctrls[] = {
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BRIGHTNESS_CONTROL,
+		.index		= 0,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_CONTRAST_CONTROL,
+		.index		= 1,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_CONTROL,
+		.index		= 2,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SATURATION_CONTROL,
+		.index		= 3,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SHARPNESS_CONTROL,
+		.index		= 4,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAMMA_CONTROL,
+		.index		= 5,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BACKLIGHT_COMPENSATION_CONTROL,
+		.index		= 8,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAIN_CONTROL,
+		.index		= 9,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_POWER_LINE_FREQUENCY_CONTROL,
+		.index		= 10,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_AUTO_CONTROL,
+		.index		= 11,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_MODE_CONTROL,
+		.index		= 1,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_PRIORITY_CONTROL,
+		.index		= 2,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+		.index		= 3,
+		.size		= 4,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_ABSOLUTE_CONTROL,
+		.index		= 5,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_AUTO_CONTROL,
+		.index		= 17,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+		.index		= 12,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+		.index		= 6,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+		.index		= 13,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.index		= 7,
+		.size		= 4,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+};
+
+static struct uvc_menu_info power_line_frequency_controls[] = {
+	{ 0, "Disabled" },
+	{ 1, "50 Hz" },
+	{ 2, "60 Hz" },
+};
+
+static struct uvc_menu_info exposure_auto_controls[] = {
+	{ 1, "Manual Mode" },
+	{ 2, "Auto Mode" },
+	{ 4, "Shutter Priority Mode" },
+	{ 8, "Aperture Priority Mode" },
+};
+
+static struct uvc_control_mapping uvc_ctrl_mappings[] = {
+	{
+		.id		= V4L2_CID_BRIGHTNESS,
+		.name		= "Brightness",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BRIGHTNESS_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_CONTRAST,
+		.name		= "Contrast",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_CONTRAST_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_HUE,
+		.name		= "Hue",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_SATURATION,
+		.name		= "Saturation",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SATURATION_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_SHARPNESS,
+		.name		= "Sharpness",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SHARPNESS_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_GAMMA,
+		.name		= "Gamma",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAMMA_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_BACKLIGHT_COMPENSATION,
+		.name		= "Backlight Compensation",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BACKLIGHT_COMPENSATION_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_GAIN,
+		.name		= "Gain",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAIN_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_POWER_LINE_FREQUENCY,
+		.name		= "Power Line Frequency",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_POWER_LINE_FREQUENCY_CONTROL,
+		.size		= 2,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
+		.menu_info	= power_line_frequency_controls,
+		.menu_count	= ARRAY_SIZE(power_line_frequency_controls),
+	},
+	{
+		.id		= V4L2_CID_HUE_AUTO,
+		.name		= "Hue, Auto",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_EXPOSURE_AUTO,
+		.name		= "Exposure, Auto",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_MODE_CONTROL,
+		.size		= 4,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+		.data_type	= UVC_CTRL_DATA_TYPE_BITMASK,
+		.menu_info	= exposure_auto_controls,
+		.menu_count	= ARRAY_SIZE(exposure_auto_controls),
+	},
+	{
+		.id		= V4L2_CID_EXPOSURE_AUTO_PRIORITY,
+		.name		= "Exposure, Auto Priority",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_PRIORITY_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_EXPOSURE_ABSOLUTE,
+		.name		= "Exposure (Absolute)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+		.size		= 32,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
+		.name		= "White Balance Temperature, Auto",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+		.name		= "White Balance Temperature",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
+		.name		= "White Balance Component, Auto",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_BLUE_BALANCE,
+		.name		= "White Balance Blue Component",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_RED_BALANCE,
+		.name		= "White Balance Red Component",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.size		= 16,
+		.offset		= 16,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_FOCUS_ABSOLUTE,
+		.name		= "Focus (absolute)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_ABSOLUTE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_FOCUS_AUTO,
+		.name		= "Focus, Auto",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
+{
+	return ctrl->data + id * ctrl->info->size;
+}
+
+static inline int uvc_get_bit(const __u8 *data, int bit)
+{
+	return (data[bit >> 3] >> (bit & 7)) & 1;
+}
+
+/* Extract the bit string specified by mapping->offset and mapping->size
+ * from the little-endian data stored at 'data' and return the result as
+ * a signed 32bit integer. Sign extension will be performed if the mapping
+ * references a signed data type.
+ */
+static __s32 uvc_get_le_value(const __u8 *data,
+	struct uvc_control_mapping *mapping)
+{
+	int bits = mapping->size;
+	int offset = mapping->offset;
+	__s32 value = 0;
+	__u8 mask;
+
+	data += offset / 8;
+	offset &= 7;
+	mask = ((1LL << bits) - 1) << offset;
+
+	for (; bits > 0; data++) {
+		__u8 byte = *data & mask;
+		value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
+		bits -= 8 - (offset > 0 ? offset : 0);
+		offset -= 8;
+		mask = (1 << bits) - 1;
+	}
+
+	/* Sign-extend the value if needed */
+	if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
+		value |= -(value & (1 << (mapping->size - 1)));
+
+	return value;
+}
+
+/* Set the bit string specified by mapping->offset and mapping->size
+ * in the little-endian data stored at 'data' to the value 'value'.
+ */
+static void uvc_set_le_value(__s32 value, __u8 *data,
+	struct uvc_control_mapping *mapping)
+{
+	int bits = mapping->size;
+	int offset = mapping->offset;
+	__u8 mask;
+
+	data += offset / 8;
+	offset &= 7;
+
+	for (; bits > 0; data++) {
+		mask = ((1LL << bits) - 1) << offset;
+		*data = (*data & ~mask) | ((value << offset) & mask);
+		value >>= offset ? offset : 8;
+		bits -= 8 - offset;
+		offset = 0;
+	}
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
+static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const __u8 uvc_media_transport_input_guid[16] =
+	UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
+
+static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
+{
+	switch (UVC_ENTITY_TYPE(entity)) {
+	case ITT_CAMERA:
+		return memcmp(uvc_camera_guid, guid, 16) == 0;
+
+	case ITT_MEDIA_TRANSPORT_INPUT:
+		return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
+
+	case VC_PROCESSING_UNIT:
+		return memcmp(uvc_processing_guid, guid, 16) == 0;
+
+	case VC_EXTENSION_UNIT:
+		return memcmp(entity->extension.guidExtensionCode,
+			      guid, 16) == 0;
+
+	default:
+		return 0;
+	}
+}
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
+	struct uvc_control_mapping **mapping, struct uvc_control **control,
+	int next)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *map;
+	unsigned int i;
+
+	if (entity == NULL)
+		return;
+
+	for (i = 0; i < entity->ncontrols; ++i) {
+		ctrl = &entity->controls[i];
+		if (ctrl->info == NULL)
+			continue;
+
+		list_for_each_entry(map, &ctrl->info->mappings, list) {
+			if ((map->id == v4l2_id) && !next) {
+				*control = ctrl;
+				*mapping = map;
+				return;
+			}
+
+			if ((*mapping == NULL || (*mapping)->id > map->id) &&
+			    (map->id > v4l2_id) && next) {
+				*control = ctrl;
+				*mapping = map;
+			}
+		}
+	}
+}
+
+struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+	__u32 v4l2_id, struct uvc_control_mapping **mapping)
+{
+	struct uvc_control *ctrl = NULL;
+	struct uvc_entity *entity;
+	int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+
+	*mapping = NULL;
+
+	/* Mask the query flags. */
+	v4l2_id &= V4L2_CTRL_ID_MASK;
+
+	/* Find the control. */
+	__uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);
+	if (ctrl && !next)
+		return ctrl;
+
+	list_for_each_entry(entity, &video->iterms, chain) {
+		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+		if (ctrl && !next)
+			return ctrl;
+	}
+
+	list_for_each_entry(entity, &video->extensions, chain) {
+		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+		if (ctrl && !next)
+			return ctrl;
+	}
+
+	if (ctrl == NULL && !next)
+		uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",
+				v4l2_id);
+
+	return ctrl;
+}
+
+int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+	struct v4l2_queryctrl *v4l2_ctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	struct uvc_menu_info *menu;
+	unsigned int i;
+	__u8 data[8];
+	int ret;
+
+	ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
+	if (ctrl == NULL)
+		return -EINVAL;
+
+	v4l2_ctrl->id = mapping->id;
+	v4l2_ctrl->type = mapping->v4l2_type;
+	strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+	v4l2_ctrl->flags = 0;
+
+	if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+	}
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		v4l2_ctrl->minimum = 0;
+		v4l2_ctrl->maximum = mapping->menu_count - 1;
+		v4l2_ctrl->step = 1;
+
+		menu = mapping->menu_info;
+		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+			if (menu->value == v4l2_ctrl->default_value) {
+				v4l2_ctrl->default_value = i;
+				break;
+			}
+		}
+
+		return 0;
+	}
+
+	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+	}
+	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+	}
+	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+	}
+
+	return 0;
+}
+
+
+/* --------------------------------------------------------------------------
+ * Control transactions
+ *
+ * To make extended set operations as atomic as the hardware allows, controls
+ * are handled using begin/commit/rollback operations.
+ *
+ * At the beginning of a set request, uvc_ctrl_begin should be called to
+ * initialize the request. This function acquires the control lock.
+ *
+ * When setting a control, the new value is stored in the control data field
+ * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for
+ * later processing. If the UVC and V4L2 control sizes differ, the current
+ * value is loaded from the hardware before storing the new value in the data
+ * field.
+ *
+ * After processing all controls in the transaction, uvc_ctrl_commit or
+ * uvc_ctrl_rollback must be called to apply the pending changes to the
+ * hardware or revert them. When applying changes, all controls marked as
+ * dirty will be modified in the UVC device, and the dirty flag will be
+ * cleared. When reverting controls, the control data field
+ * UVC_CTRL_DATA_CURRENT is reverted to its previous value
+ * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
+ * control lock.
+ */
+int uvc_ctrl_begin(struct uvc_video_device *video)
+{
+	return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;
+}
+
+static int uvc_ctrl_commit_entity(struct uvc_device *dev,
+	struct uvc_entity *entity, int rollback)
+{
+	struct uvc_control *ctrl;
+	unsigned int i;
+	int ret;
+
+	if (entity == NULL)
+		return 0;
+
+	for (i = 0; i < entity->ncontrols; ++i) {
+		ctrl = &entity->controls[i];
+		if (ctrl->info == NULL || !ctrl->dirty)
+			continue;
+
+		if (!rollback)
+			ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+				dev->intfnum, ctrl->info->selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info->size);
+		else
+			ret = 0;
+
+		if (rollback || ret < 0)
+			memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+			       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+			       ctrl->info->size);
+
+		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+			ctrl->loaded = 0;
+
+		ctrl->dirty = 0;
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
+{
+	struct uvc_entity *entity;
+	int ret = 0;
+
+	/* Find the control. */
+	ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);
+	if (ret < 0)
+		goto done;
+
+	list_for_each_entry(entity, &video->iterms, chain) {
+		ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+		if (ret < 0)
+			goto done;
+	}
+
+	list_for_each_entry(entity, &video->extensions, chain) {
+		ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+		if (ret < 0)
+			goto done;
+	}
+
+done:
+	mutex_unlock(&video->ctrl_mutex);
+	return ret;
+}
+
+int uvc_ctrl_get(struct uvc_video_device *video,
+	struct v4l2_ext_control *xctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	struct uvc_menu_info *menu;
+	unsigned int i;
+	int ret;
+
+	ctrl = uvc_find_control(video, xctrl->id, &mapping);
+	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+		return -EINVAL;
+
+	if (!ctrl->loaded) {
+		ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info->size);
+		if (ret < 0)
+			return ret;
+
+		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+			ctrl->loaded = 1;
+	}
+
+	xctrl->value = uvc_get_le_value(
+		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		menu = mapping->menu_info;
+		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+			if (menu->value == xctrl->value) {
+				xctrl->value = i;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int uvc_ctrl_set(struct uvc_video_device *video,
+	struct v4l2_ext_control *xctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	s32 value = xctrl->value;
+	int ret;
+
+	ctrl = uvc_find_control(video, xctrl->id, &mapping);
+	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
+		return -EINVAL;
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		if (value < 0 || value >= mapping->menu_count)
+			return -EINVAL;
+		value = mapping->menu_info[value].value;
+	}
+
+	if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
+		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
+			memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				0, ctrl->info->size);
+		} else {
+			ret = uvc_query_ctrl(video->dev, GET_CUR,
+				ctrl->entity->id, video->dev->intfnum,
+				ctrl->info->selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info->size);
+			if (ret < 0)
+				return ret;
+		}
+
+		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+			ctrl->loaded = 1;
+	}
+
+	if (!ctrl->dirty) {
+		memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+		       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+		       ctrl->info->size);
+	}
+
+	uvc_set_le_value(value,
+		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+	ctrl->dirty = 1;
+	ctrl->modified = 1;
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Dynamic controls
+ */
+
+int uvc_xu_ctrl_query(struct uvc_video_device *video,
+	struct uvc_xu_control *xctrl, int set)
+{
+	struct uvc_entity *entity;
+	struct uvc_control *ctrl = NULL;
+	unsigned int i, found = 0;
+	__u8 *data;
+	int ret;
+
+	/* Find the extension unit. */
+	list_for_each_entry(entity, &video->extensions, chain) {
+		if (entity->id == xctrl->unit)
+			break;
+	}
+
+	if (entity->id != xctrl->unit) {
+		uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
+			xctrl->unit);
+		return -EINVAL;
+	}
+
+	/* Find the control. */
+	for (i = 0; i < entity->ncontrols; ++i) {
+		ctrl = &entity->controls[i];
+		if (ctrl->info == NULL)
+			continue;
+
+		if (ctrl->info->selector == xctrl->selector) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		uvc_trace(UVC_TRACE_CONTROL,
+			"Control " UVC_GUID_FORMAT "/%u not found.\n",
+			UVC_GUID_ARGS(entity->extension.guidExtensionCode),
+			xctrl->selector);
+		return -EINVAL;
+	}
+
+	/* Validate control data size. */
+	if (ctrl->info->size != xctrl->size)
+		return -EINVAL;
+
+	if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) ||
+	    (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&video->ctrl_mutex))
+		return -ERESTARTSYS;
+
+	memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+	       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+	       xctrl->size);
+	data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
+
+	if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
+			     video->dev->intfnum, xctrl->selector, data,
+			     xctrl->size);
+	if (ret < 0)
+		goto out;
+
+	if (!set && copy_to_user(xctrl->data, data, xctrl->size)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+out:
+	if (ret)
+		memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+		       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+		       xctrl->size);
+
+	mutex_unlock(&video->ctrl_mutex);
+	return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Restore control values after resume, skipping controls that haven't been
+ * changed.
+ *
+ * TODO
+ * - Don't restore modified controls that are back to their default value.
+ * - Handle restore order (Auto-Exposure Mode should be restored before
+ *   Exposure Time).
+ */
+int uvc_ctrl_resume_device(struct uvc_device *dev)
+{
+	struct uvc_control *ctrl;
+	struct uvc_entity *entity;
+	unsigned int i;
+	int ret;
+
+	/* Walk the entities list and restore controls when possible. */
+	list_for_each_entry(entity, &dev->entities, list) {
+
+		for (i = 0; i < entity->ncontrols; ++i) {
+			ctrl = &entity->controls[i];
+
+			if (ctrl->info == NULL || !ctrl->modified ||
+			    (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
+				continue;
+
+			printk(KERN_INFO "restoring control " UVC_GUID_FORMAT
+				"/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity),
+				ctrl->info->index, ctrl->info->selector);
+			ctrl->dirty = 1;
+		}
+
+		ret = uvc_ctrl_commit_entity(dev, entity, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Control and mapping handling
+ */
+
+static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+	struct uvc_control_info *info)
+{
+	struct uvc_entity *entity;
+	struct uvc_control *ctrl = NULL;
+	int ret, found = 0;
+	unsigned int i;
+
+	list_for_each_entry(entity, &dev->entities, list) {
+		if (!uvc_entity_match_guid(entity, info->entity))
+			continue;
+
+		for (i = 0; i < entity->ncontrols; ++i) {
+			ctrl = &entity->controls[i];
+			if (ctrl->index == info->index) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (found)
+			break;
+	}
+
+	if (!found)
+		return;
+
+	if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+		/* Check if the device control information and length match
+		 * the user supplied information.
+		 */
+		__u32 flags;
+		__le16 size;
+		__u8 inf;
+
+		if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
+			dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+			uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
+				"control " UVC_GUID_FORMAT "/%u (%d).\n",
+				UVC_GUID_ARGS(info->entity), info->selector,
+				ret);
+			return;
+		}
+
+		if (info->size != le16_to_cpu(size)) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT
+				"/%u size doesn't match user supplied "
+				"value.\n", UVC_GUID_ARGS(info->entity),
+				info->selector);
+			return;
+		}
+
+		if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
+			dev->intfnum, info->selector, &inf, 1)) < 0) {
+			uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
+				"control " UVC_GUID_FORMAT "/%u (%d).\n",
+				UVC_GUID_ARGS(info->entity), info->selector,
+				ret);
+			return;
+		}
+
+		flags = info->flags;
+		if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
+		    ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control "
+				UVC_GUID_FORMAT "/%u flags don't match "
+				"supported operations.\n",
+				UVC_GUID_ARGS(info->entity), info->selector);
+			return;
+		}
+	}
+
+	ctrl->info = info;
+	ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
+	uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u "
+		"to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity),
+		ctrl->info->selector, dev->udev->devpath, entity->id);
+}
+
+/*
+ * Add an item to the UVC control information list, and instantiate a control
+ * structure for each device that supports the control.
+ */
+int uvc_ctrl_add_info(struct uvc_control_info *info)
+{
+	struct uvc_control_info *ctrl;
+	struct uvc_device *dev;
+	int ret = 0;
+
+	/* Find matching controls by walking the devices, entities and
+	 * controls list.
+	 */
+	mutex_lock(&uvc_driver.ctrl_mutex);
+
+	/* First check if the list contains a control matching the new one.
+	 * Bail out if it does.
+	 */
+	list_for_each_entry(ctrl, &uvc_driver.controls, list) {
+		if (memcmp(ctrl->entity, info->entity, 16))
+			continue;
+
+		if (ctrl->selector == info->selector) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control "
+				UVC_GUID_FORMAT "/%u is already defined.\n",
+				UVC_GUID_ARGS(info->entity), info->selector);
+			ret = -EEXIST;
+			goto end;
+		}
+		if (ctrl->index == info->index) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control "
+				UVC_GUID_FORMAT "/%u would overwrite index "
+				"%d.\n", UVC_GUID_ARGS(info->entity),
+				info->selector, info->index);
+			ret = -EEXIST;
+			goto end;
+		}
+	}
+
+	list_for_each_entry(dev, &uvc_driver.devices, list)
+		uvc_ctrl_add_ctrl(dev, info);
+
+	INIT_LIST_HEAD(&info->mappings);
+	list_add_tail(&info->list, &uvc_driver.controls);
+end:
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+	return ret;
+}
+
+int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
+{
+	struct uvc_control_info *info;
+	struct uvc_control_mapping *map;
+	int ret = -EINVAL;
+
+	if (mapping->id & ~V4L2_CTRL_ID_MASK) {
+		uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
+			"invalid control id 0x%08x\n", mapping->name,
+			mapping->id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&uvc_driver.ctrl_mutex);
+	list_for_each_entry(info, &uvc_driver.controls, list) {
+		if (memcmp(info->entity, mapping->entity, 16) ||
+			info->selector != mapping->selector)
+			continue;
+
+		if (info->size * 8 < mapping->size + mapping->offset) {
+			uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "
+				"overflow control " UVC_GUID_FORMAT "/%u\n",
+				mapping->name, UVC_GUID_ARGS(info->entity),
+				info->selector);
+			ret = -EOVERFLOW;
+			goto end;
+		}
+
+		/* Check if the list contains a mapping matching the new one.
+		 * Bail out if it does.
+		 */
+		list_for_each_entry(map, &info->mappings, list) {
+			if (map->id == mapping->id) {
+				uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is "
+					"already defined.\n", mapping->name);
+				ret = -EEXIST;
+				goto end;
+			}
+		}
+
+		mapping->ctrl = info;
+		list_add_tail(&mapping->list, &info->mappings);
+		uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "
+			UVC_GUID_FORMAT "/%u.\n", mapping->name,
+			UVC_GUID_ARGS(info->entity), info->selector);
+
+		ret = 0;
+		break;
+	}
+end:
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+	return ret;
+}
+
+/*
+ * Initialize device controls.
+ */
+int uvc_ctrl_init_device(struct uvc_device *dev)
+{
+	struct uvc_control_info *info;
+	struct uvc_control *ctrl;
+	struct uvc_entity *entity;
+	unsigned int i;
+
+	/* Walk the entities list and instantiate controls */
+	list_for_each_entry(entity, &dev->entities, list) {
+		unsigned int bControlSize = 0, ncontrols = 0;
+		__u8 *bmControls = NULL;
+
+		if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+			bmControls = entity->extension.bmControls;
+			bControlSize = entity->extension.bControlSize;
+		} else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+			bmControls = entity->processing.bmControls;
+			bControlSize = entity->processing.bControlSize;
+		} else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+			bmControls = entity->camera.bmControls;
+			bControlSize = entity->camera.bControlSize;
+		}
+
+		for (i = 0; i < bControlSize; ++i)
+			ncontrols += hweight8(bmControls[i]);
+
+		if (ncontrols == 0)
+			continue;
+
+		entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);
+		if (entity->controls == NULL)
+			return -ENOMEM;
+
+		entity->ncontrols = ncontrols;
+
+		ctrl = entity->controls;
+		for (i = 0; i < bControlSize * 8; ++i) {
+			if (uvc_get_bit(bmControls, i) == 0)
+				continue;
+
+			ctrl->entity = entity;
+			ctrl->index = i;
+			ctrl++;
+		}
+	}
+
+	/* Walk the controls info list and associate them with the device
+	 * controls, then add the device to the global device list. This has
+	 * to be done while holding the controls lock, to make sure
+	 * uvc_ctrl_add_info() will not get called in-between.
+	 */
+	mutex_lock(&uvc_driver.ctrl_mutex);
+	list_for_each_entry(info, &uvc_driver.controls, list)
+		uvc_ctrl_add_ctrl(dev, info);
+
+	list_add_tail(&dev->list, &uvc_driver.devices);
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+
+	return 0;
+}
+
+/*
+ * Cleanup device controls.
+ */
+void uvc_ctrl_cleanup_device(struct uvc_device *dev)
+{
+	struct uvc_entity *entity;
+	unsigned int i;
+
+	/* Remove the device from the global devices list */
+	mutex_lock(&uvc_driver.ctrl_mutex);
+	if (dev->list.next != NULL)
+		list_del(&dev->list);
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+
+	list_for_each_entry(entity, &dev->entities, list) {
+		for (i = 0; i < entity->ncontrols; ++i)
+			kfree(entity->controls[i].data);
+
+		kfree(entity->controls);
+	}
+}
+
+void uvc_ctrl_init(void)
+{
+	struct uvc_control_info *ctrl = uvc_ctrls;
+	struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);
+	struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
+	struct uvc_control_mapping *mend =
+		mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+	for (; ctrl < cend; ++ctrl)
+		uvc_ctrl_add_info(ctrl);
+
+	for (; mapping < mend; ++mapping)
+		uvc_ctrl_add_mapping(mapping);
+}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
new file mode 100644
index 0000000..60ced58
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -0,0 +1,1955 @@
+/*
+ *      uvc_driver.c  --  USB Video Class driver
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      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 driver aims to support video input devices compliant with the 'USB
+ * Video Class' specification.
+ *
+ * The driver doesn't support the deprecated v4l1 interface. It implements the
+ * mmap capture method only, and doesn't do any image format conversion in
+ * software. If your user-space application doesn't support YUYV or MJPEG, fix
+ * it :-). Please note that the MJPEG data have been stripped from their
+ * Huffman tables (DHT marker), you will need to add it back if your JPEG
+ * codec can't handle MJPEG data.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+#define DRIVER_AUTHOR		"Laurent Pinchart <laurent.pinchart@skynet.be>"
+#define DRIVER_DESC		"USB Video Class driver"
+#ifndef DRIVER_VERSION
+#define DRIVER_VERSION		"v0.1.0"
+#endif
+
+static unsigned int uvc_quirks_param;
+unsigned int uvc_trace_param;
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_format_desc uvc_fmts[] = {
+	{
+		.name		= "YUV 4:2:2 (YUYV)",
+		.guid		= UVC_GUID_FORMAT_YUY2,
+		.fcc		= V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.name		= "YUV 4:2:0 (NV12)",
+		.guid		= UVC_GUID_FORMAT_NV12,
+		.fcc		= V4L2_PIX_FMT_NV12,
+	},
+	{
+		.name		= "MJPEG",
+		.guid		= UVC_GUID_FORMAT_MJPEG,
+		.fcc		= V4L2_PIX_FMT_MJPEG,
+	},
+	{
+		.name		= "YVU 4:2:0 (YV12)",
+		.guid		= UVC_GUID_FORMAT_YV12,
+		.fcc		= V4L2_PIX_FMT_YVU420,
+	},
+	{
+		.name		= "YUV 4:2:0 (I420)",
+		.guid		= UVC_GUID_FORMAT_I420,
+		.fcc		= V4L2_PIX_FMT_YUV420,
+	},
+	{
+		.name		= "YUV 4:2:2 (UYVY)",
+		.guid		= UVC_GUID_FORMAT_UYVY,
+		.fcc		= V4L2_PIX_FMT_UYVY,
+	},
+	{
+		.name		= "Greyscale",
+		.guid		= UVC_GUID_FORMAT_Y800,
+		.fcc		= V4L2_PIX_FMT_GREY,
+	},
+	{
+		.name		= "RGB Bayer",
+		.guid		= UVC_GUID_FORMAT_BY8,
+		.fcc		= V4L2_PIX_FMT_SBGGR8,
+	},
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
+		__u8 epaddr)
+{
+	struct usb_host_endpoint *ep;
+	unsigned int i;
+
+	for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+		ep = &alts->endpoint[i];
+		if (ep->desc.bEndpointAddress == epaddr)
+			return ep;
+	}
+
+	return NULL;
+}
+
+static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
+{
+	unsigned int len = ARRAY_SIZE(uvc_fmts);
+	unsigned int i;
+
+	for (i = 0; i < len; ++i) {
+		if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+			return &uvc_fmts[i];
+	}
+
+	return NULL;
+}
+
+static __u32 uvc_colorspace(const __u8 primaries)
+{
+	static const __u8 colorprimaries[] = {
+		0,
+		V4L2_COLORSPACE_SRGB,
+		V4L2_COLORSPACE_470_SYSTEM_M,
+		V4L2_COLORSPACE_470_SYSTEM_BG,
+		V4L2_COLORSPACE_SMPTE170M,
+		V4L2_COLORSPACE_SMPTE240M,
+	};
+
+	if (primaries < ARRAY_SIZE(colorprimaries))
+		return colorprimaries[primaries];
+
+	return 0;
+}
+
+/* Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+		unsigned int n_terms, unsigned int threshold)
+{
+	uint32_t *an;
+	uint32_t x, y, r;
+	unsigned int i, n;
+
+	an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
+	if (an == NULL)
+		return;
+
+	/* Convert the fraction to a simple continued fraction. See
+	 * http://mathforum.org/dr.math/faq/faq.fractions.html
+	 * Stop if the current term is bigger than or equal to the given
+	 * threshold.
+	 */
+	x = *numerator;
+	y = *denominator;
+
+	for (n = 0; n < n_terms && y != 0; ++n) {
+		an[n] = x / y;
+		if (an[n] >= threshold) {
+			if (n < 2)
+				n++;
+			break;
+		}
+
+		r = x - an[n] * y;
+		x = y;
+		y = r;
+	}
+
+	/* Expand the simple continued fraction back to an integer fraction. */
+	x = 0;
+	y = 1;
+
+	for (i = n; i > 0; --i) {
+		r = y;
+		y = an[i-1] * y + x;
+		x = r;
+	}
+
+	*numerator = y;
+	*denominator = x;
+	kfree(an);
+}
+
+/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
+{
+	uint32_t multiplier;
+
+	/* Saturate the result if the operation would overflow. */
+	if (denominator == 0 ||
+	    numerator/denominator >= ((uint32_t)-1)/10000000)
+		return (uint32_t)-1;
+
+	/* Divide both the denominator and the multiplier by two until
+	 * numerator * multiplier doesn't overflow. If anyone knows a better
+	 * algorithm please let me know.
+	 */
+	multiplier = 10000000;
+	while (numerator > ((uint32_t)-1)/multiplier) {
+		multiplier /= 2;
+		denominator /= 2;
+	}
+
+	return denominator ? numerator * multiplier / denominator : 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+{
+	struct uvc_entity *entity;
+
+	list_for_each_entry(entity, &dev->entities, list) {
+		if (entity->id == id)
+			return entity;
+	}
+
+	return NULL;
+}
+
+static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
+	int id, struct uvc_entity *entity)
+{
+	unsigned int i;
+
+	if (entity == NULL)
+		entity = list_entry(&dev->entities, struct uvc_entity, list);
+
+	list_for_each_entry_continue(entity, &dev->entities, list) {
+		switch (UVC_ENTITY_TYPE(entity)) {
+		case TT_STREAMING:
+			if (entity->output.bSourceID == id)
+				return entity;
+			break;
+
+		case VC_PROCESSING_UNIT:
+			if (entity->processing.bSourceID == id)
+				return entity;
+			break;
+
+		case VC_SELECTOR_UNIT:
+			for (i = 0; i < entity->selector.bNrInPins; ++i)
+				if (entity->selector.baSourceID[i] == id)
+					return entity;
+			break;
+
+		case VC_EXTENSION_UNIT:
+			for (i = 0; i < entity->extension.bNrInPins; ++i)
+				if (entity->extension.baSourceID[i] == id)
+					return entity;
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------
+ * Descriptors handling
+ */
+
+static int uvc_parse_format(struct uvc_device *dev,
+	struct uvc_streaming *streaming, struct uvc_format *format,
+	__u32 **intervals, unsigned char *buffer, int buflen)
+{
+	struct usb_interface *intf = streaming->intf;
+	struct usb_host_interface *alts = intf->cur_altsetting;
+	struct uvc_format_desc *fmtdesc;
+	struct uvc_frame *frame;
+	const unsigned char *start = buffer;
+	unsigned int interval;
+	unsigned int i, n;
+	__u8 ftype;
+
+	format->type = buffer[2];
+	format->index = buffer[3];
+
+	switch (buffer[2]) {
+	case VS_FORMAT_UNCOMPRESSED:
+	case VS_FORMAT_FRAME_BASED:
+		if (buflen < 27) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		/* Find the format descriptor from its GUID. */
+		fmtdesc = uvc_format_by_guid(&buffer[5]);
+
+		if (fmtdesc != NULL) {
+			strncpy(format->name, fmtdesc->name,
+				sizeof format->name);
+			format->fcc = fmtdesc->fcc;
+		} else {
+			uvc_printk(KERN_INFO, "Unknown video format "
+				UVC_GUID_FORMAT "\n",
+				UVC_GUID_ARGS(&buffer[5]));
+			snprintf(format->name, sizeof format->name,
+				UVC_GUID_FORMAT, UVC_GUID_ARGS(&buffer[5]));
+			format->fcc = 0;
+		}
+
+		format->bpp = buffer[21];
+		if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
+			ftype = VS_FRAME_UNCOMPRESSED;
+		} else {
+			ftype = VS_FRAME_FRAME_BASED;
+			if (buffer[27])
+				format->flags = UVC_FMT_FLAG_COMPRESSED;
+		}
+		break;
+
+	case VS_FORMAT_MJPEG:
+		if (buflen < 11) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		strncpy(format->name, "MJPEG", sizeof format->name);
+		format->fcc = V4L2_PIX_FMT_MJPEG;
+		format->flags = UVC_FMT_FLAG_COMPRESSED;
+		format->bpp = 0;
+		ftype = VS_FRAME_MJPEG;
+		break;
+
+	case VS_FORMAT_DV:
+		if (buflen < 9) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		switch (buffer[8] & 0x7f) {
+		case 0:
+			strncpy(format->name, "SD-DV", sizeof format->name);
+			break;
+		case 1:
+			strncpy(format->name, "SDL-DV", sizeof format->name);
+			break;
+		case 2:
+			strncpy(format->name, "HD-DV", sizeof format->name);
+			break;
+		default:
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d: unknown DV format %u\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber, buffer[8]);
+			return -EINVAL;
+		}
+
+		strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+			sizeof format->name);
+
+		format->fcc = V4L2_PIX_FMT_DV;
+		format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
+		format->bpp = 0;
+		ftype = 0;
+
+		/* Create a dummy frame descriptor. */
+		frame = &format->frame[0];
+		memset(&format->frame[0], 0, sizeof format->frame[0]);
+		frame->bFrameIntervalType = 1;
+		frame->dwDefaultFrameInterval = 1;
+		frame->dwFrameInterval = *intervals;
+		*(*intervals)++ = 1;
+		format->nframes = 1;
+		break;
+
+	case VS_FORMAT_MPEG2TS:
+	case VS_FORMAT_STREAM_BASED:
+		/* Not supported yet. */
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+		       "interface %d unsupported format %u\n",
+		       dev->udev->devnum, alts->desc.bInterfaceNumber,
+		       buffer[2]);
+		return -EINVAL;
+	}
+
+	uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
+
+	buflen -= buffer[0];
+	buffer += buffer[0];
+
+	/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+	 * based formats have frame descriptors.
+	 */
+	while (buflen > 2 && buffer[2] == ftype) {
+		frame = &format->frame[format->nframes];
+
+		if (ftype != VS_FRAME_FRAME_BASED)
+			n = buflen > 25 ? buffer[25] : 0;
+		else
+			n = buflen > 21 ? buffer[21] : 0;
+
+		n = n ? n : 3;
+
+		if (buflen < 26 + 4*n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FRAME error\n", dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		frame->bFrameIndex = buffer[3];
+		frame->bmCapabilities = buffer[4];
+		frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]);
+		frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]);
+		frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]);
+		frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]);
+		if (ftype != VS_FRAME_FRAME_BASED) {
+			frame->dwMaxVideoFrameBufferSize =
+				le32_to_cpup((__le32 *)&buffer[17]);
+			frame->dwDefaultFrameInterval =
+				le32_to_cpup((__le32 *)&buffer[21]);
+			frame->bFrameIntervalType = buffer[25];
+		} else {
+			frame->dwMaxVideoFrameBufferSize = 0;
+			frame->dwDefaultFrameInterval =
+				le32_to_cpup((__le32 *)&buffer[17]);
+			frame->bFrameIntervalType = buffer[21];
+		}
+		frame->dwFrameInterval = *intervals;
+
+		/* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
+		 * completely. Observed behaviours range from setting the
+		 * value to 1.1x the actual frame size of hardwiring the
+		 * 16 low bits to 0. This results in a higher than necessary
+		 * memory usage as well as a wrong image size information. For
+		 * uncompressed formats this can be fixed by computing the
+		 * value from the frame size.
+		 */
+		if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
+			frame->dwMaxVideoFrameBufferSize = format->bpp
+				* frame->wWidth * frame->wHeight / 8;
+
+		/* Some bogus devices report dwMinFrameInterval equal to
+		 * dwMaxFrameInterval and have dwFrameIntervalStep set to
+		 * zero. Setting all null intervals to 1 fixes the problem and
+		 * some other divisions by zero which could happen.
+		 */
+		for (i = 0; i < n; ++i) {
+			interval = le32_to_cpup((__le32 *)&buffer[26+4*i]);
+			*(*intervals)++ = interval ? interval : 1;
+		}
+
+		/* Make sure that the default frame interval stays between
+		 * the boundaries.
+		 */
+		n -= frame->bFrameIntervalType ? 1 : 2;
+		frame->dwDefaultFrameInterval =
+			min(frame->dwFrameInterval[n],
+			    max(frame->dwFrameInterval[0],
+				frame->dwDefaultFrameInterval));
+
+		uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
+			frame->wWidth, frame->wHeight,
+			10000000/frame->dwDefaultFrameInterval,
+			(100000000/frame->dwDefaultFrameInterval)%10);
+
+		format->nframes++;
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+		if (buflen < 6) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d COLORFORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		format->colorspace = uvc_colorspace(buffer[3]);
+
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	return buffer - start;
+}
+
+static int uvc_parse_streaming(struct uvc_device *dev,
+	struct usb_interface *intf)
+{
+	struct uvc_streaming *streaming = NULL;
+	struct uvc_format *format;
+	struct uvc_frame *frame;
+	struct usb_host_interface *alts = &intf->altsetting[0];
+	unsigned char *_buffer, *buffer = alts->extra;
+	int _buflen, buflen = alts->extralen;
+	unsigned int nformats = 0, nframes = 0, nintervals = 0;
+	unsigned int size, i, n, p;
+	__u32 *interval;
+	__u16 psize;
+	int ret = -EINVAL;
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass
+		!= SC_VIDEOSTREAMING) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
+			"video streaming interface\n", dev->udev->devnum,
+			intf->altsetting[0].desc.bInterfaceNumber);
+		return -EINVAL;
+	}
+
+	if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
+			"claimed\n", dev->udev->devnum,
+			intf->altsetting[0].desc.bInterfaceNumber);
+		return -EINVAL;
+	}
+
+	streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
+	if (streaming == NULL) {
+		usb_driver_release_interface(&uvc_driver.driver, intf);
+		return -EINVAL;
+	}
+
+	mutex_init(&streaming->mutex);
+	streaming->intf = usb_get_intf(intf);
+	streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	/* The Pico iMage webcam has its class-specific interface descriptors
+	 * after the endpoint descriptors.
+	 */
+	if (buflen == 0) {
+		for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+			struct usb_host_endpoint *ep = &alts->endpoint[i];
+
+			if (ep->extralen == 0)
+				continue;
+
+			if (ep->extralen > 2 &&
+			    ep->extra[1] == USB_DT_CS_INTERFACE) {
+				uvc_trace(UVC_TRACE_DESCR, "trying extra data "
+					"from endpoint %u.\n", i);
+				buffer = alts->endpoint[i].extra;
+				buflen = alts->endpoint[i].extralen;
+				break;
+			}
+		}
+	}
+
+	/* Skip the standard interface descriptors. */
+	while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	if (buflen <= 2) {
+		uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
+			"interface descriptors found.\n");
+		goto error;
+	}
+
+	/* Parse the header descriptor. */
+	if (buffer[2] == VS_OUTPUT_HEADER) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d OUTPUT HEADER descriptor is not supported.\n",
+			dev->udev->devnum, alts->desc.bInterfaceNumber);
+		goto error;
+	} else if (buffer[2] == VS_INPUT_HEADER) {
+		p = buflen >= 5 ? buffer[3] : 0;
+		n = buflen >= 12 ? buffer[12] : 0;
+
+		if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+				"interface %d INPUT HEADER descriptor is "
+				"invalid.\n", dev->udev->devnum,
+				alts->desc.bInterfaceNumber);
+			goto error;
+		}
+
+		streaming->header.bNumFormats = p;
+		streaming->header.bEndpointAddress = buffer[6];
+		streaming->header.bmInfo = buffer[7];
+		streaming->header.bTerminalLink = buffer[8];
+		streaming->header.bStillCaptureMethod = buffer[9];
+		streaming->header.bTriggerSupport = buffer[10];
+		streaming->header.bTriggerUsage = buffer[11];
+		streaming->header.bControlSize = n;
+
+		streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+		if (streaming->header.bmaControls == NULL) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		memcpy(streaming->header.bmaControls, &buffer[13], p*n);
+	} else {
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d HEADER descriptor not found.\n", dev->udev->devnum,
+			alts->desc.bInterfaceNumber);
+		goto error;
+	}
+
+	buflen -= buffer[0];
+	buffer += buffer[0];
+
+	_buffer = buffer;
+	_buflen = buflen;
+
+	/* Count the format and frame descriptors. */
+	while (_buflen > 2) {
+		switch (_buffer[2]) {
+		case VS_FORMAT_UNCOMPRESSED:
+		case VS_FORMAT_MJPEG:
+		case VS_FORMAT_FRAME_BASED:
+			nformats++;
+			break;
+
+		case VS_FORMAT_DV:
+			/* DV format has no frame descriptor. We will create a
+			 * dummy frame descriptor with a dummy frame interval.
+			 */
+			nformats++;
+			nframes++;
+			nintervals++;
+			break;
+
+		case VS_FORMAT_MPEG2TS:
+		case VS_FORMAT_STREAM_BASED:
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+				"interface %d FORMAT %u is not supported.\n",
+				dev->udev->devnum,
+				alts->desc.bInterfaceNumber, _buffer[2]);
+			break;
+
+		case VS_FRAME_UNCOMPRESSED:
+		case VS_FRAME_MJPEG:
+			nframes++;
+			if (_buflen > 25)
+				nintervals += _buffer[25] ? _buffer[25] : 3;
+			break;
+
+		case VS_FRAME_FRAME_BASED:
+			nframes++;
+			if (_buflen > 21)
+				nintervals += _buffer[21] ? _buffer[21] : 3;
+			break;
+		}
+
+		_buflen -= _buffer[0];
+		_buffer += _buffer[0];
+	}
+
+	if (nformats == 0) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d has no supported formats defined.\n",
+			dev->udev->devnum, alts->desc.bInterfaceNumber);
+		goto error;
+	}
+
+	size = nformats * sizeof *format + nframes * sizeof *frame
+	     + nintervals * sizeof *interval;
+	format = kzalloc(size, GFP_KERNEL);
+	if (format == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	frame = (struct uvc_frame *)&format[nformats];
+	interval = (__u32 *)&frame[nframes];
+
+	streaming->format = format;
+	streaming->nformats = nformats;
+
+	/* Parse the format descriptors. */
+	while (buflen > 2) {
+		switch (buffer[2]) {
+		case VS_FORMAT_UNCOMPRESSED:
+		case VS_FORMAT_MJPEG:
+		case VS_FORMAT_DV:
+		case VS_FORMAT_FRAME_BASED:
+			format->frame = frame;
+			ret = uvc_parse_format(dev, streaming, format,
+				&interval, buffer, buflen);
+			if (ret < 0)
+				goto error;
+
+			frame += format->nframes;
+			format++;
+
+			buflen -= ret;
+			buffer += ret;
+			continue;
+
+		default:
+			break;
+		}
+
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	/* Parse the alternate settings to find the maximum bandwidth. */
+	for (i = 0; i < intf->num_altsetting; ++i) {
+		struct usb_host_endpoint *ep;
+		alts = &intf->altsetting[i];
+		ep = uvc_find_endpoint(alts,
+				streaming->header.bEndpointAddress);
+		if (ep == NULL)
+			continue;
+
+		psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+		if (psize > streaming->maxpsize)
+			streaming->maxpsize = psize;
+	}
+
+	list_add_tail(&streaming->list, &dev->streaming);
+	return 0;
+
+error:
+	usb_driver_release_interface(&uvc_driver.driver, intf);
+	usb_put_intf(intf);
+	kfree(streaming->format);
+	kfree(streaming->header.bmaControls);
+	kfree(streaming);
+	return ret;
+}
+
+/* Parse vendor-specific extensions. */
+static int uvc_parse_vendor_control(struct uvc_device *dev,
+	const unsigned char *buffer, int buflen)
+{
+	struct usb_device *udev = dev->udev;
+	struct usb_host_interface *alts = dev->intf->cur_altsetting;
+	struct uvc_entity *unit;
+	unsigned int n, p;
+	int handled = 0;
+
+	switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
+	case 0x046d:		/* Logitech */
+		if (buffer[1] != 0x41 || buffer[2] != 0x01)
+			break;
+
+		/* Logitech implements several vendor specific functions
+		 * through vendor specific extension units (LXU).
+		 *
+		 * The LXU descriptors are similar to XU descriptors
+		 * (see "USB Device Video Class for Video Devices", section
+		 * 3.7.2.6 "Extension Unit Descriptor") with the following
+		 * differences:
+		 *
+		 * ----------------------------------------------------------
+		 * 0		bLength		1	 Number
+		 *	Size of this descriptor, in bytes: 24+p+n*2
+		 * ----------------------------------------------------------
+		 * 23+p+n	bmControlsType	N	Bitmap
+		 * 	Individual bits in the set are defined:
+		 * 	0: Absolute
+		 * 	1: Relative
+		 *
+		 * 	This bitset is mapped exactly the same as bmControls.
+		 * ----------------------------------------------------------
+		 * 23+p+n*2	bReserved	1	Boolean
+		 * ----------------------------------------------------------
+		 * 24+p+n*2	iExtension	1	Index
+		 *	Index of a string descriptor that describes this
+		 *	extension unit.
+		 * ----------------------------------------------------------
+		 */
+		p = buflen >= 22 ? buffer[21] : 0;
+		n = buflen >= 25 + p ? buffer[22+p] : 0;
+
+		if (buflen < 25 + p + 2*n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d EXTENSION_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			break;
+		}
+
+		unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = VC_EXTENSION_UNIT;
+		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+		unit->extension.bNumControls = buffer[20];
+		unit->extension.bNrInPins =
+			le16_to_cpup((__le16 *)&buffer[21]);
+		unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->extension.baSourceID, &buffer[22], p);
+		unit->extension.bControlSize = buffer[22+p];
+		unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+		unit->extension.bmControlsType = (__u8 *)unit + sizeof *unit
+					       + p + n;
+		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
+
+		if (buffer[24+p+2*n] != 0)
+			usb_string(udev, buffer[24+p+2*n], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Extension %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		handled = 1;
+		break;
+	}
+
+	return handled;
+}
+
+static int uvc_parse_standard_control(struct uvc_device *dev,
+	const unsigned char *buffer, int buflen)
+{
+	struct usb_device *udev = dev->udev;
+	struct uvc_entity *unit, *term;
+	struct usb_interface *intf;
+	struct usb_host_interface *alts = dev->intf->cur_altsetting;
+	unsigned int i, n, p, len;
+	__u16 type;
+
+	switch (buffer[2]) {
+	case VC_HEADER:
+		n = buflen >= 12 ? buffer[11] : 0;
+
+		if (buflen < 12 || buflen < 12 + n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d HEADER error\n", udev->devnum,
+				alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]);
+		dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]);
+
+		/* Parse all USB Video Streaming interfaces. */
+		for (i = 0; i < n; ++i) {
+			intf = usb_ifnum_to_if(udev, buffer[12+i]);
+			if (intf == NULL) {
+				uvc_trace(UVC_TRACE_DESCR, "device %d "
+					"interface %d doesn't exists\n",
+					udev->devnum, i);
+				continue;
+			}
+
+			uvc_parse_streaming(dev, intf);
+		}
+		break;
+
+	case VC_INPUT_TERMINAL:
+		if (buflen < 8) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d INPUT_TERMINAL error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		/* Make sure the terminal type MSB is not null, otherwise it
+		 * could be confused with a unit.
+		 */
+		type = le16_to_cpup((__le16 *)&buffer[4]);
+		if ((type & 0xff00) == 0) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d INPUT_TERMINAL %d has invalid "
+				"type 0x%04x, skipping\n", udev->devnum,
+				alts->desc.bInterfaceNumber,
+				buffer[3], type);
+			return 0;
+		}
+
+		n = 0;
+		p = 0;
+		len = 8;
+
+		if (type == ITT_CAMERA) {
+			n = buflen >= 15 ? buffer[14] : 0;
+			len = 15;
+
+		} else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+			n = buflen >= 9 ? buffer[8] : 0;
+			p = buflen >= 10 + n ? buffer[9+n] : 0;
+			len = 10;
+		}
+
+		if (buflen < len + n + p) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d INPUT_TERMINAL error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		term = kzalloc(sizeof *term + n + p, GFP_KERNEL);
+		if (term == NULL)
+			return -ENOMEM;
+
+		term->id = buffer[3];
+		term->type = type | UVC_TERM_INPUT;
+
+		if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+			term->camera.bControlSize = n;
+			term->camera.bmControls = (__u8 *)term + sizeof *term;
+			term->camera.wObjectiveFocalLengthMin =
+				le16_to_cpup((__le16 *)&buffer[8]);
+			term->camera.wObjectiveFocalLengthMax =
+				le16_to_cpup((__le16 *)&buffer[10]);
+			term->camera.wOcularFocalLength =
+				le16_to_cpup((__le16 *)&buffer[12]);
+			memcpy(term->camera.bmControls, &buffer[15], n);
+		} else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+			term->media.bControlSize = n;
+			term->media.bmControls = (__u8 *)term + sizeof *term;
+			term->media.bTransportModeSize = p;
+			term->media.bmTransportModes = (__u8 *)term
+						     + sizeof *term + n;
+			memcpy(term->media.bmControls, &buffer[9], n);
+			memcpy(term->media.bmTransportModes, &buffer[10+n], p);
+		}
+
+		if (buffer[7] != 0)
+			usb_string(udev, buffer[7], term->name,
+				   sizeof term->name);
+		else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+			sprintf(term->name, "Camera %u", buffer[3]);
+		else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+			sprintf(term->name, "Media %u", buffer[3]);
+		else
+			sprintf(term->name, "Input %u", buffer[3]);
+
+		list_add_tail(&term->list, &dev->entities);
+		break;
+
+	case VC_OUTPUT_TERMINAL:
+		if (buflen < 9) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d OUTPUT_TERMINAL error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		/* Make sure the terminal type MSB is not null, otherwise it
+		 * could be confused with a unit.
+		 */
+		type = le16_to_cpup((__le16 *)&buffer[4]);
+		if ((type & 0xff00) == 0) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d OUTPUT_TERMINAL %d has invalid "
+				"type 0x%04x, skipping\n", udev->devnum,
+				alts->desc.bInterfaceNumber, buffer[3], type);
+			return 0;
+		}
+
+		term = kzalloc(sizeof *term, GFP_KERNEL);
+		if (term == NULL)
+			return -ENOMEM;
+
+		term->id = buffer[3];
+		term->type = type | UVC_TERM_OUTPUT;
+		term->output.bSourceID = buffer[7];
+
+		if (buffer[8] != 0)
+			usb_string(udev, buffer[8], term->name,
+				   sizeof term->name);
+		else
+			sprintf(term->name, "Output %u", buffer[3]);
+
+		list_add_tail(&term->list, &dev->entities);
+		break;
+
+	case VC_SELECTOR_UNIT:
+		p = buflen >= 5 ? buffer[4] : 0;
+
+		if (buflen < 5 || buflen < 6 + p) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d SELECTOR_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		unit = kzalloc(sizeof *unit + p, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = buffer[2];
+		unit->selector.bNrInPins = buffer[4];
+		unit->selector.baSourceID = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->selector.baSourceID, &buffer[5], p);
+
+		if (buffer[5+p] != 0)
+			usb_string(udev, buffer[5+p], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Selector %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		break;
+
+	case VC_PROCESSING_UNIT:
+		n = buflen >= 8 ? buffer[7] : 0;
+		p = dev->uvc_version >= 0x0110 ? 10 : 9;
+
+		if (buflen < p + n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d PROCESSING_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		unit = kzalloc(sizeof *unit + n, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = buffer[2];
+		unit->processing.bSourceID = buffer[4];
+		unit->processing.wMaxMultiplier =
+			le16_to_cpup((__le16 *)&buffer[5]);
+		unit->processing.bControlSize = buffer[7];
+		unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->processing.bmControls, &buffer[8], n);
+		if (dev->uvc_version >= 0x0110)
+			unit->processing.bmVideoStandards = buffer[9+n];
+
+		if (buffer[8+n] != 0)
+			usb_string(udev, buffer[8+n], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Processing %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		break;
+
+	case VC_EXTENSION_UNIT:
+		p = buflen >= 22 ? buffer[21] : 0;
+		n = buflen >= 24 + p ? buffer[22+p] : 0;
+
+		if (buflen < 24 + p + n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d EXTENSION_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = buffer[2];
+		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+		unit->extension.bNumControls = buffer[20];
+		unit->extension.bNrInPins =
+			le16_to_cpup((__le16 *)&buffer[21]);
+		unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->extension.baSourceID, &buffer[22], p);
+		unit->extension.bControlSize = buffer[22+p];
+		unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+		memcpy(unit->extension.bmControls, &buffer[23+p], n);
+
+		if (buffer[23+p+n] != 0)
+			usb_string(udev, buffer[23+p+n], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Extension %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		break;
+
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
+			"descriptor (%u)\n", buffer[2]);
+		break;
+	}
+
+	return 0;
+}
+
+static int uvc_parse_control(struct uvc_device *dev)
+{
+	struct usb_host_interface *alts = dev->intf->cur_altsetting;
+	unsigned char *buffer = alts->extra;
+	int buflen = alts->extralen;
+	int ret;
+
+	/* Parse the default alternate setting only, as the UVC specification
+	 * defines a single alternate setting, the default alternate setting
+	 * zero.
+	 */
+
+	while (buflen > 2) {
+		if (uvc_parse_vendor_control(dev, buffer, buflen) ||
+		    buffer[1] != USB_DT_CS_INTERFACE)
+			goto next_descriptor;
+
+		if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
+			return ret;
+
+next_descriptor:
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	/* Check if the optional status endpoint is present. */
+	if (alts->desc.bNumEndpoints == 1) {
+		struct usb_host_endpoint *ep = &alts->endpoint[0];
+		struct usb_endpoint_descriptor *desc = &ep->desc;
+
+		if (usb_endpoint_is_int_in(desc) &&
+		    le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
+		    desc->bInterval != 0) {
+			uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
+				"(addr %02x).\n", desc->bEndpointAddress);
+			dev->int_ep = ep;
+		}
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe and disconnect
+ */
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+	if (dev->video.vdev) {
+		if (dev->video.vdev->minor == -1)
+			video_device_release(dev->video.vdev);
+		else
+			video_unregister_device(dev->video.vdev);
+		dev->video.vdev = NULL;
+	}
+}
+
+/*
+ * Scan the UVC descriptors to locate a chain starting at an Output Terminal
+ * and containing the following units:
+ *
+ * - a USB Streaming Output Terminal
+ * - zero or one Processing Unit
+ * - zero, one or mode single-input Selector Units
+ * - zero or one multiple-input Selector Units, provided all inputs are
+ *   connected to input terminals
+ * - zero, one or mode single-input Extension Units
+ * - one Camera Input Terminal, or one or more External terminals.
+ *
+ * A side forward scan is made on each detected entity to check for additional
+ * extension units.
+ */
+static int uvc_scan_chain_entity(struct uvc_video_device *video,
+	struct uvc_entity *entity)
+{
+	switch (UVC_ENTITY_TYPE(entity)) {
+	case VC_EXTENSION_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- XU %d", entity->id);
+
+		if (entity->extension.bNrInPins != 1) {
+			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
+				"than 1 input pin.\n", entity->id);
+			return -1;
+		}
+
+		list_add_tail(&entity->chain, &video->extensions);
+		break;
+
+	case VC_PROCESSING_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- PU %d", entity->id);
+
+		if (video->processing != NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found multiple "
+				"Processing Units in chain.\n");
+			return -1;
+		}
+
+		video->processing = entity;
+		break;
+
+	case VC_SELECTOR_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- SU %d", entity->id);
+
+		/* Single-input selector units are ignored. */
+		if (entity->selector.bNrInPins == 1)
+			break;
+
+		if (video->selector != NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
+				"Units in chain.\n");
+			return -1;
+		}
+
+		video->selector = entity;
+		break;
+
+	case ITT_VENDOR_SPECIFIC:
+	case ITT_CAMERA:
+	case ITT_MEDIA_TRANSPORT_INPUT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- IT %d\n", entity->id);
+
+		list_add_tail(&entity->chain, &video->iterms);
+		break;
+
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
+			"0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int uvc_scan_chain_forward(struct uvc_video_device *video,
+	struct uvc_entity *entity, struct uvc_entity *prev)
+{
+	struct uvc_entity *forward;
+	int found;
+
+	/* Forward scan */
+	forward = NULL;
+	found = 0;
+
+	while (1) {
+		forward = uvc_entity_by_reference(video->dev, entity->id,
+			forward);
+		if (forward == NULL)
+			break;
+
+		if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
+		    forward == prev)
+			continue;
+
+		if (forward->extension.bNrInPins != 1) {
+			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+				"more than 1 input pin.\n", entity->id);
+			return -1;
+		}
+
+		list_add_tail(&forward->chain, &video->extensions);
+		if (uvc_trace_param & UVC_TRACE_PROBE) {
+			if (!found)
+				printk(" (-> XU");
+
+			printk(" %d", forward->id);
+			found = 1;
+		}
+	}
+	if (found)
+		printk(")");
+
+	return 0;
+}
+
+static int uvc_scan_chain_backward(struct uvc_video_device *video,
+	struct uvc_entity *entity)
+{
+	struct uvc_entity *term;
+	int id = -1, i;
+
+	switch (UVC_ENTITY_TYPE(entity)) {
+	case VC_EXTENSION_UNIT:
+		id = entity->extension.baSourceID[0];
+		break;
+
+	case VC_PROCESSING_UNIT:
+		id = entity->processing.bSourceID;
+		break;
+
+	case VC_SELECTOR_UNIT:
+		/* Single-input selector units are ignored. */
+		if (entity->selector.bNrInPins == 1) {
+			id = entity->selector.baSourceID[0];
+			break;
+		}
+
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- IT");
+
+		video->selector = entity;
+		for (i = 0; i < entity->selector.bNrInPins; ++i) {
+			id = entity->selector.baSourceID[i];
+			term = uvc_entity_by_id(video->dev, id);
+			if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
+				uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
+					"input %d isn't connected to an "
+					"input terminal\n", entity->id, i);
+				return -1;
+			}
+
+			if (uvc_trace_param & UVC_TRACE_PROBE)
+				printk(" %d", term->id);
+
+			list_add_tail(&term->chain, &video->iterms);
+			uvc_scan_chain_forward(video, term, entity);
+		}
+
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk("\n");
+
+		id = 0;
+		break;
+	}
+
+	return id;
+}
+
+static int uvc_scan_chain(struct uvc_video_device *video)
+{
+	struct uvc_entity *entity, *prev;
+	int id;
+
+	entity = video->oterm;
+	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+	id = entity->output.bSourceID;
+	while (id != 0) {
+		prev = entity;
+		entity = uvc_entity_by_id(video->dev, id);
+		if (entity == NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+				"unknown entity %d.\n", id);
+			return -1;
+		}
+
+		/* Process entity */
+		if (uvc_scan_chain_entity(video, entity) < 0)
+			return -1;
+
+		/* Forward scan */
+		if (uvc_scan_chain_forward(video, entity, prev) < 0)
+			return -1;
+
+		/* Stop when a terminal is found. */
+		if (!UVC_ENTITY_IS_UNIT(entity))
+			break;
+
+		/* Backward scan */
+		id = uvc_scan_chain_backward(video, entity);
+		if (id < 0)
+			return id;
+	}
+
+	/* Initialize the video buffers queue. */
+	uvc_queue_init(&video->queue);
+
+	return 0;
+}
+
+/*
+ * Register the video devices.
+ *
+ * The driver currently supports a single video device per control interface
+ * only. The terminal and units must match the following structure:
+ *
+ * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ *
+ * The Extension Units, if present, must have a single input pin. The
+ * Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported.
+ */
+static int uvc_register_video(struct uvc_device *dev)
+{
+	struct video_device *vdev;
+	struct uvc_entity *term;
+	int found = 0, ret;
+
+	/* Check if the control interface matches the structure we expect. */
+	list_for_each_entry(term, &dev->entities, list) {
+		struct uvc_streaming *streaming;
+
+		if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+			continue;
+
+		memset(&dev->video, 0, sizeof dev->video);
+		mutex_init(&dev->video.ctrl_mutex);
+		INIT_LIST_HEAD(&dev->video.iterms);
+		INIT_LIST_HEAD(&dev->video.extensions);
+		dev->video.oterm = term;
+		dev->video.dev = dev;
+		if (uvc_scan_chain(&dev->video) < 0)
+			continue;
+
+		list_for_each_entry(streaming, &dev->streaming, list) {
+			if (streaming->header.bTerminalLink == term->id) {
+				dev->video.streaming = streaming;
+				found = 1;
+				break;
+			}
+		}
+
+		if (found)
+			break;
+	}
+
+	if (!found) {
+		uvc_printk(KERN_INFO, "No valid video chain found.\n");
+		return -1;
+	}
+
+	if (uvc_trace_param & UVC_TRACE_PROBE) {
+		uvc_printk(KERN_INFO, "Found a valid video chain (");
+		list_for_each_entry(term, &dev->video.iterms, chain) {
+			printk("%d", term->id);
+			if (term->chain.next != &dev->video.iterms)
+				printk(",");
+		}
+		printk(" -> %d).\n", dev->video.oterm->id);
+	}
+
+	/* Initialize the streaming interface with default streaming
+	 * parameters.
+	 */
+	if ((ret = uvc_video_init(&dev->video)) < 0) {
+		uvc_printk(KERN_ERR, "Failed to initialize the device "
+			"(%d).\n", ret);
+		return ret;
+	}
+
+	/* Register the device with V4L. */
+	vdev = video_device_alloc();
+	if (vdev == NULL)
+		return -1;
+
+	/* We already hold a reference to dev->udev. The video device will be
+	 * unregistered before the reference is released, so we don't need to
+	 * get another one.
+	 */
+	vdev->dev = &dev->intf->dev;
+	vdev->type = 0;
+	vdev->type2 = 0;
+	vdev->minor = -1;
+	vdev->fops = &uvc_fops;
+	vdev->release = video_device_release;
+	strncpy(vdev->name, dev->name, sizeof vdev->name);
+
+	/* Set the driver data before calling video_register_device, otherwise
+	 * uvc_v4l2_open might race us.
+	 *
+	 * FIXME: usb_set_intfdata hasn't been called so far. Is that a
+	 * 	  problem ? Does any function which could be called here get
+	 * 	  a pointer to the usb_interface ?
+	 */
+	dev->video.vdev = vdev;
+	video_set_drvdata(vdev, &dev->video);
+
+	if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
+		dev->video.vdev = NULL;
+		video_device_release(vdev);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Delete the UVC device.
+ *
+ * Called by the kernel when the last reference to the uvc_device structure
+ * is released.
+ *
+ * Unregistering the video devices is done here because every opened instance
+ * must be closed before the device can be unregistered. An alternative would
+ * have been to use another reference count for uvc_v4l2_open/uvc_release, and
+ * unregister the video devices on disconnect when that reference count drops
+ * to zero.
+ *
+ * As this function is called after or during disconnect(), all URBs have
+ * already been canceled by the USB core. There is no need to kill the
+ * interrupt URB manually.
+ */
+void uvc_delete(struct kref *kref)
+{
+	struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
+	struct list_head *p, *n;
+
+	/* Unregister the video device */
+	uvc_unregister_video(dev);
+	usb_put_intf(dev->intf);
+	usb_put_dev(dev->udev);
+
+	uvc_status_cleanup(dev);
+	uvc_ctrl_cleanup_device(dev);
+
+	list_for_each_safe(p, n, &dev->entities) {
+		struct uvc_entity *entity;
+		entity = list_entry(p, struct uvc_entity, list);
+		kfree(entity);
+	}
+
+	list_for_each_safe(p, n, &dev->streaming) {
+		struct uvc_streaming *streaming;
+		streaming = list_entry(p, struct uvc_streaming, list);
+		usb_driver_release_interface(&uvc_driver.driver,
+			streaming->intf);
+		usb_put_intf(streaming->intf);
+		kfree(streaming->format);
+		kfree(streaming->header.bmaControls);
+		kfree(streaming);
+	}
+
+	kfree(dev);
+}
+
+static int uvc_probe(struct usb_interface *intf,
+		     const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct uvc_device *dev;
+	int ret;
+
+	if (id->idVendor && id->idProduct)
+		uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
+				"(%04x:%04x)\n", udev->devpath, id->idVendor,
+				id->idProduct);
+	else
+		uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
+				udev->devpath);
+
+	/* Allocate memory for the device and initialize it */
+	if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev->entities);
+	INIT_LIST_HEAD(&dev->streaming);
+	kref_init(&dev->kref);
+
+	dev->udev = usb_get_dev(udev);
+	dev->intf = usb_get_intf(intf);
+	dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	dev->quirks = id->driver_info | uvc_quirks_param;
+
+	if (udev->product != NULL)
+		strncpy(dev->name, udev->product, sizeof dev->name);
+	else
+		snprintf(dev->name, sizeof dev->name,
+			"UVC Camera (%04x:%04x)",
+			le16_to_cpu(udev->descriptor.idVendor),
+			le16_to_cpu(udev->descriptor.idProduct));
+
+	/* Parse the Video Class control descriptor */
+	if (uvc_parse_control(dev) < 0) {
+		uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
+			"descriptors.\n");
+		goto error;
+	}
+
+	uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n",
+		dev->uvc_version >> 8, dev->uvc_version & 0xff,
+		udev->product ? udev->product : "<unnamed>",
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct));
+
+	if (uvc_quirks_param != 0) {
+		uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
+			"parameter for testing purpose.\n", uvc_quirks_param);
+		uvc_printk(KERN_INFO, "Please report required quirks to the "
+			"linux-uvc-devel mailing list.\n");
+	}
+
+	/* Initialize controls */
+	if (uvc_ctrl_init_device(dev) < 0)
+		goto error;
+
+	/* Register the video devices */
+	if (uvc_register_video(dev) < 0)
+		goto error;
+
+	/* Save our data pointer in the interface data */
+	usb_set_intfdata(intf, dev);
+
+	/* Initialize the interrupt URB */
+	if ((ret = uvc_status_init(dev)) < 0) {
+		uvc_printk(KERN_INFO, "Unable to initialize the status "
+			"endpoint (%d), status interrupt will not be "
+			"supported.\n", ret);
+	}
+
+	uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+	return 0;
+
+error:
+	kref_put(&dev->kref, uvc_delete);
+	return -ENODEV;
+}
+
+static void uvc_disconnect(struct usb_interface *intf)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+
+	/* Set the USB interface data to NULL. This can be done outside the
+	 * lock, as there's no other reader.
+	 */
+	usb_set_intfdata(intf, NULL);
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+		return;
+
+	/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
+	 * lock is needed to prevent uvc_disconnect from releasing its
+	 * reference to the uvc_device instance after uvc_v4l2_open() received
+	 * the pointer to the device (video_devdata) but before it got the
+	 * chance to increase the reference count (kref_get).
+	 */
+	mutex_lock(&uvc_driver.open_mutex);
+
+	dev->state |= UVC_DEV_DISCONNECTED;
+	kref_put(&dev->kref, uvc_delete);
+
+	mutex_unlock(&uvc_driver.open_mutex);
+}
+
+static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	/* Controls are cached on the fly so they don't need to be saved. */
+	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+		return uvc_status_suspend(dev);
+
+	if (dev->video.streaming->intf != intf) {
+		uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "
+				"interface mismatch.\n");
+		return -EINVAL;
+	}
+
+	return uvc_video_suspend(&dev->video);
+}
+
+static int uvc_resume(struct usb_interface *intf)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+	int ret;
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+		if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+			return ret;
+
+		return uvc_status_resume(dev);
+	}
+
+	if (dev->video.streaming->intf != intf) {
+		uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "
+				"interface mismatch.\n");
+		return -EINVAL;
+	}
+
+	return uvc_video_resume(&dev->video);
+}
+
+/* ------------------------------------------------------------------------
+ * Driver initialization and cleanup
+ */
+
+/*
+ * The Logitech cameras listed below have their interface class set to
+ * VENDOR_SPEC because they don't announce themselves as UVC devices, even
+ * though they are compliant.
+ */
+static struct usb_device_id uvc_ids[] = {
+	/* ALi M5606 (Clevo M540SR) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0402,
+	  .idProduct		= 0x5606,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Creative Live! Optia */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x041e,
+	  .idProduct		= 0x4057,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Microsoft Lifecam NX-6000 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x045e,
+	  .idProduct		= 0x00f8,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Microsoft Lifecam VX-7000 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x045e,
+	  .idProduct		= 0x0723,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Logitech Quickcam Fusion */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c1,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam Orbit MP */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c2,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam Pro for Notebook */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c3,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam Pro 5000 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c5,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam OEM Dell Notebook */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c6,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam OEM Cisco VT Camera II */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c7,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Apple Built-In iSight */
+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x05ac,
+	  .idProduct		= 0x8501,
+	  .bInterfaceClass      = USB_CLASS_VIDEO,
+	  .bInterfaceSubClass   = 1,
+	  .bInterfaceProtocol   = 0,
+	  .driver_info 		= UVC_QUIRK_PROBE_MINMAX
+				| UVC_QUIRK_BUILTIN_ISIGHT },
+	/* Genesys Logic USB 2.0 PC Camera */
+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor             = 0x05e3,
+	  .idProduct            = 0x0505,
+	  .bInterfaceClass      = USB_CLASS_VIDEO,
+	  .bInterfaceSubClass   = 1,
+	  .bInterfaceProtocol   = 0,
+	  .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+	/* Silicon Motion SM371 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x090c,
+	  .idProduct		= 0xb371,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* MT6227 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0e8d,
+	  .idProduct		= 0x0004,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Syntek (HP Spartan) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x174f,
+	  .idProduct		= 0x5212,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
+	/* Syntek (Asus U3S) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x174f,
+	  .idProduct		= 0x8a33,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
+	/* Ecamm Pico iMage */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x18cd,
+	  .idProduct		= 0xcafe,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_EXTRAFIELDS },
+	/* Bodelin ProScopeHR */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_DEV_HI
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x19ab,
+	  .idProduct		= 0x1000,
+	  .bcdDevice_hi		= 0x0126,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STATUS_INTERVAL },
+	/* SiGma Micro USB Web Camera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x1c4f,
+	  .idProduct		= 0x3000,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX
+				| UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+	/* Acer OEM Webcam - Unknown vendor */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0100,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Packard Bell OEM Webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0101,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Acer Crystal Eye webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0102,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Acer OrbiCam - Unknown vendor */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0200,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Generic USB Video Class */
+	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, uvc_ids);
+
+struct uvc_driver uvc_driver = {
+	.driver = {
+		.name		= "uvcvideo",
+		.probe		= uvc_probe,
+		.disconnect	= uvc_disconnect,
+		.suspend	= uvc_suspend,
+		.resume		= uvc_resume,
+		.id_table	= uvc_ids,
+		.supports_autosuspend = 1,
+	},
+};
+
+static int __init uvc_init(void)
+{
+	int result;
+
+	INIT_LIST_HEAD(&uvc_driver.devices);
+	INIT_LIST_HEAD(&uvc_driver.controls);
+	mutex_init(&uvc_driver.open_mutex);
+	mutex_init(&uvc_driver.ctrl_mutex);
+
+	uvc_ctrl_init();
+
+	result = usb_register(&uvc_driver.driver);
+	if (result == 0)
+		printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+	return result;
+}
+
+static void __exit uvc_cleanup(void)
+{
+	usb_deregister(&uvc_driver.driver);
+}
+
+module_init(uvc_init);
+module_exit(uvc_cleanup);
+
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
new file mode 100644
index 0000000..37bdefd
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -0,0 +1,134 @@
+/*
+ *      uvc_isight.c  --  USB Video Class driver - iSight support
+ *
+ *	Copyright (C) 2006-2007
+ *		Ivan N. Zlatev <contact@i-nz.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.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include "uvcvideo.h"
+
+/* Built-in iSight webcams implements most of UVC 1.0 except a
+ * different packet format. Instead of sending a header at the
+ * beginning of each isochronous transfer payload, the webcam sends a
+ * single header per image (on its own in a packet), followed by
+ * packets containing data only.
+ *
+ * Offset   Size (bytes)	Description
+ * ------------------------------------------------------------------
+ * 0x00 	1   	Header length
+ * 0x01 	1   	Flags (UVC-compliant)
+ * 0x02 	4   	Always equal to '11223344'
+ * 0x06 	8   	Always equal to 'deadbeefdeadface'
+ * 0x0e 	16  	Unknown
+ *
+ * The header can be prefixed by an optional, unknown-purpose byte.
+ */
+
+static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
+		const __u8 *data, unsigned int len)
+{
+	static const __u8 hdr[] = {
+		0x11, 0x22, 0x33, 0x44,
+		0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xfa, 0xce
+	};
+
+	unsigned int maxlen, nbytes;
+	__u8 *mem;
+	int is_header = 0;
+
+	if (buf == NULL)
+		return 0;
+
+	if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) ||
+	    (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) {
+		uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
+		is_header = 1;
+	}
+
+	/* Synchronize to the input stream by waiting for a header packet. */
+	if (buf->state != UVC_BUF_STATE_ACTIVE) {
+		if (!is_header) {
+			uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
+				  "sync).\n");
+			return 0;
+		}
+
+		buf->state = UVC_BUF_STATE_ACTIVE;
+	}
+
+	/* Mark the buffer as done if we're at the beginning of a new frame.
+	 *
+	 * Empty buffers (bytesused == 0) don't trigger end of frame detection
+	 * as it doesn't make sense to return an empty buffer.
+	 */
+	if (is_header && buf->buf.bytesused != 0) {
+		buf->state = UVC_BUF_STATE_DONE;
+		return -EAGAIN;
+	}
+
+	/* Copy the video data to the buffer. Skip header packets, as they
+	 * contain no data.
+	 */
+	if (!is_header) {
+		maxlen = buf->buf.length - buf->buf.bytesused;
+		mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+		nbytes = min(len, maxlen);
+		memcpy(mem, data, nbytes);
+		buf->buf.bytesused += nbytes;
+
+		if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+			uvc_trace(UVC_TRACE_FRAME, "Frame complete "
+				  "(overflow).\n");
+			buf->state = UVC_BUF_STATE_DONE;
+		}
+	}
+
+	return 0;
+}
+
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+		struct uvc_buffer *buf)
+{
+	int ret, i;
+
+	for (i = 0; i < urb->number_of_packets; ++i) {
+		if (urb->iso_frame_desc[i].status < 0) {
+			uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+				  "lost (%d).\n",
+				  urb->iso_frame_desc[i].status);
+		}
+
+		/* Decode the payload packet.
+		 * uvc_video_decode is entered twice when a frame transition
+		 * has been detected because the end of frame can only be
+		 * reliably detected when the first packet of the new frame
+		 * is processed. The first pass detects the transition and
+		 * closes the previous frame's buffer, the second pass
+		 * processes the data of the first payload of the new frame.
+		 */
+		do {
+			ret = isight_decode(&video->queue, buf,
+					urb->transfer_buffer +
+					urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+
+			if (buf == NULL)
+				break;
+
+			if (buf->state == UVC_BUF_STATE_DONE ||
+			    buf->state == UVC_BUF_STATE_ERROR)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		} while (ret == -EAGAIN);
+	}
+}
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
new file mode 100644
index 0000000..0923f0e
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -0,0 +1,477 @@
+/*
+ *      uvc_queue.c  --  USB Video Class driver - Buffers management
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * Video buffers queue management.
+ *
+ * Video queues is initialized by uvc_queue_init(). The function performs
+ * basic initialization of the uvc_video_queue struct and never fails.
+ *
+ * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
+ * uvc_free_buffers respectively. The former acquires the video queue lock,
+ * while the later must be called with the lock held (so that allocation can
+ * free previously allocated buffers). Trying to free buffers that are mapped
+ * to user space will return -EBUSY.
+ *
+ * Video buffers are managed using two queues. However, unlike most USB video
+ * drivers which use an in queue and an out queue, we use a main queue which
+ * holds all queued buffers (both 'empty' and 'done' buffers), and an irq
+ * queue which holds empty buffers. This design (copied from video-buf)
+ * minimizes locking in interrupt, as only one queue is shared between
+ * interrupt and user contexts.
+ *
+ * Use cases
+ * ---------
+ *
+ * Unless stated otherwise, all operations which modify the irq buffers queue
+ * are protected by the irq spinlock.
+ *
+ * 1. The user queues the buffers, starts streaming and dequeues a buffer.
+ *
+ *    The buffers are added to the main and irq queues. Both operations are
+ *    protected by the queue lock, and the latert is protected by the irq
+ *    spinlock as well.
+ *
+ *    The completion handler fetches a buffer from the irq queue and fills it
+ *    with video data. If no buffer is available (irq queue empty), the handler
+ *    returns immediately.
+ *
+ *    When the buffer is full, the completion handler removes it from the irq
+ *    queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue.
+ *    At that point, any process waiting on the buffer will be woken up. If a
+ *    process tries to dequeue a buffer after it has been marked ready, the
+ *    dequeing will succeed immediately.
+ *
+ * 2. Buffers are queued, user is waiting on a buffer and the device gets
+ *    disconnected.
+ *
+ *    When the device is disconnected, the kernel calls the completion handler
+ *    with an appropriate status code. The handler marks all buffers in the
+ *    irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
+ *    that any process waiting on a buffer gets woken up.
+ *
+ *    Waking up up the first buffer on the irq list is not enough, as the
+ *    process waiting on the buffer might restart the dequeue operation
+ *    immediately.
+ *
+ */
+
+void uvc_queue_init(struct uvc_video_queue *queue)
+{
+	mutex_init(&queue->mutex);
+	spin_lock_init(&queue->irqlock);
+	INIT_LIST_HEAD(&queue->mainqueue);
+	INIT_LIST_HEAD(&queue->irqqueue);
+}
+
+/*
+ * Allocate the video buffers.
+ *
+ * Pages are reserved to make sure they will not be swaped, as they will be
+ * filled in URB completion handler.
+ *
+ * Buffers will be individually mapped, so they must all be page aligned.
+ */
+int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
+		unsigned int buflength)
+{
+	unsigned int bufsize = PAGE_ALIGN(buflength);
+	unsigned int i;
+	void *mem = NULL;
+	int ret;
+
+	if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
+		nbuffers = UVC_MAX_VIDEO_BUFFERS;
+
+	mutex_lock(&queue->mutex);
+
+	if ((ret = uvc_free_buffers(queue)) < 0)
+		goto done;
+
+	/* Bail out if no buffers should be allocated. */
+	if (nbuffers == 0)
+		goto done;
+
+	/* Decrement the number of buffers until allocation succeeds. */
+	for (; nbuffers > 0; --nbuffers) {
+		mem = vmalloc_32(nbuffers * bufsize);
+		if (mem != NULL)
+			break;
+	}
+
+	if (mem == NULL) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	for (i = 0; i < nbuffers; ++i) {
+		memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
+		queue->buffer[i].buf.index = i;
+		queue->buffer[i].buf.m.offset = i * bufsize;
+		queue->buffer[i].buf.length = buflength;
+		queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		queue->buffer[i].buf.sequence = 0;
+		queue->buffer[i].buf.field = V4L2_FIELD_NONE;
+		queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
+		queue->buffer[i].buf.flags = 0;
+		init_waitqueue_head(&queue->buffer[i].wait);
+	}
+
+	queue->mem = mem;
+	queue->count = nbuffers;
+	queue->buf_size = bufsize;
+	ret = nbuffers;
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+	unsigned int i;
+
+	for (i = 0; i < queue->count; ++i) {
+		if (queue->buffer[i].vma_use_count != 0)
+			return -EBUSY;
+	}
+
+	if (queue->count) {
+		vfree(queue->mem);
+		queue->count = 0;
+	}
+
+	return 0;
+}
+
+static void __uvc_query_buffer(struct uvc_buffer *buf,
+		struct v4l2_buffer *v4l2_buf)
+{
+	memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
+
+	if (buf->vma_use_count)
+		v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	switch (buf->state) {
+	case UVC_BUF_STATE_ERROR:
+	case UVC_BUF_STATE_DONE:
+		v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
+		break;
+	case UVC_BUF_STATE_QUEUED:
+	case UVC_BUF_STATE_ACTIVE:
+		v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		break;
+	case UVC_BUF_STATE_IDLE:
+	default:
+		break;
+	}
+}
+
+int uvc_query_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf)
+{
+	int ret = 0;
+
+	mutex_lock(&queue->mutex);
+	if (v4l2_buf->index >= queue->count) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+
+done:
+       mutex_unlock(&queue->mutex);
+       return ret;
+}
+
+/*
+ * Queue a video buffer. Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+	struct v4l2_buffer *v4l2_buf)
+{
+	struct uvc_buffer *buf;
+	unsigned long flags;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+			"and/or memory (%u).\n", v4l2_buf->type,
+			v4l2_buf->memory);
+		return -EINVAL;
+	}
+
+	mutex_lock(&queue->mutex);
+	if (v4l2_buf->index >= queue->count)  {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = &queue->buffer[v4l2_buf->index];
+	if (buf->state != UVC_BUF_STATE_IDLE) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
+			"(%u).\n", buf->state);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	if (queue->flags & UVC_QUEUE_DISCONNECTED) {
+		spin_unlock_irqrestore(&queue->irqlock, flags);
+		ret = -ENODEV;
+		goto done;
+	}
+	buf->state = UVC_BUF_STATE_QUEUED;
+	buf->buf.bytesused = 0;
+	list_add_tail(&buf->stream, &queue->mainqueue);
+	list_add_tail(&buf->queue, &queue->irqqueue);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
+{
+	if (nonblocking) {
+		return (buf->state != UVC_BUF_STATE_QUEUED &&
+			buf->state != UVC_BUF_STATE_ACTIVE)
+			? 0 : -EAGAIN;
+	}
+
+	return wait_event_interruptible(buf->wait,
+		buf->state != UVC_BUF_STATE_QUEUED &&
+		buf->state != UVC_BUF_STATE_ACTIVE);
+}
+
+/*
+ * Dequeue a video buffer. If nonblocking is false, block until a buffer is
+ * available.
+ */
+int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf, int nonblocking)
+{
+	struct uvc_buffer *buf;
+	int ret = 0;
+
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+			"and/or memory (%u).\n", v4l2_buf->type,
+			v4l2_buf->memory);
+		return -EINVAL;
+	}
+
+	mutex_lock(&queue->mutex);
+	if (list_empty(&queue->mainqueue)) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+	if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
+		goto done;
+
+	uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
+		buf->buf.index, buf->state, buf->buf.bytesused);
+
+	switch (buf->state) {
+	case UVC_BUF_STATE_ERROR:
+		uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
+			"(transmission error).\n");
+		ret = -EIO;
+	case UVC_BUF_STATE_DONE:
+		buf->state = UVC_BUF_STATE_IDLE;
+		break;
+
+	case UVC_BUF_STATE_IDLE:
+	case UVC_BUF_STATE_QUEUED:
+	case UVC_BUF_STATE_ACTIVE:
+	default:
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
+			"(driver bug?).\n", buf->state);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	list_del(&buf->stream);
+	__uvc_query_buffer(buf, v4l2_buf);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Poll the video queue.
+ *
+ * This function implements video queue polling and is intended to be used by
+ * the device poll handler.
+ */
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+		poll_table *wait)
+{
+	struct uvc_buffer *buf;
+	unsigned int mask = 0;
+
+	mutex_lock(&queue->mutex);
+	if (list_empty(&queue->mainqueue)) {
+		mask |= POLLERR;
+		goto done;
+	}
+	buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+
+	poll_wait(file, &buf->wait, wait);
+	if (buf->state == UVC_BUF_STATE_DONE ||
+	    buf->state == UVC_BUF_STATE_ERROR)
+		mask |= POLLIN | POLLRDNORM;
+
+done:
+	mutex_unlock(&queue->mutex);
+	return mask;
+}
+
+/*
+ * Enable or disable the video buffers queue.
+ *
+ * The queue must be enabled before starting video acquisition and must be
+ * disabled after stopping it. This ensures that the video buffers queue
+ * state can be properly initialized before buffers are accessed from the
+ * interrupt handler.
+ *
+ * Enabling the video queue initializes parameters (such as sequence number,
+ * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ *
+ * Disabling the video queue cancels the queue and removes all buffers from
+ * the main queue.
+ *
+ * This function can't be called from interrupt context. Use
+ * uvc_queue_cancel() instead.
+ */
+int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
+{
+	unsigned int i;
+	int ret = 0;
+
+	mutex_lock(&queue->mutex);
+	if (enable) {
+		if (uvc_queue_streaming(queue)) {
+			ret = -EBUSY;
+			goto done;
+		}
+		queue->sequence = 0;
+		queue->flags |= UVC_QUEUE_STREAMING;
+	} else {
+		uvc_queue_cancel(queue, 0);
+		INIT_LIST_HEAD(&queue->mainqueue);
+
+		for (i = 0; i < queue->count; ++i)
+			queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+
+		queue->flags &= ~UVC_QUEUE_STREAMING;
+	}
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Cancel the video buffers queue.
+ *
+ * Cancelling the queue marks all buffers on the irq queue as erroneous,
+ * wakes them up and remove them from the queue.
+ *
+ * If the disconnect parameter is set, further calls to uvc_queue_buffer will
+ * fail with -ENODEV.
+ *
+ * This function acquires the irq spinlock and can be called from interrupt
+ * context.
+ */
+void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
+{
+	struct uvc_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	while (!list_empty(&queue->irqqueue)) {
+		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+				       queue);
+		list_del(&buf->queue);
+		buf->state = UVC_BUF_STATE_ERROR;
+		wake_up(&buf->wait);
+	}
+	/* This must be protected by the irqlock spinlock to avoid race
+	 * conditions between uvc_queue_buffer and the disconnection event that
+	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
+	 * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+	 * state outside the queue code.
+	 */
+	if (disconnect)
+		queue->flags |= UVC_QUEUE_DISCONNECTED;
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+		struct uvc_buffer *buf)
+{
+	struct uvc_buffer *nextbuf;
+	unsigned long flags;
+
+	if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
+	    buf->buf.length != buf->buf.bytesused) {
+		buf->state = UVC_BUF_STATE_QUEUED;
+		buf->buf.bytesused = 0;
+		return buf;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	list_del(&buf->queue);
+	if (!list_empty(&queue->irqqueue))
+		nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+					   queue);
+	else
+		nextbuf = NULL;
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	buf->buf.sequence = queue->sequence++;
+	do_gettimeofday(&buf->buf.timestamp);
+
+	wake_up(&buf->wait);
+	return nextbuf;
+}
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
new file mode 100644
index 0000000..be9084e
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -0,0 +1,207 @@
+/*
+ *      uvc_status.c  --  USB Video Class driver - Status endpoint
+ *
+ *      Copyright (C) 2007-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#include "uvcvideo.h"
+
+/* --------------------------------------------------------------------------
+ * Input device
+ */
+static int uvc_input_init(struct uvc_device *dev)
+{
+	struct usb_device *udev = dev->udev;
+	struct input_dev *input;
+	char *phys = NULL;
+	int ret;
+
+	input = input_allocate_device();
+	if (input == NULL)
+		return -ENOMEM;
+
+	phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath),
+			GFP_KERNEL);
+	if (phys == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath);
+
+	input->name = dev->name;
+	input->phys = phys;
+	usb_to_input_id(udev, &input->id);
+	input->dev.parent = &dev->intf->dev;
+
+	set_bit(EV_KEY, input->evbit);
+	set_bit(BTN_0, input->keybit);
+
+	if ((ret = input_register_device(input)) < 0)
+		goto error;
+
+	dev->input = input;
+	return 0;
+
+error:
+	input_free_device(input);
+	kfree(phys);
+	return ret;
+}
+
+static void uvc_input_cleanup(struct uvc_device *dev)
+{
+	if (dev->input)
+		input_unregister_device(dev->input);
+}
+
+/* --------------------------------------------------------------------------
+ * Status interrupt endpoint
+ */
+static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
+{
+	if (len < 3) {
+		uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
+				"received.\n");
+		return;
+	}
+
+	if (data[2] == 0) {
+		if (len < 4)
+			return;
+		uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
+			data[1], data[3] ? "pressed" : "released", len);
+		if (dev->input)
+			input_report_key(dev->input, BTN_0, data[3]);
+	} else {
+		uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
+			"len %d.\n", data[1], data[2], data[3], len);
+	}
+}
+
+static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
+{
+	char *attrs[3] = { "value", "info", "failure" };
+
+	if (len < 6 || data[2] != 0 || data[4] > 2) {
+		uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
+				"received.\n");
+		return;
+	}
+
+	uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
+		data[1], data[3], attrs[data[4]], len);
+}
+
+static void uvc_status_complete(struct urb *urb)
+{
+	struct uvc_device *dev = urb->context;
+	int len, ret;
+
+	switch (urb->status) {
+	case 0:
+		break;
+
+	case -ENOENT:		/* usb_kill_urb() called. */
+	case -ECONNRESET:	/* usb_unlink_urb() called. */
+	case -ESHUTDOWN:	/* The endpoint is being disabled. */
+	case -EPROTO:		/* Device is disconnected (reported by some
+				 * host controller). */
+		return;
+
+	default:
+		uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
+			"completion handler.\n", urb->status);
+		return;
+	}
+
+	len = urb->actual_length;
+	if (len > 0) {
+		switch (dev->status[0] & 0x0f) {
+		case UVC_STATUS_TYPE_CONTROL:
+			uvc_event_control(dev, dev->status, len);
+			break;
+
+		case UVC_STATUS_TYPE_STREAMING:
+			uvc_event_streaming(dev, dev->status, len);
+			break;
+
+		default:
+			uvc_printk(KERN_INFO, "unknown event type %u.\n",
+				dev->status[0]);
+			break;
+		}
+	}
+
+	/* Resubmit the URB. */
+	urb->interval = dev->int_ep->desc.bInterval;
+	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+			ret);
+	}
+}
+
+int uvc_status_init(struct uvc_device *dev)
+{
+	struct usb_host_endpoint *ep = dev->int_ep;
+	unsigned int pipe;
+	int interval;
+
+	if (ep == NULL)
+		return 0;
+
+	uvc_input_init(dev);
+
+	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (dev->int_urb == NULL)
+		return -ENOMEM;
+
+	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
+
+	/* For high-speed interrupt endpoints, the bInterval value is used as
+	 * an exponent of two. Some developers forgot about it.
+	 */
+	interval = ep->desc.bInterval;
+	if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
+	    (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
+		interval = fls(interval) - 1;
+
+	usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
+		dev->status, sizeof dev->status, uvc_status_complete,
+		dev, interval);
+
+	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_cleanup(struct uvc_device *dev)
+{
+	usb_kill_urb(dev->int_urb);
+	usb_free_urb(dev->int_urb);
+	uvc_input_cleanup(dev);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+	usb_kill_urb(dev->int_urb);
+	return 0;
+}
+
+int uvc_status_resume(struct uvc_device *dev)
+{
+	if (dev->int_urb == NULL)
+		return 0;
+
+	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
new file mode 100644
index 0000000..2e0a665
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -0,0 +1,1105 @@
+/*
+ *      uvc_v4l2.c  --  USB Video Class driver - V4L2 API
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * V4L2 interface
+ */
+
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls which can be mapped directly, and handle the others
+ * manually.
+ */
+static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+	struct v4l2_querymenu *query_menu)
+{
+	struct uvc_menu_info *menu_info;
+	struct uvc_control_mapping *mapping;
+	struct uvc_control *ctrl;
+
+	ctrl = uvc_find_control(video, query_menu->id, &mapping);
+	if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
+		return -EINVAL;
+
+	if (query_menu->index >= mapping->menu_count)
+		return -EINVAL;
+
+	menu_info = &mapping->menu_info[query_menu->index];
+	strncpy(query_menu->name, menu_info->name, 32);
+	return 0;
+}
+
+/*
+ * Find the frame interval closest to the requested frame interval for the
+ * given frame format and size. This should be done by the device as part of
+ * the Video Probe and Commit negotiation, but some hardware don't implement
+ * that feature.
+ */
+static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
+{
+	unsigned int i;
+
+	if (frame->bFrameIntervalType) {
+		__u32 best = -1, dist;
+
+		for (i = 0; i < frame->bFrameIntervalType; ++i) {
+			dist = interval > frame->dwFrameInterval[i]
+			     ? interval - frame->dwFrameInterval[i]
+			     : frame->dwFrameInterval[i] - interval;
+
+			if (dist > best)
+				break;
+
+			best = dist;
+		}
+
+		interval = frame->dwFrameInterval[i-1];
+	} else {
+		const __u32 min = frame->dwFrameInterval[0];
+		const __u32 max = frame->dwFrameInterval[1];
+		const __u32 step = frame->dwFrameInterval[2];
+
+		interval = min + (interval - min + step/2) / step * step;
+		if (interval > max)
+			interval = max;
+	}
+
+	return interval;
+}
+
+static int uvc_v4l2_try_format(struct uvc_video_device *video,
+	struct v4l2_format *fmt, struct uvc_streaming_control *probe,
+	struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
+{
+	struct uvc_format *format = NULL;
+	struct uvc_frame *frame = NULL;
+	__u16 rw, rh;
+	unsigned int d, maxd;
+	unsigned int i;
+	__u32 interval;
+	int ret = 0;
+	__u8 *fcc;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
+	uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n",
+			fmt->fmt.pix.pixelformat,
+			fcc[0], fcc[1], fcc[2], fcc[3],
+			fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+	/* Check if the hardware supports the requested format. */
+	for (i = 0; i < video->streaming->nformats; ++i) {
+		format = &video->streaming->format[i];
+		if (format->fcc == fmt->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
+		uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n",
+				fmt->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	/* Find the closest image size. The distance between image sizes is
+	 * the size in pixels of the non-overlapping regions between the
+	 * requested size and the frame-specified size.
+	 */
+	rw = fmt->fmt.pix.width;
+	rh = fmt->fmt.pix.height;
+	maxd = (unsigned int)-1;
+
+	for (i = 0; i < format->nframes; ++i) {
+		__u16 w = format->frame[i].wWidth;
+		__u16 h = format->frame[i].wHeight;
+
+		d = min(w, rw) * min(h, rh);
+		d = w*h + rw*rh - 2*d;
+		if (d < maxd) {
+			maxd = d;
+			frame = &format->frame[i];
+		}
+
+		if (maxd == 0)
+			break;
+	}
+
+	if (frame == NULL) {
+		uvc_trace(UVC_TRACE_FORMAT, "Unsupported size %ux%u.\n",
+				fmt->fmt.pix.width, fmt->fmt.pix.height);
+		return -EINVAL;
+	}
+
+	/* Use the default frame interval. */
+	interval = frame->dwDefaultFrameInterval;
+	uvc_trace(UVC_TRACE_FORMAT, "Using default frame interval %u.%u us "
+		"(%u.%u fps).\n", interval/10, interval%10, 10000000/interval,
+		(100000000/interval)%10);
+
+	/* Set the format index, frame index and frame interval. */
+	memset(probe, 0, sizeof *probe);
+	probe->bmHint = 1;	/* dwFrameInterval */
+	probe->bFormatIndex = format->index;
+	probe->bFrameIndex = frame->bFrameIndex;
+	probe->dwFrameInterval = uvc_try_frame_interval(frame, interval);
+	/* Some webcams stall the probe control set request when the
+	 * dwMaxVideoFrameSize field is set to zero. The UVC specification
+	 * clearly states that the field is read-only from the host, so this
+	 * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by
+	 * the webcam to work around the problem.
+	 *
+	 * The workaround could probably be enabled for all webcams, so the
+	 * quirk can be removed if needed. It's currently useful to detect
+	 * webcam bugs and fix them before they hit the market (providing
+	 * developers test their webcams with the Linux driver as well as with
+	 * the Windows driver).
+	 */
+	if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+		probe->dwMaxVideoFrameSize =
+			video->streaming->ctrl.dwMaxVideoFrameSize;
+
+	/* Probe the device */
+	if ((ret = uvc_probe_video(video, probe)) < 0)
+		goto done;
+
+	fmt->fmt.pix.width = frame->wWidth;
+	fmt->fmt.pix.height = frame->wHeight;
+	fmt->fmt.pix.field = V4L2_FIELD_NONE;
+	fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+	fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+	fmt->fmt.pix.colorspace = format->colorspace;
+	fmt->fmt.pix.priv = 0;
+
+	if (uvc_format != NULL)
+		*uvc_format = format;
+	if (uvc_frame != NULL)
+		*uvc_frame = frame;
+
+done:
+	return ret;
+}
+
+static int uvc_v4l2_get_format(struct uvc_video_device *video,
+	struct v4l2_format *fmt)
+{
+	struct uvc_format *format = video->streaming->cur_format;
+	struct uvc_frame *frame = video->streaming->cur_frame;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (format == NULL || frame == NULL)
+		return -EINVAL;
+
+	fmt->fmt.pix.pixelformat = format->fcc;
+	fmt->fmt.pix.width = frame->wWidth;
+	fmt->fmt.pix.height = frame->wHeight;
+	fmt->fmt.pix.field = V4L2_FIELD_NONE;
+	fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+	fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+	fmt->fmt.pix.colorspace = format->colorspace;
+	fmt->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int uvc_v4l2_set_format(struct uvc_video_device *video,
+	struct v4l2_format *fmt)
+{
+	struct uvc_streaming_control probe;
+	struct uvc_format *format;
+	struct uvc_frame *frame;
+	int ret;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (uvc_queue_streaming(&video->queue))
+		return -EBUSY;
+
+	ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+	if (ret < 0)
+		return ret;
+
+	if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+		return ret;
+
+	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+	video->streaming->cur_format = format;
+	video->streaming->cur_frame = frame;
+
+	return 0;
+}
+
+static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+		struct v4l2_streamparm *parm)
+{
+	uint32_t numerator, denominator;
+
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	numerator = video->streaming->ctrl.dwFrameInterval;
+	denominator = 10000000;
+	uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+
+	memset(parm, 0, sizeof *parm);
+	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	parm->parm.capture.capturemode = 0;
+	parm->parm.capture.timeperframe.numerator = numerator;
+	parm->parm.capture.timeperframe.denominator = denominator;
+	parm->parm.capture.extendedmode = 0;
+	parm->parm.capture.readbuffers = 0;
+
+	return 0;
+}
+
+static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+		struct v4l2_streamparm *parm)
+{
+	struct uvc_frame *frame = video->streaming->cur_frame;
+	struct uvc_streaming_control probe;
+	uint32_t interval;
+	int ret;
+
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (uvc_queue_streaming(&video->queue))
+		return -EBUSY;
+
+	memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+	interval = uvc_fraction_to_interval(
+			parm->parm.capture.timeperframe.numerator,
+			parm->parm.capture.timeperframe.denominator);
+
+	uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
+			parm->parm.capture.timeperframe.numerator,
+			parm->parm.capture.timeperframe.denominator,
+			interval);
+	probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+	/* Probe the device with the new settings. */
+	if ((ret = uvc_probe_video(video, &probe)) < 0)
+		return ret;
+
+	/* Commit the new settings. */
+	if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+		return ret;
+
+	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+
+	/* Return the actual frame period. */
+	parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
+	parm->parm.capture.timeperframe.denominator = 10000000;
+	uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
+				&parm->parm.capture.timeperframe.denominator,
+				8, 333);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Privilege management
+ */
+
+/*
+ * Privilege management is the multiple-open implementation basis. The current
+ * implementation is completely transparent for the end-user and doesn't
+ * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
+ * Those ioctls enable finer control on the device (by making possible for a
+ * user to request exclusive access to a device), but are not mature yet.
+ * Switching to the V4L2 priority mechanism might be considered in the future
+ * if this situation changes.
+ *
+ * Each open instance of a UVC device can either be in a privileged or
+ * unprivileged state. Only a single instance can be in a privileged state at
+ * a given time. Trying to perform an operation which requires privileges will
+ * automatically acquire the required privileges if possible, or return -EBUSY
+ * otherwise. Privileges are dismissed when closing the instance.
+ *
+ * Operations which require privileges are:
+ *
+ * - VIDIOC_S_INPUT
+ * - VIDIOC_S_PARM
+ * - VIDIOC_S_FMT
+ * - VIDIOC_TRY_FMT
+ * - VIDIOC_REQBUFS
+ */
+static int uvc_acquire_privileges(struct uvc_fh *handle)
+{
+	int ret = 0;
+
+	/* Always succeed if the handle is already privileged. */
+	if (handle->state == UVC_HANDLE_ACTIVE)
+		return 0;
+
+	/* Check if the device already has a privileged handle. */
+	mutex_lock(&uvc_driver.open_mutex);
+	if (atomic_inc_return(&handle->device->active) != 1) {
+		atomic_dec(&handle->device->active);
+		ret = -EBUSY;
+		goto done;
+	}
+
+	handle->state = UVC_HANDLE_ACTIVE;
+
+done:
+	mutex_unlock(&uvc_driver.open_mutex);
+	return ret;
+}
+
+static void uvc_dismiss_privileges(struct uvc_fh *handle)
+{
+	if (handle->state == UVC_HANDLE_ACTIVE)
+		atomic_dec(&handle->device->active);
+
+	handle->state = UVC_HANDLE_PASSIVE;
+}
+
+static int uvc_has_privileges(struct uvc_fh *handle)
+{
+	return handle->state == UVC_HANDLE_ACTIVE;
+}
+
+/* ------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int uvc_v4l2_open(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev;
+	struct uvc_video_device *video;
+	struct uvc_fh *handle;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
+	mutex_lock(&uvc_driver.open_mutex);
+	vdev = video_devdata(file);
+	video = video_get_drvdata(vdev);
+
+	if (video->dev->state & UVC_DEV_DISCONNECTED) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	ret = usb_autopm_get_interface(video->dev->intf);
+	if (ret < 0)
+		goto done;
+
+	/* Create the device handle. */
+	handle = kzalloc(sizeof *handle, GFP_KERNEL);
+	if (handle == NULL) {
+		usb_autopm_put_interface(video->dev->intf);
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	handle->device = video;
+	handle->state = UVC_HANDLE_PASSIVE;
+	file->private_data = handle;
+
+	kref_get(&video->dev->kref);
+
+done:
+	mutex_unlock(&uvc_driver.open_mutex);
+	return ret;
+}
+
+static int uvc_v4l2_release(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
+
+	/* Only free resources if this is a privileged handle. */
+	if (uvc_has_privileges(handle)) {
+		uvc_video_enable(video, 0);
+
+		mutex_lock(&video->queue.mutex);
+		if (uvc_free_buffers(&video->queue) < 0)
+			uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
+					"free buffers.\n");
+		mutex_unlock(&video->queue.mutex);
+	}
+
+	/* Release the file handle. */
+	uvc_dismiss_privileges(handle);
+	kfree(handle);
+	file->private_data = NULL;
+
+	usb_autopm_put_interface(video->dev->intf);
+	kref_put(&video->dev->kref, uvc_delete);
+	return 0;
+}
+
+static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	int ret = 0;
+
+	if (uvc_trace_param & UVC_TRACE_IOCTL)
+		v4l_printk_ioctl(cmd);
+
+	switch (cmd) {
+	/* Query capabilities */
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap, 0, sizeof *cap);
+		strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
+		strncpy(cap->card, vdev->name, 32);
+		strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
+			sizeof cap->bus_info);
+		cap->version = DRIVER_VERSION_NUMBER;
+		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+				  | V4L2_CAP_STREAMING;
+		break;
+	}
+
+	/* Get, Set & Query control */
+	case VIDIOC_QUERYCTRL:
+		return uvc_query_v4l2_ctrl(video, arg);
+
+	case VIDIOC_G_CTRL:
+	{
+		struct v4l2_control *ctrl = arg;
+		struct v4l2_ext_control xctrl;
+
+		memset(&xctrl, 0, sizeof xctrl);
+		xctrl.id = ctrl->id;
+
+		uvc_ctrl_begin(video);
+		ret = uvc_ctrl_get(video, &xctrl);
+		uvc_ctrl_rollback(video);
+		if (ret >= 0)
+			ctrl->value = xctrl.value;
+		break;
+	}
+
+	case VIDIOC_S_CTRL:
+	{
+		struct v4l2_control *ctrl = arg;
+		struct v4l2_ext_control xctrl;
+
+		memset(&xctrl, 0, sizeof xctrl);
+		xctrl.id = ctrl->id;
+		xctrl.value = ctrl->value;
+
+		uvc_ctrl_begin(video);
+		ret = uvc_ctrl_set(video, &xctrl);
+		if (ret < 0) {
+			uvc_ctrl_rollback(video);
+			return ret;
+		}
+		ret = uvc_ctrl_commit(video);
+		break;
+	}
+
+	case VIDIOC_QUERYMENU:
+		return uvc_v4l2_query_menu(video, arg);
+
+	case VIDIOC_G_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *ctrls = arg;
+		struct v4l2_ext_control *ctrl = ctrls->controls;
+		unsigned int i;
+
+		uvc_ctrl_begin(video);
+		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+			ret = uvc_ctrl_get(video, ctrl);
+			if (ret < 0) {
+				uvc_ctrl_rollback(video);
+				ctrls->error_idx = i;
+				return ret;
+			}
+		}
+		ctrls->error_idx = 0;
+		ret = uvc_ctrl_rollback(video);
+		break;
+	}
+
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *ctrls = arg;
+		struct v4l2_ext_control *ctrl = ctrls->controls;
+		unsigned int i;
+
+		ret = uvc_ctrl_begin(video);
+		if (ret < 0)
+			return ret;
+
+		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+			ret = uvc_ctrl_set(video, ctrl);
+			if (ret < 0) {
+				uvc_ctrl_rollback(video);
+				ctrls->error_idx = i;
+				return ret;
+			}
+		}
+
+		ctrls->error_idx = 0;
+
+		if (cmd == VIDIOC_S_EXT_CTRLS)
+			ret = uvc_ctrl_commit(video);
+		else
+			ret = uvc_ctrl_rollback(video);
+		break;
+	}
+
+	/* Get, Set & Enum input */
+	case VIDIOC_ENUMINPUT:
+	{
+		const struct uvc_entity *selector = video->selector;
+		struct v4l2_input *input = arg;
+		struct uvc_entity *iterm = NULL;
+		u32 index = input->index;
+		int pin = 0;
+
+		if (selector == NULL ||
+		    (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+			if (index != 0)
+				return -EINVAL;
+			iterm = list_first_entry(&video->iterms,
+					struct uvc_entity, chain);
+			pin = iterm->id;
+		} else if (pin < selector->selector.bNrInPins) {
+			pin = selector->selector.baSourceID[index];
+			list_for_each_entry(iterm, video->iterms.next, chain) {
+				if (iterm->id == pin)
+					break;
+			}
+		}
+
+		if (iterm == NULL || iterm->id != pin)
+			return -EINVAL;
+
+		memset(input, 0, sizeof *input);
+		input->index = index;
+		strncpy(input->name, iterm->name, sizeof input->name);
+		if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+			input->type = V4L2_INPUT_TYPE_CAMERA;
+		break;
+	}
+
+	case VIDIOC_G_INPUT:
+	{
+		u8 input;
+
+		if (video->selector == NULL ||
+		    (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+			*(int *)arg = 0;
+			break;
+		}
+
+		ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
+			video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+			&input, 1);
+		if (ret < 0)
+			return ret;
+
+		*(int *)arg = input - 1;
+		break;
+	}
+
+	case VIDIOC_S_INPUT:
+	{
+		u8 input = *(u32 *)arg + 1;
+
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		if (video->selector == NULL ||
+		    (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+			if (input != 1)
+				return -EINVAL;
+			break;
+		}
+
+		if (input > video->selector->selector.bNrInPins)
+			return -EINVAL;
+
+		return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
+			video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+			&input, 1);
+	}
+
+	/* Try, Get, Set & Enum format */
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *fmt = arg;
+		struct uvc_format *format;
+
+		if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		    fmt->index >= video->streaming->nformats)
+			return -EINVAL;
+
+		format = &video->streaming->format[fmt->index];
+		fmt->flags = 0;
+		if (format->flags & UVC_FMT_FLAG_COMPRESSED)
+			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+		strncpy(fmt->description, format->name,
+			sizeof fmt->description);
+		fmt->description[sizeof fmt->description - 1] = 0;
+		fmt->pixelformat = format->fcc;
+		break;
+	}
+
+	case VIDIOC_TRY_FMT:
+	{
+		struct uvc_streaming_control probe;
+
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+	}
+
+	case VIDIOC_S_FMT:
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		return uvc_v4l2_set_format(video, arg);
+
+	case VIDIOC_G_FMT:
+		return uvc_v4l2_get_format(video, arg);
+
+	/* Frame size enumeration */
+	case VIDIOC_ENUM_FRAMESIZES:
+	{
+		struct v4l2_frmsizeenum *fsize = arg;
+		struct uvc_format *format = NULL;
+		struct uvc_frame *frame;
+		int i;
+
+		/* Look for the given pixel format */
+		for (i = 0; i < video->streaming->nformats; i++) {
+			if (video->streaming->format[i].fcc ==
+					fsize->pixel_format) {
+				format = &video->streaming->format[i];
+				break;
+			}
+		}
+		if (format == NULL)
+			return -EINVAL;
+
+		if (fsize->index >= format->nframes)
+			return -EINVAL;
+
+		frame = &format->frame[fsize->index];
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		fsize->discrete.width = frame->wWidth;
+		fsize->discrete.height = frame->wHeight;
+		break;
+	}
+
+	/* Frame interval enumeration */
+	case VIDIOC_ENUM_FRAMEINTERVALS:
+	{
+		struct v4l2_frmivalenum *fival = arg;
+		struct uvc_format *format = NULL;
+		struct uvc_frame *frame = NULL;
+		int i;
+
+		/* Look for the given pixel format and frame size */
+		for (i = 0; i < video->streaming->nformats; i++) {
+			if (video->streaming->format[i].fcc ==
+					fival->pixel_format) {
+				format = &video->streaming->format[i];
+				break;
+			}
+		}
+		if (format == NULL)
+			return -EINVAL;
+
+		for (i = 0; i < format->nframes; i++) {
+			if (format->frame[i].wWidth == fival->width &&
+			    format->frame[i].wHeight == fival->height) {
+				frame = &format->frame[i];
+				break;
+			}
+		}
+		if (frame == NULL)
+			return -EINVAL;
+
+		if (frame->bFrameIntervalType) {
+			if (fival->index >= frame->bFrameIntervalType)
+				return -EINVAL;
+
+			fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+			fival->discrete.numerator =
+				frame->dwFrameInterval[fival->index];
+			fival->discrete.denominator = 10000000;
+			uvc_simplify_fraction(&fival->discrete.numerator,
+				&fival->discrete.denominator, 8, 333);
+		} else {
+			fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+			fival->stepwise.min.numerator =
+				frame->dwFrameInterval[0];
+			fival->stepwise.min.denominator = 10000000;
+			fival->stepwise.max.numerator =
+				frame->dwFrameInterval[1];
+			fival->stepwise.max.denominator = 10000000;
+			fival->stepwise.step.numerator =
+				frame->dwFrameInterval[2];
+			fival->stepwise.step.denominator = 10000000;
+			uvc_simplify_fraction(&fival->stepwise.min.numerator,
+				&fival->stepwise.min.denominator, 8, 333);
+			uvc_simplify_fraction(&fival->stepwise.max.numerator,
+				&fival->stepwise.max.denominator, 8, 333);
+			uvc_simplify_fraction(&fival->stepwise.step.numerator,
+				&fival->stepwise.step.denominator, 8, 333);
+		}
+		break;
+	}
+
+	/* Get & Set streaming parameters */
+	case VIDIOC_G_PARM:
+		return uvc_v4l2_get_streamparm(video, arg);
+
+	case VIDIOC_S_PARM:
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		return uvc_v4l2_set_streamparm(video, arg);
+
+	/* Cropping and scaling */
+	case VIDIOC_CROPCAP:
+	{
+		struct v4l2_cropcap *ccap = arg;
+		struct uvc_frame *frame = video->streaming->cur_frame;
+
+		if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		ccap->bounds.left = 0;
+		ccap->bounds.top = 0;
+		ccap->bounds.width = frame->wWidth;
+		ccap->bounds.height = frame->wHeight;
+
+		ccap->defrect = ccap->bounds;
+
+		ccap->pixelaspect.numerator = 1;
+		ccap->pixelaspect.denominator = 1;
+		break;
+	}
+
+	case VIDIOC_G_CROP:
+	case VIDIOC_S_CROP:
+		return -EINVAL;
+
+	/* Buffers & streaming */
+	case VIDIOC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *rb = arg;
+		unsigned int bufsize =
+			video->streaming->ctrl.dwMaxVideoFrameSize;
+
+		if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		    rb->memory != V4L2_MEMORY_MMAP)
+			return -EINVAL;
+
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+		if (ret < 0)
+			return ret;
+
+		if (!(video->streaming->cur_format->flags &
+		    UVC_FMT_FLAG_COMPRESSED))
+			video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+
+		rb->count = ret;
+		ret = 0;
+		break;
+	}
+
+	case VIDIOC_QUERYBUF:
+	{
+		struct v4l2_buffer *buf = arg;
+
+		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_query_buffer(&video->queue, buf);
+	}
+
+	case VIDIOC_QBUF:
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_queue_buffer(&video->queue, arg);
+
+	case VIDIOC_DQBUF:
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_dequeue_buffer(&video->queue, arg,
+			file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_STREAMON:
+	{
+		int *type = arg;
+
+		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		if ((ret = uvc_video_enable(video, 1)) < 0)
+			return ret;
+		break;
+	}
+
+	case VIDIOC_STREAMOFF:
+	{
+		int *type = arg;
+
+		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_video_enable(video, 0);
+	}
+
+	/* Analog video standards make no sense for digital cameras. */
+	case VIDIOC_ENUMSTD:
+	case VIDIOC_QUERYSTD:
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+
+	case VIDIOC_OVERLAY:
+
+	case VIDIOC_ENUMAUDIO:
+	case VIDIOC_ENUMAUDOUT:
+
+	case VIDIOC_ENUMOUTPUT:
+		uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
+		return -EINVAL;
+
+	/* Dynamic controls. */
+	case UVCIOC_CTRL_ADD:
+	{
+		struct uvc_xu_control_info *xinfo = arg;
+		struct uvc_control_info *info;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		info = kmalloc(sizeof *info, GFP_KERNEL);
+		if (info == NULL)
+			return -ENOMEM;
+
+		memcpy(info->entity, xinfo->entity, sizeof info->entity);
+		info->index = xinfo->index;
+		info->selector = xinfo->selector;
+		info->size = xinfo->size;
+		info->flags = xinfo->flags;
+
+		info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+				UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+
+		ret = uvc_ctrl_add_info(info);
+		if (ret < 0)
+			kfree(info);
+		break;
+	}
+
+	case UVCIOC_CTRL_MAP:
+	{
+		struct uvc_xu_control_mapping *xmap = arg;
+		struct uvc_control_mapping *map;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		map = kmalloc(sizeof *map, GFP_KERNEL);
+		if (map == NULL)
+			return -ENOMEM;
+
+		map->id = xmap->id;
+		memcpy(map->name, xmap->name, sizeof map->name);
+		memcpy(map->entity, xmap->entity, sizeof map->entity);
+		map->selector = xmap->selector;
+		map->size = xmap->size;
+		map->offset = xmap->offset;
+		map->v4l2_type = xmap->v4l2_type;
+		map->data_type = xmap->data_type;
+
+		ret = uvc_ctrl_add_mapping(map);
+		if (ret < 0)
+			kfree(map);
+		break;
+	}
+
+	case UVCIOC_CTRL_GET:
+		return uvc_xu_ctrl_query(video, arg, 0);
+
+	case UVCIOC_CTRL_SET:
+		return uvc_xu_ctrl_query(video, arg, 1);
+
+	default:
+		if ((ret = v4l_compat_translate_ioctl(inode, file, cmd, arg,
+			uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+			uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
+				  cmd);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
+	return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl);
+}
+
+static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
+		    size_t count, loff_t *ppos)
+{
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
+	return -ENODEV;
+}
+
+/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+	struct uvc_buffer *buffer = vma->vm_private_data;
+	buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+	struct uvc_buffer *buffer = vma->vm_private_data;
+	buffer->vma_use_count--;
+}
+
+static struct vm_operations_struct uvc_vm_ops = {
+	.open		= uvc_vm_open,
+	.close		= uvc_vm_close,
+};
+
+static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_buffer *buffer;
+	struct page *page;
+	unsigned long addr, start, size;
+	unsigned int i;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
+
+	start = vma->vm_start;
+	size = vma->vm_end - vma->vm_start;
+
+	mutex_lock(&video->queue.mutex);
+
+	for (i = 0; i < video->queue.count; ++i) {
+		buffer = &video->queue.buffer[i];
+		if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+
+	if (i == video->queue.count || size != video->queue.buf_size) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 * VM_IO marks the area as being an mmaped region for I/O to a
+	 * device. It also prevents the region from being core dumped.
+	 */
+	vma->vm_flags |= VM_IO;
+
+	addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+	while (size > 0) {
+		page = vmalloc_to_page((void *)addr);
+		if ((ret = vm_insert_page(vma, start, page)) < 0)
+			goto done;
+
+		start += PAGE_SIZE;
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &uvc_vm_ops;
+	vma->vm_private_data = buffer;
+	uvc_vm_open(vma);
+
+done:
+	mutex_unlock(&video->queue.mutex);
+	return ret;
+}
+
+static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
+
+	return uvc_queue_poll(&video->queue, file, wait);
+}
+
+struct file_operations uvc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uvc_v4l2_open,
+	.release	= uvc_v4l2_release,
+	.ioctl		= uvc_v4l2_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
+	.llseek		= no_llseek,
+	.read		= uvc_v4l2_read,
+	.mmap		= uvc_v4l2_mmap,
+	.poll		= uvc_v4l2_poll,
+};
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
new file mode 100644
index 0000000..6faf1fb
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -0,0 +1,934 @@
+/*
+ *      uvc_video.c  --  USB Video Class driver - Video handling
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/unaligned.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+			__u8 intfnum, __u8 cs, void *data, __u16 size,
+			int timeout)
+{
+	__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	unsigned int pipe;
+	int ret;
+
+	pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
+			      : usb_sndctrlpipe(dev->udev, 0);
+	type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+
+	ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+			unit << 8 | intfnum, data, size, timeout);
+
+	if (ret != size) {
+		uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
+			"(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
+			size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+			__u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+	return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+				UVC_CTRL_CONTROL_TIMEOUT);
+}
+
+static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+	struct uvc_streaming_control *ctrl)
+{
+	struct uvc_format *format;
+	struct uvc_frame *frame;
+
+	if (ctrl->bFormatIndex <= 0 ||
+	    ctrl->bFormatIndex > video->streaming->nformats)
+		return;
+
+	format = &video->streaming->format[ctrl->bFormatIndex - 1];
+
+	if (ctrl->bFrameIndex <= 0 ||
+	    ctrl->bFrameIndex > format->nframes)
+		return;
+
+	frame = &format->frame[ctrl->bFrameIndex - 1];
+
+	if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+	     (ctrl->dwMaxVideoFrameSize == 0 &&
+	      video->dev->uvc_version < 0x0110))
+		ctrl->dwMaxVideoFrameSize =
+			frame->dwMaxVideoFrameBufferSize;
+}
+
+static int uvc_get_video_ctrl(struct uvc_video_device *video,
+	struct uvc_streaming_control *ctrl, int probe, __u8 query)
+{
+	__u8 data[34];
+	__u8 size;
+	int ret;
+
+	size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+	ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
+		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+		UVC_CTRL_STREAMING_TIMEOUT);
+
+	if (ret < 0)
+		return ret;
+
+	ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
+	ctrl->bFormatIndex = data[2];
+	ctrl->bFrameIndex = data[3];
+	ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
+	ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
+	ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
+	ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
+	ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
+	ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
+	ctrl->dwMaxVideoFrameSize =
+		le32_to_cpu(get_unaligned((__le32 *)&data[18]));
+	ctrl->dwMaxPayloadTransferSize =
+		le32_to_cpu(get_unaligned((__le32 *)&data[22]));
+
+	if (size == 34) {
+		ctrl->dwClockFrequency =
+			le32_to_cpu(get_unaligned((__le32 *)&data[26]));
+		ctrl->bmFramingInfo = data[30];
+		ctrl->bPreferedVersion = data[31];
+		ctrl->bMinVersion = data[32];
+		ctrl->bMaxVersion = data[33];
+	} else {
+		ctrl->dwClockFrequency = video->dev->clock_frequency;
+		ctrl->bmFramingInfo = 0;
+		ctrl->bPreferedVersion = 0;
+		ctrl->bMinVersion = 0;
+		ctrl->bMaxVersion = 0;
+	}
+
+	/* Some broken devices return a null or wrong dwMaxVideoFrameSize.
+	 * Try to get the value from the format and frame descriptor.
+	 */
+	uvc_fixup_buffer_size(video, ctrl);
+
+	return 0;
+}
+
+int uvc_set_video_ctrl(struct uvc_video_device *video,
+	struct uvc_streaming_control *ctrl, int probe)
+{
+	__u8 data[34];
+	__u8 size;
+
+	size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+	memset(data, 0, sizeof data);
+
+	*(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
+	data[2] = ctrl->bFormatIndex;
+	data[3] = ctrl->bFrameIndex;
+	*(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
+	*(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
+	*(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
+	*(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
+	*(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
+	*(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
+	/* Note: Some of the fields below are not required for IN devices (see
+	 * UVC spec, 4.3.1.1), but we still copy them in case support for OUT
+	 * devices is added in the future. */
+	put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize),
+		(__le32 *)&data[18]);
+	put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize),
+		(__le32 *)&data[22]);
+
+	if (size == 34) {
+		put_unaligned(cpu_to_le32(ctrl->dwClockFrequency),
+			(__le32 *)&data[26]);
+		data[30] = ctrl->bmFramingInfo;
+		data[31] = ctrl->bPreferedVersion;
+		data[32] = ctrl->bMinVersion;
+		data[33] = ctrl->bMaxVersion;
+	}
+
+	return __uvc_query_ctrl(video->dev, SET_CUR, 0,
+		video->streaming->intfnum,
+		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+		UVC_CTRL_STREAMING_TIMEOUT);
+}
+
+int uvc_probe_video(struct uvc_video_device *video,
+	struct uvc_streaming_control *probe)
+{
+	struct uvc_streaming_control probe_min, probe_max;
+	__u16 bandwidth;
+	unsigned int i;
+	int ret;
+
+	mutex_lock(&video->streaming->mutex);
+
+	/* Perform probing. The device should adjust the requested values
+	 * according to its capabilities. However, some devices, namely the
+	 * first generation UVC Logitech webcams, don't implement the Video
+	 * Probe control properly, and just return the needed bandwidth. For
+	 * that reason, if the needed bandwidth exceeds the maximum available
+	 * bandwidth, try to lower the quality.
+	 */
+	if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0)
+		goto done;
+
+	/* Get the minimum and maximum values for compression settings. */
+	if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+		ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+		if (ret < 0)
+			goto done;
+		ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+		if (ret < 0)
+			goto done;
+
+		probe->wCompQuality = probe_max.wCompQuality;
+	}
+
+	for (i = 0; i < 2; ++i) {
+		if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
+		    (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+			goto done;
+
+		if (video->streaming->intf->num_altsetting == 1)
+			break;
+
+		bandwidth = probe->dwMaxPayloadTransferSize;
+		if (bandwidth <= video->streaming->maxpsize)
+			break;
+
+		if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+			ret = -ENOSPC;
+			goto done;
+		}
+
+		/* TODO: negotiate compression parameters */
+		probe->wKeyFrameRate = probe_min.wKeyFrameRate;
+		probe->wPFrameRate = probe_min.wPFrameRate;
+		probe->wCompQuality = probe_max.wCompQuality;
+		probe->wCompWindowSize = probe_min.wCompWindowSize;
+	}
+
+done:
+	mutex_unlock(&video->streaming->mutex);
+	return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video codecs
+ */
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH	(1 << 7)
+#define UVC_STREAM_ERR	(1 << 6)
+#define UVC_STREAM_STI	(1 << 5)
+#define UVC_STREAM_RES	(1 << 4)
+#define UVC_STREAM_SCR	(1 << 3)
+#define UVC_STREAM_PTS	(1 << 2)
+#define UVC_STREAM_EOF	(1 << 1)
+#define UVC_STREAM_FID	(1 << 0)
+
+/* Video payload decoding is handled by uvc_video_decode_start(),
+ * uvc_video_decode_data() and uvc_video_decode_end().
+ *
+ * uvc_video_decode_start is called with URB data at the start of a bulk or
+ * isochronous payload. It processes header data and returns the header size
+ * in bytes if successful. If an error occurs, it returns a negative error
+ * code. The following error codes have special meanings.
+ *
+ * - EAGAIN informs the caller that the current video buffer should be marked
+ *   as done, and that the function should be called again with the same data
+ *   and a new video buffer. This is used when end of frame conditions can be
+ *   reliably detected at the beginning of the next frame only.
+ *
+ * If an error other than -EAGAIN is returned, the caller will drop the current
+ * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
+ * made until the next payload. -ENODATA can be used to drop the current
+ * payload if no other error code is appropriate.
+ *
+ * uvc_video_decode_data is called for every URB with URB data. It copies the
+ * data to the video buffer.
+ *
+ * uvc_video_decode_end is called with header data at the end of a bulk or
+ * isochronous payload. It performs any additional header data processing and
+ * returns 0 or a negative error code if an error occured. As header data have
+ * already been processed by uvc_video_decode_start, this functions isn't
+ * required to perform sanity checks a second time.
+ *
+ * For isochronous transfers where a payload is always transfered in a single
+ * URB, the three functions will be called in a row.
+ *
+ * To let the decoder process header data and update its internal state even
+ * when no video buffer is available, uvc_video_decode_start must be prepared
+ * to be called with a NULL buf parameter. uvc_video_decode_data and
+ * uvc_video_decode_end will never be called with a NULL buffer.
+ */
+static int uvc_video_decode_start(struct uvc_video_device *video,
+		struct uvc_buffer *buf, const __u8 *data, int len)
+{
+	__u8 fid;
+
+	/* Sanity checks:
+	 * - packet must be at least 2 bytes long
+	 * - bHeaderLength value must be at least 2 bytes (see above)
+	 * - bHeaderLength value can't be larger than the packet size.
+	 */
+	if (len < 2 || data[0] < 2 || data[0] > len)
+		return -EINVAL;
+
+	/* Skip payloads marked with the error bit ("error frames"). */
+	if (data[1] & UVC_STREAM_ERR) {
+		uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
+			  "set).\n");
+		return -ENODATA;
+	}
+
+	fid = data[1] & UVC_STREAM_FID;
+
+	/* Store the payload FID bit and return immediately when the buffer is
+	 * NULL.
+	 */
+	if (buf == NULL) {
+		video->last_fid = fid;
+		return -ENODATA;
+	}
+
+	/* Synchronize to the input stream by waiting for the FID bit to be
+	 * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
+	 * queue->last_fid is initialized to -1, so the first isochronous
+	 * frame will always be in sync.
+	 *
+	 * If the device doesn't toggle the FID bit, invert video->last_fid
+	 * when the EOF bit is set to force synchronisation on the next packet.
+	 */
+	if (buf->state != UVC_BUF_STATE_ACTIVE) {
+		if (fid == video->last_fid) {
+			uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
+				"sync).\n");
+			if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+			    (data[1] & UVC_STREAM_EOF))
+				video->last_fid ^= UVC_STREAM_FID;
+			return -ENODATA;
+		}
+
+		/* TODO: Handle PTS and SCR. */
+		buf->state = UVC_BUF_STATE_ACTIVE;
+	}
+
+	/* Mark the buffer as done if we're at the beginning of a new frame.
+	 * End of frame detection is better implemented by checking the EOF
+	 * bit (FID bit toggling is delayed by one frame compared to the EOF
+	 * bit), but some devices don't set the bit at end of frame (and the
+	 * last payload can be lost anyway). We thus must check if the FID has
+	 * been toggled.
+	 *
+	 * queue->last_fid is initialized to -1, so the first isochronous
+	 * frame will never trigger an end of frame detection.
+	 *
+	 * Empty buffers (bytesused == 0) don't trigger end of frame detection
+	 * as it doesn't make sense to return an empty buffer. This also
+	 * avoids detecting and of frame conditions at FID toggling if the
+	 * previous payload had the EOF bit set.
+	 */
+	if (fid != video->last_fid && buf->buf.bytesused != 0) {
+		uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
+				"toggled).\n");
+		buf->state = UVC_BUF_STATE_DONE;
+		return -EAGAIN;
+	}
+
+	video->last_fid = fid;
+
+	return data[0];
+}
+
+static void uvc_video_decode_data(struct uvc_video_device *video,
+		struct uvc_buffer *buf, const __u8 *data, int len)
+{
+	struct uvc_video_queue *queue = &video->queue;
+	unsigned int maxlen, nbytes;
+	void *mem;
+
+	if (len <= 0)
+		return;
+
+	/* Copy the video data to the buffer. */
+	maxlen = buf->buf.length - buf->buf.bytesused;
+	mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+	nbytes = min((unsigned int)len, maxlen);
+	memcpy(mem, data, nbytes);
+	buf->buf.bytesused += nbytes;
+
+	/* Complete the current frame if the buffer size was exceeded. */
+	if (len > maxlen) {
+		uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+		buf->state = UVC_BUF_STATE_DONE;
+	}
+}
+
+static void uvc_video_decode_end(struct uvc_video_device *video,
+		struct uvc_buffer *buf, const __u8 *data, int len)
+{
+	/* Mark the buffer as done if the EOF marker is set. */
+	if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+		uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
+		if (data[0] == len)
+			uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
+		buf->state = UVC_BUF_STATE_DONE;
+		if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+			video->last_fid ^= UVC_STREAM_FID;
+	}
+}
+
+/* ------------------------------------------------------------------------
+ * URB handling
+ */
+
+/*
+ * Completion handler for video URBs.
+ */
+static void uvc_video_decode_isoc(struct urb *urb,
+	struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+	u8 *mem;
+	int ret, i;
+
+	for (i = 0; i < urb->number_of_packets; ++i) {
+		if (urb->iso_frame_desc[i].status < 0) {
+			uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+				"lost (%d).\n", urb->iso_frame_desc[i].status);
+			continue;
+		}
+
+		/* Decode the payload header. */
+		mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		do {
+			ret = uvc_video_decode_start(video, buf, mem,
+				urb->iso_frame_desc[i].actual_length);
+			if (ret == -EAGAIN)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		} while (ret == -EAGAIN);
+
+		if (ret < 0)
+			continue;
+
+		/* Decode the payload data. */
+		uvc_video_decode_data(video, buf, mem + ret,
+			urb->iso_frame_desc[i].actual_length - ret);
+
+		/* Process the header again. */
+		uvc_video_decode_end(video, buf, mem, ret);
+
+		if (buf->state == UVC_BUF_STATE_DONE ||
+		    buf->state == UVC_BUF_STATE_ERROR)
+			buf = uvc_queue_next_buffer(&video->queue, buf);
+	}
+}
+
+static void uvc_video_decode_bulk(struct urb *urb,
+	struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+	u8 *mem;
+	int len, ret;
+
+	mem = urb->transfer_buffer;
+	len = urb->actual_length;
+	video->bulk.payload_size += len;
+
+	/* If the URB is the first of its payload, decode and save the
+	 * header.
+	 */
+	if (video->bulk.header_size == 0) {
+		do {
+			ret = uvc_video_decode_start(video, buf, mem, len);
+			if (ret == -EAGAIN)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		} while (ret == -EAGAIN);
+
+		/* If an error occured skip the rest of the payload. */
+		if (ret < 0 || buf == NULL) {
+			video->bulk.skip_payload = 1;
+			return;
+		}
+
+		video->bulk.header_size = ret;
+		memcpy(video->bulk.header, mem, video->bulk.header_size);
+
+		mem += ret;
+		len -= ret;
+	}
+
+	/* The buffer queue might have been cancelled while a bulk transfer
+	 * was in progress, so we can reach here with buf equal to NULL. Make
+	 * sure buf is never dereferenced if NULL.
+	 */
+
+	/* Process video data. */
+	if (!video->bulk.skip_payload && buf != NULL)
+		uvc_video_decode_data(video, buf, mem, len);
+
+	/* Detect the payload end by a URB smaller than the maximum size (or
+	 * a payload size equal to the maximum) and process the header again.
+	 */
+	if (urb->actual_length < urb->transfer_buffer_length ||
+	    video->bulk.payload_size >= video->bulk.max_payload_size) {
+		if (!video->bulk.skip_payload && buf != NULL) {
+			uvc_video_decode_end(video, buf, video->bulk.header,
+				video->bulk.header_size);
+			if (buf->state == UVC_BUF_STATE_DONE ||
+			    buf->state == UVC_BUF_STATE_ERROR)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		}
+
+		video->bulk.header_size = 0;
+		video->bulk.skip_payload = 0;
+		video->bulk.payload_size = 0;
+	}
+}
+
+static void uvc_video_complete(struct urb *urb)
+{
+	struct uvc_video_device *video = urb->context;
+	struct uvc_video_queue *queue = &video->queue;
+	struct uvc_buffer *buf = NULL;
+	unsigned long flags;
+	int ret;
+
+	switch (urb->status) {
+	case 0:
+		break;
+
+	default:
+		uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
+			"completion handler.\n", urb->status);
+
+	case -ENOENT:		/* usb_kill_urb() called. */
+		if (video->frozen)
+			return;
+
+	case -ECONNRESET:	/* usb_unlink_urb() called. */
+	case -ESHUTDOWN:	/* The endpoint is being disabled. */
+		uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+		return;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	if (!list_empty(&queue->irqqueue))
+		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+				       queue);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	video->decode(urb, video, buf);
+
+	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+			ret);
+	}
+}
+
+/*
+ * Uninitialize isochronous/bulk URBs and free transfer buffers.
+ */
+static void uvc_uninit_video(struct uvc_video_device *video)
+{
+	struct urb *urb;
+	unsigned int i;
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		if ((urb = video->urb[i]) == NULL)
+			continue;
+
+		usb_kill_urb(urb);
+		/* urb->transfer_buffer_length is not touched by USB core, so
+		 * we can use it here as the buffer length.
+		 */
+		if (video->urb_buffer[i]) {
+			usb_buffer_free(video->dev->udev,
+				urb->transfer_buffer_length,
+				video->urb_buffer[i], urb->transfer_dma);
+			video->urb_buffer[i] = NULL;
+		}
+
+		usb_free_urb(urb);
+		video->urb[i] = NULL;
+	}
+}
+
+/*
+ * Initialize isochronous URBs and allocate transfer buffers. The packet size
+ * is given by the endpoint.
+ */
+static int uvc_init_video_isoc(struct uvc_video_device *video,
+	struct usb_host_endpoint *ep)
+{
+	struct urb *urb;
+	unsigned int npackets, i, j;
+	__u16 psize;
+	__u32 size;
+
+	/* Compute the number of isochronous packets to allocate by dividing
+	 * the maximum video frame size by the packet size. Limit the result
+	 * to UVC_MAX_ISO_PACKETS.
+	 */
+	psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+	psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+
+	size = video->streaming->ctrl.dwMaxVideoFrameSize;
+	if (size > UVC_MAX_FRAME_SIZE)
+		return -EINVAL;
+
+	npackets = (size + psize - 1) / psize;
+	if (npackets > UVC_MAX_ISO_PACKETS)
+		npackets = UVC_MAX_ISO_PACKETS;
+
+	size = npackets * psize;
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		urb = usb_alloc_urb(npackets, GFP_KERNEL);
+		if (urb == NULL) {
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+			size, GFP_KERNEL, &urb->transfer_dma);
+		if (video->urb_buffer[i] == NULL) {
+			usb_free_urb(urb);
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		urb->dev = video->dev->udev;
+		urb->context = video;
+		urb->pipe = usb_rcvisocpipe(video->dev->udev,
+				ep->desc.bEndpointAddress);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = ep->desc.bInterval;
+		urb->transfer_buffer = video->urb_buffer[i];
+		urb->complete = uvc_video_complete;
+		urb->number_of_packets = npackets;
+		urb->transfer_buffer_length = size;
+
+		for (j = 0; j < npackets; ++j) {
+			urb->iso_frame_desc[j].offset = j * psize;
+			urb->iso_frame_desc[j].length = psize;
+		}
+
+		video->urb[i] = urb;
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize bulk URBs and allocate transfer buffers. The packet size is
+ * given by the endpoint.
+ */
+static int uvc_init_video_bulk(struct uvc_video_device *video,
+	struct usb_host_endpoint *ep)
+{
+	struct urb *urb;
+	unsigned int pipe, i;
+	__u16 psize;
+	__u32 size;
+
+	/* Compute the bulk URB size. Some devices set the maximum payload
+	 * size to a value too high for memory-constrained devices. We must
+	 * then transfer the payload accross multiple URBs. To be consistant
+	 * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
+	 * URB.
+	 */
+	psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
+	size = video->streaming->ctrl.dwMaxPayloadTransferSize;
+	video->bulk.max_payload_size = size;
+	if (size > psize * UVC_MAX_ISO_PACKETS)
+		size = psize * UVC_MAX_ISO_PACKETS;
+
+	pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (urb == NULL) {
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+			size, GFP_KERNEL, &urb->transfer_dma);
+		if (video->urb_buffer[i] == NULL) {
+			usb_free_urb(urb);
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		usb_fill_bulk_urb(urb, video->dev->udev, pipe,
+			video->urb_buffer[i], size, uvc_video_complete,
+			video);
+		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+
+		video->urb[i] = urb;
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize isochronous/bulk URBs and allocate transfer buffers.
+ */
+static int uvc_init_video(struct uvc_video_device *video)
+{
+	struct usb_interface *intf = video->streaming->intf;
+	struct usb_host_interface *alts;
+	struct usb_host_endpoint *ep = NULL;
+	int intfnum = video->streaming->intfnum;
+	unsigned int bandwidth, psize, i;
+	int ret;
+
+	video->last_fid = -1;
+	video->bulk.header_size = 0;
+	video->bulk.skip_payload = 0;
+	video->bulk.payload_size = 0;
+
+	if (intf->num_altsetting > 1) {
+		/* Isochronous endpoint, select the alternate setting. */
+		bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize;
+
+		if (bandwidth == 0) {
+			uvc_printk(KERN_WARNING, "device %s requested null "
+				"bandwidth, defaulting to lowest.\n",
+				video->vdev->name);
+			bandwidth = 1;
+		}
+
+		for (i = 0; i < intf->num_altsetting; ++i) {
+			alts = &intf->altsetting[i];
+			ep = uvc_find_endpoint(alts,
+				video->streaming->header.bEndpointAddress);
+			if (ep == NULL)
+				continue;
+
+			/* Check if the bandwidth is high enough. */
+			psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+			psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+			if (psize >= bandwidth)
+				break;
+		}
+
+		if (i >= intf->num_altsetting)
+			return -EIO;
+
+		if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
+			return ret;
+
+		ret = uvc_init_video_isoc(video, ep);
+	} else {
+		/* Bulk endpoint, proceed to URB initialization. */
+		ep = uvc_find_endpoint(&intf->altsetting[0],
+				video->streaming->header.bEndpointAddress);
+		if (ep == NULL)
+			return -EIO;
+
+		ret = uvc_init_video_bulk(video, ep);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	/* Submit the URBs. */
+	for (i = 0; i < UVC_URBS; ++i) {
+		if ((ret = usb_submit_urb(video->urb[i], GFP_KERNEL)) < 0) {
+			uvc_printk(KERN_ERR, "Failed to submit URB %u "
+					"(%d).\n", i, ret);
+			uvc_uninit_video(video);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Stop streaming without disabling the video queue.
+ *
+ * To let userspace applications resume without trouble, we must not touch the
+ * video buffers in any way. We mark the device as frozen to make sure the URB
+ * completion handler won't try to cancel the queue when we kill the URBs.
+ */
+int uvc_video_suspend(struct uvc_video_device *video)
+{
+	if (!uvc_queue_streaming(&video->queue))
+		return 0;
+
+	video->frozen = 1;
+	uvc_uninit_video(video);
+	usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+	return 0;
+}
+
+/*
+ * Reconfigure the video interface and restart streaming if it was enable
+ * before suspend.
+ *
+ * If an error occurs, disable the video queue. This will wake all pending
+ * buffers, making sure userspace applications are notified of the problem
+ * instead of waiting forever.
+ */
+int uvc_video_resume(struct uvc_video_device *video)
+{
+	int ret;
+
+	video->frozen = 0;
+
+	if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) {
+		uvc_queue_enable(&video->queue, 0);
+		return ret;
+	}
+
+	if (!uvc_queue_streaming(&video->queue))
+		return 0;
+
+	if ((ret = uvc_init_video(video)) < 0)
+		uvc_queue_enable(&video->queue, 0);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device
+ */
+
+/*
+ * Initialize the UVC video device by retrieving the default format and
+ * committing it.
+ *
+ * Some cameras (namely the Fuji Finepix) set the format and frame
+ * indexes to zero. The UVC standard doesn't clearly make this a spec
+ * violation, so try to silently fix the values if possible.
+ *
+ * This function is called before registering the device with V4L.
+ */
+int uvc_video_init(struct uvc_video_device *video)
+{
+	struct uvc_streaming_control *probe = &video->streaming->ctrl;
+	struct uvc_format *format = NULL;
+	struct uvc_frame *frame = NULL;
+	unsigned int i;
+	int ret;
+
+	if (video->streaming->nformats == 0) {
+		uvc_printk(KERN_INFO, "No supported video formats found.\n");
+		return -EINVAL;
+	}
+
+	/* Alternate setting 0 should be the default, yet the XBox Live Vision
+	 * Cam (and possibly other devices) crash or otherwise misbehave if
+	 * they don't receive a SET_INTERFACE request before any other video
+	 * control request.
+	 */
+	usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+
+	/* Some webcams don't suport GET_DEF request on the probe control. We
+	 * fall back to GET_CUR if GET_DEF fails.
+	 */
+	if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
+	    (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+		return ret;
+
+	/* Check if the default format descriptor exists. Use the first
+	 * available format otherwise.
+	 */
+	for (i = video->streaming->nformats; i > 0; --i) {
+		format = &video->streaming->format[i-1];
+		if (format->index == probe->bFormatIndex)
+			break;
+	}
+
+	if (format->nframes == 0) {
+		uvc_printk(KERN_INFO, "No frame descriptor found for the "
+			"default format.\n");
+		return -EINVAL;
+	}
+
+	/* Zero bFrameIndex might be correct. Stream-based formats (including
+	 * MPEG-2 TS and DV) do not support frames but have a dummy frame
+	 * descriptor with bFrameIndex set to zero. If the default frame
+	 * descriptor is not found, use the first avalable frame.
+	 */
+	for (i = format->nframes; i > 0; --i) {
+		frame = &format->frame[i-1];
+		if (frame->bFrameIndex == probe->bFrameIndex)
+			break;
+	}
+
+	/* Commit the default settings. */
+	probe->bFormatIndex = format->index;
+	probe->bFrameIndex = frame->bFrameIndex;
+	if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
+		return ret;
+
+	video->streaming->cur_format = format;
+	video->streaming->cur_frame = frame;
+	atomic_set(&video->active, 0);
+
+	/* Select the video decoding function */
+	if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+		video->decode = uvc_video_decode_isight;
+	else if (video->streaming->intf->num_altsetting > 1)
+		video->decode = uvc_video_decode_isoc;
+	else
+		video->decode = uvc_video_decode_bulk;
+
+	return 0;
+}
+
+/*
+ * Enable or disable the video stream.
+ */
+int uvc_video_enable(struct uvc_video_device *video, int enable)
+{
+	int ret;
+
+	if (!enable) {
+		uvc_uninit_video(video);
+		usb_set_interface(video->dev->udev,
+			video->streaming->intfnum, 0);
+		uvc_queue_enable(&video->queue, 0);
+		return 0;
+	}
+
+	if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+		return ret;
+
+	return uvc_init_video(video);
+}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
new file mode 100644
index 0000000..a995a78
--- /dev/null
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -0,0 +1,796 @@
+#ifndef _USB_VIDEO_H_
+#define _USB_VIDEO_H_
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+
+/*
+ * Dynamic controls
+ */
+
+/* Data types for UVC control data */
+#define UVC_CTRL_DATA_TYPE_RAW		0
+#define UVC_CTRL_DATA_TYPE_SIGNED	1
+#define UVC_CTRL_DATA_TYPE_UNSIGNED	2
+#define UVC_CTRL_DATA_TYPE_BOOLEAN	3
+#define UVC_CTRL_DATA_TYPE_ENUM		4
+#define UVC_CTRL_DATA_TYPE_BITMASK	5
+
+/* Control flags */
+#define UVC_CONTROL_SET_CUR	(1 << 0)
+#define UVC_CONTROL_GET_CUR	(1 << 1)
+#define UVC_CONTROL_GET_MIN	(1 << 2)
+#define UVC_CONTROL_GET_MAX	(1 << 3)
+#define UVC_CONTROL_GET_RES	(1 << 4)
+#define UVC_CONTROL_GET_DEF	(1 << 5)
+/* Control should be saved at suspend and restored at resume. */
+#define UVC_CONTROL_RESTORE	(1 << 6)
+/* Control can be updated by the camera. */
+#define UVC_CONTROL_AUTO_UPDATE	(1 << 7)
+
+#define UVC_CONTROL_GET_RANGE	(UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
+				 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
+				 UVC_CONTROL_GET_DEF)
+
+struct uvc_xu_control_info {
+	__u8 entity[16];
+	__u8 index;
+	__u8 selector;
+	__u16 size;
+	__u32 flags;
+};
+
+struct uvc_xu_control_mapping {
+	__u32 id;
+	__u8 name[32];
+	__u8 entity[16];
+	__u8 selector;
+
+	__u8 size;
+	__u8 offset;
+	enum v4l2_ctrl_type v4l2_type;
+	__u32 data_type;
+};
+
+struct uvc_xu_control {
+	__u8 unit;
+	__u8 selector;
+	__u16 size;
+	__u8 __user *data;
+};
+
+#define UVCIOC_CTRL_ADD		_IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP		_IOWR('U', 2, struct uvc_xu_control_mapping)
+#define UVCIOC_CTRL_GET		_IOWR('U', 3, struct uvc_xu_control)
+#define UVCIOC_CTRL_SET		_IOW('U', 4, struct uvc_xu_control)
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+#define SC_UNDEFINED                    0x00
+#define SC_VIDEOCONTROL                 0x01
+#define SC_VIDEOSTREAMING               0x02
+#define SC_VIDEO_INTERFACE_COLLECTION   0x03
+
+#define PC_PROTOCOL_UNDEFINED           0x00
+
+#define CS_UNDEFINED                    0x20
+#define CS_DEVICE                       0x21
+#define CS_CONFIGURATION                0x22
+#define CS_STRING                       0x23
+#define CS_INTERFACE                    0x24
+#define CS_ENDPOINT                     0x25
+
+/* VideoControl class specific interface descriptor */
+#define VC_DESCRIPTOR_UNDEFINED         0x00
+#define VC_HEADER                       0x01
+#define VC_INPUT_TERMINAL               0x02
+#define VC_OUTPUT_TERMINAL              0x03
+#define VC_SELECTOR_UNIT                0x04
+#define VC_PROCESSING_UNIT              0x05
+#define VC_EXTENSION_UNIT               0x06
+
+/* VideoStreaming class specific interface descriptor */
+#define VS_UNDEFINED                    0x00
+#define VS_INPUT_HEADER                 0x01
+#define VS_OUTPUT_HEADER                0x02
+#define VS_STILL_IMAGE_FRAME            0x03
+#define VS_FORMAT_UNCOMPRESSED          0x04
+#define VS_FRAME_UNCOMPRESSED           0x05
+#define VS_FORMAT_MJPEG                 0x06
+#define VS_FRAME_MJPEG                  0x07
+#define VS_FORMAT_MPEG2TS               0x0a
+#define VS_FORMAT_DV                    0x0c
+#define VS_COLORFORMAT                  0x0d
+#define VS_FORMAT_FRAME_BASED           0x10
+#define VS_FRAME_FRAME_BASED            0x11
+#define VS_FORMAT_STREAM_BASED          0x12
+
+/* Endpoint type */
+#define EP_UNDEFINED                    0x00
+#define EP_GENERAL                      0x01
+#define EP_ENDPOINT                     0x02
+#define EP_INTERRUPT                    0x03
+
+/* Request codes */
+#define RC_UNDEFINED                    0x00
+#define SET_CUR                         0x01
+#define GET_CUR                         0x81
+#define GET_MIN                         0x82
+#define GET_MAX                         0x83
+#define GET_RES                         0x84
+#define GET_LEN                         0x85
+#define GET_INFO                        0x86
+#define GET_DEF                         0x87
+
+/* VideoControl interface controls */
+#define VC_CONTROL_UNDEFINED            0x00
+#define VC_VIDEO_POWER_MODE_CONTROL     0x01
+#define VC_REQUEST_ERROR_CODE_CONTROL   0x02
+
+/* Terminal controls */
+#define TE_CONTROL_UNDEFINED            0x00
+
+/* Selector Unit controls */
+#define SU_CONTROL_UNDEFINED            0x00
+#define SU_INPUT_SELECT_CONTROL         0x01
+
+/* Camera Terminal controls */
+#define CT_CONTROL_UNDEFINED            		0x00
+#define CT_SCANNING_MODE_CONTROL        		0x01
+#define CT_AE_MODE_CONTROL              		0x02
+#define CT_AE_PRIORITY_CONTROL          		0x03
+#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL               0x04
+#define CT_EXPOSURE_TIME_RELATIVE_CONTROL               0x05
+#define CT_FOCUS_ABSOLUTE_CONTROL       		0x06
+#define CT_FOCUS_RELATIVE_CONTROL       		0x07
+#define CT_FOCUS_AUTO_CONTROL           		0x08
+#define CT_IRIS_ABSOLUTE_CONTROL        		0x09
+#define CT_IRIS_RELATIVE_CONTROL        		0x0a
+#define CT_ZOOM_ABSOLUTE_CONTROL        		0x0b
+#define CT_ZOOM_RELATIVE_CONTROL        		0x0c
+#define CT_PANTILT_ABSOLUTE_CONTROL     		0x0d
+#define CT_PANTILT_RELATIVE_CONTROL     		0x0e
+#define CT_ROLL_ABSOLUTE_CONTROL        		0x0f
+#define CT_ROLL_RELATIVE_CONTROL        		0x10
+#define CT_PRIVACY_CONTROL              		0x11
+
+/* Processing Unit controls */
+#define PU_CONTROL_UNDEFINED            		0x00
+#define PU_BACKLIGHT_COMPENSATION_CONTROL               0x01
+#define PU_BRIGHTNESS_CONTROL           		0x02
+#define PU_CONTRAST_CONTROL             		0x03
+#define PU_GAIN_CONTROL                 		0x04
+#define PU_POWER_LINE_FREQUENCY_CONTROL 		0x05
+#define PU_HUE_CONTROL                  		0x06
+#define PU_SATURATION_CONTROL           		0x07
+#define PU_SHARPNESS_CONTROL            		0x08
+#define PU_GAMMA_CONTROL                		0x09
+#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL            0x0a
+#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL       0x0b
+#define PU_WHITE_BALANCE_COMPONENT_CONTROL              0x0c
+#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL         0x0d
+#define PU_DIGITAL_MULTIPLIER_CONTROL   		0x0e
+#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL             0x0f
+#define PU_HUE_AUTO_CONTROL             		0x10
+#define PU_ANALOG_VIDEO_STANDARD_CONTROL                0x11
+#define PU_ANALOG_LOCK_STATUS_CONTROL   		0x12
+
+#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL		0x01
+#define LXU_MOTOR_PANTILT_RESET_CONTROL			0x02
+#define LXU_MOTOR_FOCUS_MOTOR_CONTROL			0x03
+
+/* VideoStreaming interface controls */
+#define VS_CONTROL_UNDEFINED            0x00
+#define VS_PROBE_CONTROL                0x01
+#define VS_COMMIT_CONTROL               0x02
+#define VS_STILL_PROBE_CONTROL          0x03
+#define VS_STILL_COMMIT_CONTROL         0x04
+#define VS_STILL_IMAGE_TRIGGER_CONTROL  0x05
+#define VS_STREAM_ERROR_CODE_CONTROL    0x06
+#define VS_GENERATE_KEY_FRAME_CONTROL   0x07
+#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
+#define VS_SYNC_DELAY_CONTROL           0x09
+
+#define TT_VENDOR_SPECIFIC              0x0100
+#define TT_STREAMING                    0x0101
+
+/* Input Terminal types */
+#define ITT_VENDOR_SPECIFIC             0x0200
+#define ITT_CAMERA                      0x0201
+#define ITT_MEDIA_TRANSPORT_INPUT       0x0202
+
+/* Output Terminal types */
+#define OTT_VENDOR_SPECIFIC             0x0300
+#define OTT_DISPLAY                     0x0301
+#define OTT_MEDIA_TRANSPORT_OUTPUT      0x0302
+
+/* External Terminal types */
+#define EXTERNAL_VENDOR_SPECIFIC        0x0400
+#define COMPOSITE_CONNECTOR             0x0401
+#define SVIDEO_CONNECTOR                0x0402
+#define COMPONENT_CONNECTOR             0x0403
+
+#define UVC_TERM_INPUT			0x0000
+#define UVC_TERM_OUTPUT			0x8000
+
+#define UVC_ENTITY_TYPE(entity)		((entity)->type & 0x7fff)
+#define UVC_ENTITY_IS_UNIT(entity)	(((entity)->type & 0xff00) == 0)
+#define UVC_ENTITY_IS_TERM(entity)	(((entity)->type & 0xff00) != 0)
+#define UVC_ENTITY_IS_ITERM(entity) \
+	(((entity)->type & 0x8000) == UVC_TERM_INPUT)
+#define UVC_ENTITY_IS_OTERM(entity) \
+	(((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+
+#define UVC_STATUS_TYPE_CONTROL		1
+#define UVC_STATUS_TYPE_STREAMING	2
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+
+#define UVC_GUID_LOGITECH_DEV_INFO \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
+#define UVC_GUID_LOGITECH_USER_HW \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
+#define UVC_GUID_LOGITECH_VIDEO \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
+#define UVC_GUID_LOGITECH_MOTOR \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
+
+#define UVC_GUID_FORMAT_MJPEG \
+	{ 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+	{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+	{ 'N',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+	{ 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+	{ 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+	{ 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+	{ 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+	{ 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+
+/* ------------------------------------------------------------------------
+ * Driver specific constants.
+ */
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(0, 1, 0)
+
+/* Number of isochronous URBs. */
+#define UVC_URBS		5
+/* Maximum number of packets per isochronous URB. */
+#define UVC_MAX_ISO_PACKETS	40
+/* Maximum frame size in bytes, for sanity checking. */
+#define UVC_MAX_FRAME_SIZE	(16*1024*1024)
+/* Maximum number of video buffers. */
+#define UVC_MAX_VIDEO_BUFFERS	32
+
+#define UVC_CTRL_CONTROL_TIMEOUT	300
+#define UVC_CTRL_STREAMING_TIMEOUT	1000
+
+/* Devices quirks */
+#define UVC_QUIRK_STATUS_INTERVAL	0x00000001
+#define UVC_QUIRK_PROBE_MINMAX		0x00000002
+#define UVC_QUIRK_PROBE_EXTRAFIELDS	0x00000004
+#define UVC_QUIRK_BUILTIN_ISIGHT	0x00000008
+#define UVC_QUIRK_STREAM_NO_FID		0x00000010
+#define UVC_QUIRK_IGNORE_SELECTOR_UNIT	0x00000020
+
+/* Format flags */
+#define UVC_FMT_FLAG_COMPRESSED		0x00000001
+#define UVC_FMT_FLAG_STREAM		0x00000002
+
+/* ------------------------------------------------------------------------
+ * Structures.
+ */
+
+struct uvc_device;
+
+/* TODO: Put the most frequently accessed fields at the beginning of
+ * structures to maximize cache efficiency.
+ */
+struct uvc_streaming_control {
+	__u16 bmHint;
+	__u8  bFormatIndex;
+	__u8  bFrameIndex;
+	__u32 dwFrameInterval;
+	__u16 wKeyFrameRate;
+	__u16 wPFrameRate;
+	__u16 wCompQuality;
+	__u16 wCompWindowSize;
+	__u16 wDelay;
+	__u32 dwMaxVideoFrameSize;
+	__u32 dwMaxPayloadTransferSize;
+	__u32 dwClockFrequency;
+	__u8  bmFramingInfo;
+	__u8  bPreferedVersion;
+	__u8  bMinVersion;
+	__u8  bMaxVersion;
+};
+
+struct uvc_menu_info {
+	__u32 value;
+	__u8 name[32];
+};
+
+struct uvc_control_info {
+	struct list_head list;
+	struct list_head mappings;
+
+	__u8 entity[16];
+	__u8 index;
+	__u8 selector;
+
+	__u16 size;
+	__u32 flags;
+};
+
+struct uvc_control_mapping {
+	struct list_head list;
+
+	struct uvc_control_info *ctrl;
+
+	__u32 id;
+	__u8 name[32];
+	__u8 entity[16];
+	__u8 selector;
+
+	__u8 size;
+	__u8 offset;
+	enum v4l2_ctrl_type v4l2_type;
+	__u32 data_type;
+
+	struct uvc_menu_info *menu_info;
+	__u32 menu_count;
+};
+
+struct uvc_control {
+	struct uvc_entity *entity;
+	struct uvc_control_info *info;
+
+	__u8 index;	/* Used to match the uvc_control entry with a
+			   uvc_control_info. */
+	__u8 dirty : 1,
+	     loaded : 1,
+	     modified : 1;
+
+	__u8 *data;
+};
+
+struct uvc_format_desc {
+	char *name;
+	__u8 guid[16];
+	__u32 fcc;
+};
+
+/* The term 'entity' refers to both UVC units and UVC terminals.
+ *
+ * The type field is either the terminal type (wTerminalType in the terminal
+ * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
+ * As the bDescriptorSubtype field is one byte long, the type value will
+ * always have a null MSB for units. All terminal types defined by the UVC
+ * specification have a non-null MSB, so it is safe to use the MSB to
+ * differentiate between units and terminals as long as the descriptor parsing
+ * code makes sure terminal types have a non-null MSB.
+ *
+ * For terminals, the type's most significant bit stores the terminal
+ * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
+ * always be accessed with the UVC_ENTITY_* macros and never directly.
+ */
+
+struct uvc_entity {
+	struct list_head list;		/* Entity as part of a UVC device. */
+	struct list_head chain;		/* Entity as part of a video device
+					 * chain. */
+	__u8 id;
+	__u16 type;
+	char name[64];
+
+	union {
+		struct {
+			__u16 wObjectiveFocalLengthMin;
+			__u16 wObjectiveFocalLengthMax;
+			__u16 wOcularFocalLength;
+			__u8  bControlSize;
+			__u8  *bmControls;
+		} camera;
+
+		struct {
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  bTransportModeSize;
+			__u8  *bmTransportModes;
+		} media;
+
+		struct {
+			__u8  bSourceID;
+		} output;
+
+		struct {
+			__u8  bSourceID;
+			__u16 wMaxMultiplier;
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  bmVideoStandards;
+		} processing;
+
+		struct {
+			__u8  bNrInPins;
+			__u8  *baSourceID;
+		} selector;
+
+		struct {
+			__u8  guidExtensionCode[16];
+			__u8  bNumControls;
+			__u8  bNrInPins;
+			__u8  *baSourceID;
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  *bmControlsType;
+		} extension;
+	};
+
+	unsigned int ncontrols;
+	struct uvc_control *controls;
+};
+
+struct uvc_frame {
+	__u8  bFrameIndex;
+	__u8  bmCapabilities;
+	__u16 wWidth;
+	__u16 wHeight;
+	__u32 dwMinBitRate;
+	__u32 dwMaxBitRate;
+	__u32 dwMaxVideoFrameBufferSize;
+	__u8  bFrameIntervalType;
+	__u32 dwDefaultFrameInterval;
+	__u32 *dwFrameInterval;
+};
+
+struct uvc_format {
+	__u8 type;
+	__u8 index;
+	__u8 bpp;
+	__u8 colorspace;
+	__u32 fcc;
+	__u32 flags;
+
+	char name[32];
+
+	unsigned int nframes;
+	struct uvc_frame *frame;
+};
+
+struct uvc_streaming_header {
+	__u8 bNumFormats;
+	__u8 bEndpointAddress;
+	__u8 bTerminalLink;
+	__u8 bControlSize;
+	__u8 *bmaControls;
+	/* The following fields are used by input headers only. */
+	__u8 bmInfo;
+	__u8 bStillCaptureMethod;
+	__u8 bTriggerSupport;
+	__u8 bTriggerUsage;
+};
+
+struct uvc_streaming {
+	struct list_head list;
+
+	struct usb_interface *intf;
+	int intfnum;
+	__u16 maxpsize;
+
+	struct uvc_streaming_header header;
+
+	unsigned int nformats;
+	struct uvc_format *format;
+
+	struct uvc_streaming_control ctrl;
+	struct uvc_format *cur_format;
+	struct uvc_frame *cur_frame;
+
+	struct mutex mutex;
+};
+
+enum uvc_buffer_state {
+	UVC_BUF_STATE_IDLE       = 0,
+	UVC_BUF_STATE_QUEUED     = 1,
+	UVC_BUF_STATE_ACTIVE     = 2,
+	UVC_BUF_STATE_DONE       = 3,
+	UVC_BUF_STATE_ERROR      = 4,
+};
+
+struct uvc_buffer {
+	unsigned long vma_use_count;
+	struct list_head stream;
+
+	/* Touched by interrupt handler. */
+	struct v4l2_buffer buf;
+	struct list_head queue;
+	wait_queue_head_t wait;
+	enum uvc_buffer_state state;
+};
+
+#define UVC_QUEUE_STREAMING		(1 << 0)
+#define UVC_QUEUE_DISCONNECTED		(1 << 1)
+#define UVC_QUEUE_DROP_INCOMPLETE	(1 << 2)
+
+struct uvc_video_queue {
+	void *mem;
+	unsigned int flags;
+	__u32 sequence;
+
+	unsigned int count;
+	unsigned int buf_size;
+	struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
+	struct mutex mutex;	/* protects buffers and mainqueue */
+	spinlock_t irqlock;	/* protects irqqueue */
+
+	struct list_head mainqueue;
+	struct list_head irqqueue;
+};
+
+struct uvc_video_device {
+	struct uvc_device *dev;
+	struct video_device *vdev;
+	atomic_t active;
+	unsigned int frozen : 1;
+
+	struct list_head iterms;
+	struct uvc_entity *oterm;
+	struct uvc_entity *processing;
+	struct uvc_entity *selector;
+	struct list_head extensions;
+	struct mutex ctrl_mutex;
+
+	struct uvc_video_queue queue;
+
+	/* Video streaming object, must always be non-NULL. */
+	struct uvc_streaming *streaming;
+
+	void (*decode) (struct urb *urb, struct uvc_video_device *video,
+			struct uvc_buffer *buf);
+
+	/* Context data used by the bulk completion handler. */
+	struct {
+		__u8 header[256];
+		unsigned int header_size;
+		int skip_payload;
+		__u32 payload_size;
+		__u32 max_payload_size;
+	} bulk;
+
+	struct urb *urb[UVC_URBS];
+	char *urb_buffer[UVC_URBS];
+
+	__u8 last_fid;
+};
+
+enum uvc_device_state {
+	UVC_DEV_DISCONNECTED = 1,
+};
+
+struct uvc_device {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	__u32 quirks;
+	int intfnum;
+	char name[32];
+
+	enum uvc_device_state state;
+	struct kref kref;
+	struct list_head list;
+
+	/* Video control interface */
+	__u16 uvc_version;
+	__u32 clock_frequency;
+
+	struct list_head entities;
+
+	struct uvc_video_device video;
+
+	/* Status Interrupt Endpoint */
+	struct usb_host_endpoint *int_ep;
+	struct urb *int_urb;
+	__u8 status[16];
+	struct input_dev *input;
+
+	/* Video Streaming interfaces */
+	struct list_head streaming;
+};
+
+enum uvc_handle_state {
+	UVC_HANDLE_PASSIVE	= 0,
+	UVC_HANDLE_ACTIVE	= 1,
+};
+
+struct uvc_fh {
+	struct uvc_video_device *device;
+	enum uvc_handle_state state;
+};
+
+struct uvc_driver {
+	struct usb_driver driver;
+
+	struct mutex open_mutex;	/* protects from open/disconnect race */
+
+	struct list_head devices;	/* struct uvc_device list */
+	struct list_head controls;	/* struct uvc_control_info list */
+	struct mutex ctrl_mutex;	/* protects controls and devices
+					   lists */
+};
+
+/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+#define UVC_TRACE_PROBE		(1 << 0)
+#define UVC_TRACE_DESCR		(1 << 1)
+#define UVC_TRACE_CONTROL	(1 << 2)
+#define UVC_TRACE_FORMAT	(1 << 3)
+#define UVC_TRACE_CAPTURE	(1 << 4)
+#define UVC_TRACE_CALLS		(1 << 5)
+#define UVC_TRACE_IOCTL		(1 << 6)
+#define UVC_TRACE_FRAME		(1 << 7)
+#define UVC_TRACE_SUSPEND	(1 << 8)
+#define UVC_TRACE_STATUS	(1 << 9)
+
+extern unsigned int uvc_trace_param;
+
+#define uvc_trace(flag, msg...) \
+	do { \
+		if (uvc_trace_param & flag) \
+			printk(KERN_DEBUG "uvcvideo: " msg); \
+	} while (0)
+
+#define uvc_printk(level, msg...) \
+	printk(level "uvcvideo: " msg)
+
+#define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
+			"%02x%02x%02x%02x%02x%02x"
+#define UVC_GUID_ARGS(guid) \
+	(guid)[3],  (guid)[2],  (guid)[1],  (guid)[0], \
+	(guid)[5],  (guid)[4], \
+	(guid)[7],  (guid)[6], \
+	(guid)[8],  (guid)[9], \
+	(guid)[10], (guid)[11], (guid)[12], \
+	(guid)[13], (guid)[14], (guid)[15]
+
+/* --------------------------------------------------------------------------
+ * Internal functions.
+ */
+
+/* Core driver */
+extern struct uvc_driver uvc_driver;
+extern void uvc_delete(struct kref *kref);
+
+/* Video buffers queue management. */
+extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
+		unsigned int nbuffers, unsigned int buflength);
+extern int uvc_free_buffers(struct uvc_video_queue *queue);
+extern int uvc_query_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf);
+extern int uvc_queue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf);
+extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf, int nonblocking);
+extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+		struct uvc_buffer *buf);
+extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+		struct file *file, poll_table *wait);
+static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
+{
+	return queue->flags & UVC_QUEUE_STREAMING;
+}
+
+/* V4L2 interface */
+extern struct file_operations uvc_fops;
+
+/* Video */
+extern int uvc_video_init(struct uvc_video_device *video);
+extern int uvc_video_suspend(struct uvc_video_device *video);
+extern int uvc_video_resume(struct uvc_video_device *video);
+extern int uvc_video_enable(struct uvc_video_device *video, int enable);
+extern int uvc_probe_video(struct uvc_video_device *video,
+		struct uvc_streaming_control *probe);
+extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+		__u8 intfnum, __u8 cs, void *data, __u16 size);
+extern int uvc_set_video_ctrl(struct uvc_video_device *video,
+		struct uvc_streaming_control *ctrl, int probe);
+
+/* Status */
+extern int uvc_status_init(struct uvc_device *dev);
+extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_suspend(struct uvc_device *dev);
+extern int uvc_status_resume(struct uvc_device *dev);
+
+/* Controls */
+extern struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+		__u32 v4l2_id, struct uvc_control_mapping **mapping);
+extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+		struct v4l2_queryctrl *v4l2_ctrl);
+
+extern int uvc_ctrl_add_info(struct uvc_control_info *info);
+extern int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_init_device(struct uvc_device *dev);
+extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
+extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern void uvc_ctrl_init(void);
+
+extern int uvc_ctrl_begin(struct uvc_video_device *video);
+extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback);
+static inline int uvc_ctrl_commit(struct uvc_video_device *video)
+{
+	return __uvc_ctrl_commit(video, 0);
+}
+static inline int uvc_ctrl_rollback(struct uvc_video_device *video)
+{
+	return __uvc_ctrl_commit(video, 1);
+}
+
+extern int uvc_ctrl_get(struct uvc_video_device *video,
+		struct v4l2_ext_control *xctrl);
+extern int uvc_ctrl_set(struct uvc_video_device *video,
+		struct v4l2_ext_control *xctrl);
+
+extern int uvc_xu_ctrl_query(struct uvc_video_device *video,
+		struct uvc_xu_control *ctrl, int set);
+
+/* Utility functions */
+extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+		unsigned int n_terms, unsigned int threshold);
+extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
+		uint32_t denominator);
+extern struct usb_host_endpoint *uvc_find_endpoint(
+		struct usb_host_interface *alts, __u8 epaddr);
+
+/* Quirks support */
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+		struct uvc_buffer *buf);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 31e8af0..67a661c 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -51,12 +51,51 @@
 #define VIDEO_NUM_DEVICES	256
 #define VIDEO_NAME              "video4linux"
 
+struct std_descr {
+	v4l2_std_id std;
+	const char *descr;
+};
+
+static const struct std_descr standards[] = {
+	{ V4L2_STD_NTSC, 	"NTSC"      },
+	{ V4L2_STD_NTSC_M, 	"NTSC-M"    },
+	{ V4L2_STD_NTSC_M_JP, 	"NTSC-M-JP" },
+	{ V4L2_STD_NTSC_M_KR,	"NTSC-M-KR" },
+	{ V4L2_STD_NTSC_443, 	"NTSC-443"  },
+	{ V4L2_STD_PAL, 	"PAL"       },
+	{ V4L2_STD_PAL_BG, 	"PAL-BG"    },
+	{ V4L2_STD_PAL_B, 	"PAL-B"     },
+	{ V4L2_STD_PAL_B1, 	"PAL-B1"    },
+	{ V4L2_STD_PAL_G, 	"PAL-G"     },
+	{ V4L2_STD_PAL_H, 	"PAL-H"     },
+	{ V4L2_STD_PAL_I, 	"PAL-I"     },
+	{ V4L2_STD_PAL_DK, 	"PAL-DK"    },
+	{ V4L2_STD_PAL_D, 	"PAL-D"     },
+	{ V4L2_STD_PAL_D1, 	"PAL-D1"    },
+	{ V4L2_STD_PAL_K, 	"PAL-K"     },
+	{ V4L2_STD_PAL_M, 	"PAL-M"     },
+	{ V4L2_STD_PAL_N, 	"PAL-N"     },
+	{ V4L2_STD_PAL_Nc, 	"PAL-Nc"    },
+	{ V4L2_STD_PAL_60, 	"PAL-60"    },
+	{ V4L2_STD_SECAM, 	"SECAM"     },
+	{ V4L2_STD_SECAM_B, 	"SECAM-B"   },
+	{ V4L2_STD_SECAM_G, 	"SECAM-G"   },
+	{ V4L2_STD_SECAM_H, 	"SECAM-H"   },
+	{ V4L2_STD_SECAM_DK, 	"SECAM-DK"  },
+	{ V4L2_STD_SECAM_D, 	"SECAM-D"   },
+	{ V4L2_STD_SECAM_K, 	"SECAM-K"   },
+	{ V4L2_STD_SECAM_K1, 	"SECAM-K1"  },
+	{ V4L2_STD_SECAM_L, 	"SECAM-L"   },
+	{ V4L2_STD_SECAM_LC, 	"SECAM-Lc"  },
+	{ 0, 			"Unknown"   }
+};
+
 /* video4linux standard ID conversion to standard name
  */
-char *v4l2_norm_to_name(v4l2_std_id id)
+const char *v4l2_norm_to_name(v4l2_std_id id)
 {
-	char *name;
 	u32 myid = id;
+	int i;
 
 	/* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
 	   64 bit comparations. So, on that architecture, with some gcc
@@ -64,110 +103,17 @@
 	 */
 	BUG_ON(myid != id);
 
-	switch (myid) {
-	case V4L2_STD_PAL:
-		name = "PAL";
-		break;
-	case V4L2_STD_PAL_BG:
-		name = "PAL-BG";
-		break;
-	case V4L2_STD_PAL_DK:
-		name = "PAL-DK";
-		break;
-	case V4L2_STD_PAL_B:
-		name = "PAL-B";
-		break;
-	case V4L2_STD_PAL_B1:
-		name = "PAL-B1";
-		break;
-	case V4L2_STD_PAL_G:
-		name = "PAL-G";
-		break;
-	case V4L2_STD_PAL_H:
-		name = "PAL-H";
-		break;
-	case V4L2_STD_PAL_I:
-		name = "PAL-I";
-		break;
-	case V4L2_STD_PAL_D:
-		name = "PAL-D";
-		break;
-	case V4L2_STD_PAL_D1:
-		name = "PAL-D1";
-		break;
-	case V4L2_STD_PAL_K:
-		name = "PAL-K";
-		break;
-	case V4L2_STD_PAL_M:
-		name = "PAL-M";
-		break;
-	case V4L2_STD_PAL_N:
-		name = "PAL-N";
-		break;
-	case V4L2_STD_PAL_Nc:
-		name = "PAL-Nc";
-		break;
-	case V4L2_STD_PAL_60:
-		name = "PAL-60";
-		break;
-	case V4L2_STD_NTSC:
-		name = "NTSC";
-		break;
-	case V4L2_STD_NTSC_M:
-		name = "NTSC-M";
-		break;
-	case V4L2_STD_NTSC_M_JP:
-		name = "NTSC-M-JP";
-		break;
-	case V4L2_STD_NTSC_443:
-		name = "NTSC-443";
-		break;
-	case V4L2_STD_NTSC_M_KR:
-		name = "NTSC-M-KR";
-		break;
-	case V4L2_STD_SECAM:
-		name = "SECAM";
-		break;
-	case V4L2_STD_SECAM_DK:
-		name = "SECAM-DK";
-		break;
-	case V4L2_STD_SECAM_B:
-		name = "SECAM-B";
-		break;
-	case V4L2_STD_SECAM_D:
-		name = "SECAM-D";
-		break;
-	case V4L2_STD_SECAM_G:
-		name = "SECAM-G";
-		break;
-	case V4L2_STD_SECAM_H:
-		name = "SECAM-H";
-		break;
-	case V4L2_STD_SECAM_K:
-		name = "SECAM-K";
-		break;
-	case V4L2_STD_SECAM_K1:
-		name = "SECAM-K1";
-		break;
-	case V4L2_STD_SECAM_L:
-		name = "SECAM-L";
-		break;
-	case V4L2_STD_SECAM_LC:
-		name = "SECAM-LC";
-		break;
-	default:
-		name = "Unknown";
-		break;
-	}
-
-	return name;
+	for (i = 0; standards[i].std; i++)
+		if (myid == standards[i].std)
+			break;
+	return standards[i].descr;
 }
 EXPORT_SYMBOL(v4l2_norm_to_name);
 
 /* Fill in the fields of a v4l2_standard structure according to the
    'id' and 'transmission' parameters.  Returns negative on error.  */
 int v4l2_video_std_construct(struct v4l2_standard *vs,
-			     int id, char *name)
+			     int id, const char *name)
 {
 	u32 index = vs->index;
 
@@ -1218,95 +1164,40 @@
 	case VIDIOC_ENUMSTD:
 	{
 		struct v4l2_standard *p = arg;
-		v4l2_std_id id = vfd->tvnorms,curr_id=0;
-		unsigned int index = p->index,i;
+		v4l2_std_id id = vfd->tvnorms, curr_id = 0;
+		unsigned int index = p->index, i, j = 0;
+		const char *descr = "";
 
-		if (index<0) {
-			ret=-EINVAL;
-			break;
-		}
-
-		/* Return norm array on a canonical way */
-		for (i=0;i<= index && id; i++) {
-			if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
-				curr_id = V4L2_STD_PAL;
-			} else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
-				curr_id = V4L2_STD_PAL_BG;
-			} else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
-				curr_id = V4L2_STD_PAL_DK;
-			} else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
-				curr_id = V4L2_STD_PAL_B;
-			} else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
-				curr_id = V4L2_STD_PAL_B1;
-			} else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
-				curr_id = V4L2_STD_PAL_G;
-			} else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
-				curr_id = V4L2_STD_PAL_H;
-			} else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
-				curr_id = V4L2_STD_PAL_I;
-			} else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
-				curr_id = V4L2_STD_PAL_D;
-			} else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
-				curr_id = V4L2_STD_PAL_D1;
-			} else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
-				curr_id = V4L2_STD_PAL_K;
-			} else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
-				curr_id = V4L2_STD_PAL_M;
-			} else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
-				curr_id = V4L2_STD_PAL_N;
-			} else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
-				curr_id = V4L2_STD_PAL_Nc;
-			} else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
-				curr_id = V4L2_STD_PAL_60;
-			} else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
-				curr_id = V4L2_STD_NTSC;
-			} else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
-				curr_id = V4L2_STD_NTSC_M;
-			} else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
-				curr_id = V4L2_STD_NTSC_M_JP;
-			} else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
-				curr_id = V4L2_STD_NTSC_443;
-			} else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
-				curr_id = V4L2_STD_NTSC_M_KR;
-			} else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
-				curr_id = V4L2_STD_SECAM;
-			} else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
-				curr_id = V4L2_STD_SECAM_DK;
-			} else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
-				curr_id = V4L2_STD_SECAM_B;
-			} else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
-				curr_id = V4L2_STD_SECAM_D;
-			} else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
-				curr_id = V4L2_STD_SECAM_G;
-			} else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
-				curr_id = V4L2_STD_SECAM_H;
-			} else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
-				curr_id = V4L2_STD_SECAM_K;
-			} else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
-				curr_id = V4L2_STD_SECAM_K1;
-			} else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
-				curr_id = V4L2_STD_SECAM_L;
-			} else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
-				curr_id = V4L2_STD_SECAM_LC;
-			} else {
+		/* Return norm array in a canonical way */
+		for (i = 0; i <= index && id; i++) {
+			/* last std value in the standards array is 0, so this
+			   while always ends there since (id & 0) == 0. */
+			while ((id & standards[j].std) != standards[j].std)
+				j++;
+			curr_id = standards[j].std;
+			descr = standards[j].descr;
+			j++;
+			if (curr_id == 0)
 				break;
-			}
-			id &= ~curr_id;
+			if (curr_id != V4L2_STD_PAL &&
+			    curr_id != V4L2_STD_SECAM &&
+			    curr_id != V4L2_STD_NTSC)
+				id &= ~curr_id;
 		}
-		if (i<=index)
+		if (i <= index)
 			return -EINVAL;
 
-		v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
+		v4l2_video_std_construct(p, curr_id, descr);
 		p->index = index;
 
-		dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+		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;
+		ret = 0;
 		break;
 	}
 	case VIDIOC_G_STD:
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 845be18..5ff9a58 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -327,13 +327,14 @@
 	int hmax  = buf->vb.height;
 	int wmax  = buf->vb.width;
 	struct timeval ts;
-	char *tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+	char *tmpbuf;
 	void *vbuf = videobuf_to_vmalloc(&buf->vb);
 
-	if (!tmpbuf)
+	if (!vbuf)
 		return;
 
-	if (!vbuf)
+	tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+	if (!tmpbuf)
 		return;
 
 	for (h = 0; h < hmax; h++) {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 07c2048..b413aa6 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -55,6 +55,10 @@
 #define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
 /* Controller needs to be reset after each request to stay stable */
 #define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
+/* Controller has an off-by-one issue with timeout value */
+#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL		(1<<10)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -115,7 +119,8 @@
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+				  SDHCI_QUIRK_BROKEN_DMA,
 	},
 
 	{
@@ -124,7 +129,17 @@
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor         = PCI_VENDOR_ID_MARVELL,
+		.device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.driver_data    = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+				  SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
 	},
 
 	{
@@ -469,6 +484,13 @@
 			break;
 	}
 
+	/*
+	 * Compensate for an off-by-one error in the CaFe hardware; otherwise,
+	 * a too-small count gives us interrupt timeouts.
+	 */
+	if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
+		count++;
+
 	if (count >= 0xF) {
 		printk(KERN_WARNING "%s: Too large timeout requested!\n",
 			mmc_hostname(host->mmc));
@@ -774,6 +796,14 @@
 		BUG();
 	}
 
+	/*
+	 * At least the CaFe chip gets confused if we set the voltage
+	 * and set turn on power at the same time, so set the voltage first.
+	 */
+	if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
+		writeb(pwr & ~SDHCI_POWER_ON,
+				host->ioaddr + SDHCI_POWER_CONTROL);
+
 	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
 
 out:
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 2edda8c..aabad8c 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1768,9 +1768,10 @@
 	case XCVR_MII: case XCVR_NWAY:
 		{
 			ok = 1;
-			spin_lock_bh(&vp->lock);
+			/* Interrupts are already disabled */
+			spin_lock(&vp->lock);
 			vortex_check_media(dev, 0);
-			spin_unlock_bh(&vp->lock);
+			spin_unlock(&vp->lock);
 		}
 		break;
 	  default:					/* Other media types handled by Tx timeouts. */
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index f3cba5e..1037b13 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1803,6 +1803,8 @@
 	if (rx->prev->skb) {
 		struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
 		put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
+		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
+			sizeof(struct rfd), PCI_DMA_TODEVICE);
 	}
 
 	return 0;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 701531e..a3f6a9c 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -347,7 +347,7 @@
 	else
 		netdev->features &= ~NETIF_F_TSO;
 
-	if (data)
+	if (data && (adapter->hw.mac_type > e1000_82547_rev_2))
 		netdev->features |= NETIF_F_TSO6;
 	else
 		netdev->features &= ~NETIF_F_TSO6;
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index cab1835..648a87b 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2535,7 +2535,8 @@
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 
-	e1000e_reset(adapter);
+	if (!pci_channel_offline(adapter->pdev))
+		e1000e_reset(adapter);
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
 
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 0b94833..e8cfade 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1077,8 +1077,6 @@
 
 static void start_timer(struct scc_priv *priv, int t, int r15)
 {
-	unsigned long flags;
-
 	outb(priv->tmr_mode, priv->tmr_ctrl);
 	if (t == 0) {
 		tm_isr(priv);
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index ae398f0..e79a26a 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -718,7 +718,8 @@
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 
-	igb_reset(adapter);
+	if (!pci_channel_offline(adapter->pdev))
+		igb_reset(adapter);
 	igb_clean_all_tx_rings(adapter);
 	igb_clean_all_rx_rings(adapter);
 }
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 679a082..2c03f4e 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -1271,7 +1271,7 @@
 
 			framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
 
-			endframeLen = framelen - jumbo->current_size;
+			endframelen = framelen - jumbo->current_size;
 			/*
 			if (framelen > IPG_RXFRAG_SIZE)
 				framelen=IPG_RXFRAG_SIZE;
@@ -1279,8 +1279,8 @@
 			if (framelen > IPG_RXSUPPORT_SIZE)
 				dev_kfree_skb_irq(jumbo->skb);
 			else {
-				memcpy(skb_put(jumbo->skb, endframeLen),
-				       skb->data, endframeLen);
+				memcpy(skb_put(jumbo->skb, endframelen),
+				       skb->data, endframelen);
 
 				jumbo->skb->protocol =
 				    eth_type_trans(jumbo->skb, dev);
@@ -1352,16 +1352,16 @@
 
 		switch (ipg_nic_rx_check_frame_type(dev)) {
 		case FRAME_WITH_START_WITH_END:
-			ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+			ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry);
 			break;
 		case FRAME_WITH_START:
-			ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+			ipg_nic_rx_with_start(dev, sp, rxfd, entry);
 			break;
 		case FRAME_WITH_END:
-			ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+			ipg_nic_rx_with_end(dev, sp, rxfd, entry);
 			break;
 		case FRAME_NO_START_NO_END:
-			ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+			ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry);
 			break;
 		}
 	}
@@ -1808,7 +1808,7 @@
 	/* initialize JUMBO Frame control variable */
 	sp->jumbo.found_start = 0;
 	sp->jumbo.current_size = 0;
-	sp->jumbo.skb = 0;
+	sp->jumbo.skb = NULL;
 	dev->mtu = IPG_TXFRAG_SIZE;
 #endif
 
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 7b85922..8f04609 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1969,7 +1969,8 @@
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
-	ixgbe_reset(adapter);
+	if (!pci_channel_offline(adapter->pdev))
+		ixgbe_reset(adapter);
 	ixgbe_clean_all_tx_rings(adapter);
 	ixgbe_clean_all_rx_rings(adapter);
 
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 6797ed0..63cd67b 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -71,14 +71,18 @@
 static irqreturn_t netxen_msi_intr(int irq, void *data);
 
 /*  PCI Device ID Table  */
+#define ENTRY(device) \
+	{PCI_DEVICE(0x4040, (device)), \
+	.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
+
 static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
-	{PCI_DEVICE(0x4040, 0x0001), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0002), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0003), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0004), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0005), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0024), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0025), PCI_DEVICE_CLASS(0x020000, ~0)},
+	ENTRY(0x0001),
+	ENTRY(0x0002),
+	ENTRY(0x0003),
+	ENTRY(0x0004),
+	ENTRY(0x0005),
+	ENTRY(0x0024),
+	ENTRY(0x0025),
 	{0,}
 };
 
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index ce95c5d..70d012e 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -525,12 +525,14 @@
     int ret;
     axnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
+    unsigned int nic_base = dev->base_addr;
     
     DEBUG(2, "axnet_open('%s')\n", dev->name);
 
     if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
+    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
     if (ret)
 	    return ret;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index fd8158a..2d4c4ad 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -969,6 +969,7 @@
     int ret;
     pcnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
+    unsigned int nic_base = dev->base_addr;
 
     DEBUG(2, "pcnet_open('%s')\n", dev->name);
 
@@ -976,6 +977,8 @@
 	return -ENODEV;
 
     set_misc_reg(dev);
+
+    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
     if (ret)
 	    return ret;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index bafb69b..fc6f4b8 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -942,7 +942,7 @@
 	m->msg_namelen = 0;
 
 	if (skb) {
-		total_len = min(total_len, skb->len);
+		total_len = min_t(size_t, total_len, skb->len);
 		error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
 		if (error == 0)
 			error = total_len;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index b7f7b22..bccee68 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -3701,7 +3701,9 @@
 		printk(KERN_ERR PFX
 				"%s: Driver up/down cycle failed, "
 				"closing device\n",qdev->ndev->name);
+		rtnl_lock();
 		dev_close(qdev->ndev);
+		rtnl_unlock();
 		return -1;
 	}
 	return 0;
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 858b191..504a48f 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -273,7 +273,7 @@
 	dma_addr_t mapping = desc_dma;
 
 	while (size-- > 0) {
-		mapping += sizeof(sizeof(*desc));
+		mapping += sizeof(*desc);
 		desc->ndesc = cpu_to_le32(mapping);
 		desc->vndescp = desc + 1;
 		desc++;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index b5c1e66..ae7b697 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2625,9 +2625,7 @@
 			rxdp1->Buffer0_ptr = pci_map_single
 			    (ring->pdev, skb->data, size - NET_IP_ALIGN,
 				PCI_DMA_FROMDEVICE);
-			if( (rxdp1->Buffer0_ptr == 0) ||
-				(rxdp1->Buffer0_ptr ==
-				DMA_ERROR_CODE))
+			if(pci_dma_mapping_error(rxdp1->Buffer0_ptr))
 				goto pci_map_failed;
 
 			rxdp->Control_2 =
@@ -2657,6 +2655,7 @@
 			skb->data = (void *) (unsigned long)tmp;
 			skb_reset_tail_pointer(skb);
 
+			/* AK: check is wrong. 0 can be valid dma address */
 			if (!(rxdp3->Buffer0_ptr))
 				rxdp3->Buffer0_ptr =
 				   pci_map_single(ring->pdev, ba->ba_0,
@@ -2665,8 +2664,7 @@
 				pci_dma_sync_single_for_device(ring->pdev,
 				(dma_addr_t) rxdp3->Buffer0_ptr,
 				    BUF0_LEN, PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer0_ptr == 0) ||
-				(rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
+			if (pci_dma_mapping_error(rxdp3->Buffer0_ptr))
 				goto pci_map_failed;
 
 			rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
@@ -2681,18 +2679,17 @@
 				(ring->pdev, skb->data, ring->mtu + 4,
 						PCI_DMA_FROMDEVICE);
 
-				if( (rxdp3->Buffer2_ptr == 0) ||
-					(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
+				if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
 					goto pci_map_failed;
 
+				/* AK: check is wrong */
 				if (!rxdp3->Buffer1_ptr)
 					rxdp3->Buffer1_ptr =
 						pci_map_single(ring->pdev,
 						ba->ba_1, BUF1_LEN,
 						PCI_DMA_FROMDEVICE);
 
-				if( (rxdp3->Buffer1_ptr == 0) ||
-					(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+				if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
 					pci_unmap_single
 						(ring->pdev,
 						(dma_addr_t)(unsigned long)
@@ -4264,16 +4261,14 @@
 		txdp->Buffer_Pointer = pci_map_single(sp->pdev,
 					fifo->ufo_in_band_v,
 					sizeof(u64), PCI_DMA_TODEVICE);
-		if((txdp->Buffer_Pointer == 0) ||
-			(txdp->Buffer_Pointer == DMA_ERROR_CODE))
+		if (pci_dma_mapping_error(txdp->Buffer_Pointer))
 			goto pci_map_failed;
 		txdp++;
 	}
 
 	txdp->Buffer_Pointer = pci_map_single
 	    (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
-	if((txdp->Buffer_Pointer == 0) ||
-		(txdp->Buffer_Pointer == DMA_ERROR_CODE))
+	if (pci_dma_mapping_error(txdp->Buffer_Pointer))
 		goto pci_map_failed;
 
 	txdp->Host_Control = (unsigned long) skb;
@@ -6884,10 +6879,8 @@
 				pci_map_single( sp->pdev, (*skb)->data,
 					size - NET_IP_ALIGN,
 					PCI_DMA_FROMDEVICE);
-			if( (rxdp1->Buffer0_ptr == 0) ||
-				(rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp1->Buffer0_ptr))
 				goto memalloc_failed;
-			}
 			rxdp->Host_Control = (unsigned long) (*skb);
 		}
 	} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
@@ -6913,15 +6906,12 @@
 				pci_map_single(sp->pdev, (*skb)->data,
 					       dev->mtu + 4,
 					       PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer2_ptr == 0) ||
-				(rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
 				goto memalloc_failed;
-			}
 			rxdp3->Buffer0_ptr = *temp0 =
 				pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
 						PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer0_ptr == 0) ||
-				(rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) {
 				pci_unmap_single (sp->pdev,
 					(dma_addr_t)rxdp3->Buffer2_ptr,
 					dev->mtu + 4, PCI_DMA_FROMDEVICE);
@@ -6933,8 +6923,7 @@
 			rxdp3->Buffer1_ptr = *temp1 =
 				pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
 						PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer1_ptr == 0) ||
-				(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
 				pci_unmap_single (sp->pdev,
 					(dma_addr_t)rxdp3->Buffer0_ptr,
 					BUF0_LEN, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 4706f7f..1827b66 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -75,10 +75,6 @@
 /* DEBUG message print. */
 #define DBG_PRINT(dbg_level, args...)  if(!(debug_level<dbg_level)) printk(args)
 
-#ifndef DMA_ERROR_CODE
-#define DMA_ERROR_CODE          (~(dma_addr_t)0x0)
-#endif
-
 /* Protocol assist features of the NIC */
 #define L3_CKSUM_OK 0xFFFF
 #define L4_CKSUM_OK 0xFFFF
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 10e4e85..b07b8cb 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1394,6 +1394,7 @@
 	tc35815_chip_init(dev);
 	spin_unlock_irq(&lp->lock);
 
+	netif_carrier_off(dev);
 	/* schedule a link state check */
 	phy_start(lp->phy_dev);
 
@@ -1735,7 +1736,6 @@
 			skb = lp->rx_skbs[cur_bd].skb;
 			prefetch(skb->data);
 			lp->rx_skbs[cur_bd].skb = NULL;
-			lp->fbl_count--;
 			pci_unmap_single(lp->pci_dev,
 					 lp->rx_skbs[cur_bd].skb_dma,
 					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -1791,6 +1791,7 @@
 #ifdef TC35815_USE_PACKEDBUFFER
 			while (lp->fbl_curid != id)
 #else
+			lp->fbl_count--;
 			while (lp->fbl_count < RX_BUF_NUM)
 #endif
 			{
@@ -2453,6 +2454,7 @@
 		return 0;
 	pci_set_power_state(pdev, PCI_D0);
 	tc35815_restart(dev);
+	netif_carrier_off(dev);
 	if (lp->phy_dev)
 		phy_start(lp->phy_dev);
 	netif_device_attach(dev);
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 249e180..069f8bb 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -32,6 +32,7 @@
 #include <linux/x25.h>
 #include <linux/lapb.h>
 #include <linux/init.h>
+#include <linux/rtnetlink.h>
 #include "x25_asy.h"
 
 #include <net/x25device.h>
@@ -601,8 +602,10 @@
 	if (!sl || sl->magic != X25_ASY_MAGIC)
 		return;
 
+	rtnl_lock();
 	if (sl->dev->flags & IFF_UP)
 		dev_close(sl->dev);
+	rtnl_unlock();
 
 	tty->disc_data = NULL;
 	sl->tty = NULL;
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index 36a9c42..76f4c7b 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -72,6 +72,9 @@
 	struct b43_wldev *dev = led->dev;
 	bool radio_enabled;
 
+	if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
+		return;
+
 	/* Checking the radio-enabled status here is slightly racy,
 	 * but we want to avoid the locking overhead and we don't care
 	 * whether the LED has the wrong state for a second. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index fa4b0d8..a708277 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2883,12 +2883,11 @@
 
 	if (unlikely(skb->len < 2 + 2 + 6)) {
 		/* Too short, this can't be a valid frame. */
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
+		goto drop_packet;
 	}
 	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
 	if (unlikely(!dev))
-		return NETDEV_TX_BUSY;
+		goto drop_packet;
 
 	/* Transmissions on seperate queues can run concurrently. */
 	read_lock_irqsave(&wl->tx_lock, flags);
@@ -2904,7 +2903,12 @@
 	read_unlock_irqrestore(&wl->tx_lock, flags);
 
 	if (unlikely(err))
-		return NETDEV_TX_BUSY;
+		goto drop_packet;
+	return NETDEV_TX_OK;
+
+drop_packet:
+	/* We can not transmit this packet. Drop it. */
+	dev_kfree_skb_any(skb);
 	return NETDEV_TX_OK;
 }
 
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index c990f87..93ddc1c 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -876,6 +876,7 @@
 	if (!ring)
 		goto out;
 	ring->type = type;
+	ring->dev = dev;
 
 	nr_slots = B43legacy_RXRING_SLOTS;
 	if (for_tx)
@@ -922,7 +923,6 @@
 				 DMA_TO_DEVICE);
 	}
 
-	ring->dev = dev;
 	ring->nr_slots = nr_slots;
 	ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
 	ring->index = controller_index;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 204077c..3e612d0 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2378,8 +2378,10 @@
 	} else
 		err = b43legacy_dma_tx(dev, skb, ctl);
 out:
-	if (unlikely(err))
-		return NETDEV_TX_BUSY;
+	if (unlikely(err)) {
+		/* Drop the packet. */
+		dev_kfree_skb_any(skb);
+	}
 	return NETDEV_TX_OK;
 }
 
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index 4fd7380..020f450 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -64,7 +64,7 @@
 	int hdrlen, phdrlen, head_need, tail_need;
 	u16 fc;
 	int prism_header, ret;
-	struct ieee80211_hdr_4addr *hdr;
+	struct ieee80211_hdr_4addr *fhdr;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -83,8 +83,8 @@
 		phdrlen = 0;
 	}
 
-	hdr = (struct ieee80211_hdr_4addr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_ctl);
+	fhdr = (struct ieee80211_hdr_4addr *) skb->data;
+	fc = le16_to_cpu(fhdr->frame_ctl);
 
 	if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
 		printk(KERN_DEBUG "%s: dropped management frame with header "
@@ -551,7 +551,7 @@
 	     hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
 	     hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
 		/* RA (or BSSID) is not ours - drop */
-		PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
+		PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
 		       "not own or broadcast %s=%s\n",
 		       local->dev->name,
 		       fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 0acd958..ab981af 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1930,7 +1930,7 @@
 		PDEBUG(DEBUG_PS, "   PSPOLL and AID[15:14] not set\n");
 		return;
 	}
-	aid &= ~BIT(15) & ~BIT(14);
+	aid &= ~(BIT(15) | BIT(14));
 	if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
 		PDEBUG(DEBUG_PS, "   invalid aid=%d\n", aid);
 		return;
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index ed4317a1..80039a0 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -533,10 +533,10 @@
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
 #define CFG_CHECK2(fn, retf) \
-do { int ret = (retf); \
-if (ret != 0) { \
-	PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
-	cs_error(link, fn, ret); \
+do { int _ret = (retf); \
+if (_ret != 0) { \
+	PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \
+	cs_error(link, fn, _ret); \
 	goto next_entry; \
 } \
 } while (0)
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index cdf90c4..936f52e 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2835,7 +2835,7 @@
 {
 	local_info_t *local = (local_info_t *) data;
 	struct net_device *dev = local->dev;
-	u16 channel;
+	u16 chan;
 
 	if (local->passive_scan_interval <= 0)
 		return;
@@ -2872,11 +2872,11 @@
 
 		printk(KERN_DEBUG "%s: passive scan channel %d\n",
 		       dev->name, local->passive_scan_channel);
-		channel = local->passive_scan_channel;
+		chan = local->passive_scan_channel;
 		local->passive_scan_state = PASSIVE_SCAN_WAIT;
 		local->passive_scan_timer.expires = jiffies + HZ / 10;
 	} else {
-		channel = local->channel;
+		chan = local->channel;
 		local->passive_scan_state = PASSIVE_SCAN_LISTEN;
 		local->passive_scan_timer.expires = jiffies +
 			local->passive_scan_interval * HZ;
@@ -2884,9 +2884,9 @@
 
 	if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
 				 (HFA384X_TEST_CHANGE_CHANNEL << 8),
-				 channel, NULL, 0))
+				 chan, NULL, 0))
 		printk(KERN_ERR "%s: passive scan channel set %d "
-		       "failed\n", dev->name, channel);
+		       "failed\n", dev->name, chan);
 
 	add_timer(&local->passive_scan_timer);
 }
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index f7aec93..a38e85f 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -594,7 +594,8 @@
 }
 
 
-int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+static int hostap_80211_header_parse(const struct sk_buff *skb,
+				     unsigned char *haddr)
 {
 	struct hostap_interface *iface = netdev_priv(skb->dev);
 	local_info_t *local = iface->local;
@@ -857,7 +858,6 @@
 	.rebuild	= eth_rebuild_header,
 	.cache		= eth_header_cache,
 	.cache_update	= eth_header_cache_update,
-
 	.parse		= hostap_80211_header_parse,
 };
 EXPORT_SYMBOL(hostap_80211_ops);
@@ -1150,7 +1150,6 @@
 EXPORT_SYMBOL(hostap_set_auth_algs);
 EXPORT_SYMBOL(hostap_dump_rx_header);
 EXPORT_SYMBOL(hostap_dump_tx_header);
-EXPORT_SYMBOL(hostap_80211_header_parse);
 EXPORT_SYMBOL(hostap_80211_get_hdrlen);
 EXPORT_SYMBOL(hostap_get_stats);
 EXPORT_SYMBOL(hostap_setup_dev);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 13925b6..b1b3c52 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2227,7 +2227,10 @@
 	}
 
 	IWL_DEBUG_INFO("Starting scan...\n");
-	priv->scan_bands = 2;
+	if (priv->cfg->sku & IWL_SKU_G)
+		priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+	if (priv->cfg->sku & IWL_SKU_A)
+		priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
 	set_bit(STATUS_SCANNING, &priv->status);
 	priv->scan_start = jiffies;
 	priv->scan_pass_start = priv->scan_start;
@@ -3352,13 +3355,18 @@
 	cancel_delayed_work(&priv->scan_check);
 
 	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-		       (priv->scan_bands == 2) ? "2.4" : "5.2",
+		       (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+							"2.4" : "5.2",
 		       jiffies_to_msecs(elapsed_jiffies
 					(priv->scan_pass_start, jiffies)));
 
-	/* Remove this scanned band from the list
-	 * of pending bands to scan */
-	priv->scan_bands--;
+	/* Remove this scanned band from the list of pending
+	 * bands to scan, band G precedes A in order of scanning
+	 * as seen in iwl3945_bg_request_scan */
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+	else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
 	/* If a request to abort was given, or the scan did not succeed
 	 * then we reset the scan state machine and terminate,
@@ -4972,7 +4980,7 @@
 
 		ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel);
 		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
 				       scan_ch->channel);
 			continue;
 		}
@@ -6315,21 +6323,16 @@
 
 	/* flags + rate selection */
 
-	switch (priv->scan_bands) {
-	case 2:
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
 		scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
 		scan->good_CRC_th = 0;
 		band = IEEE80211_BAND_2GHZ;
-		break;
-
-	case 1:
+	} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
 		scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
 		scan->good_CRC_th = IWL_GOOD_CRC_TH;
 		band = IEEE80211_BAND_5GHZ;
-		break;
-
-	default:
+	} else {
 		IWL_WARNING("Invalid scan band count\n");
 		goto done;
 	}
@@ -6770,7 +6773,7 @@
 	ch_info = iwl3945_get_channel_info(priv, conf->channel->band,
 					   conf->channel->hw_value);
 	if (!is_channel_valid(ch_info)) {
-		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this band.\n",
 			       conf->channel->hw_value, conf->channel->band);
 		IWL_DEBUG_MAC80211("leave - invalid channel\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 883b42f..5ed16ce 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -1774,7 +1774,10 @@
 	}
 
 	IWL_DEBUG_INFO("Starting scan...\n");
-	priv->scan_bands = 2;
+	if (priv->cfg->sku & IWL_SKU_G)
+		priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+	if (priv->cfg->sku & IWL_SKU_A)
+		priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
 	set_bit(STATUS_SCANNING, &priv->status);
 	priv->scan_start = jiffies;
 	priv->scan_pass_start = priv->scan_start;
@@ -3023,8 +3026,9 @@
 
 	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
 	if (index != -1) {
-		int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
 #ifdef CONFIG_IWL4965_HT
+		int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
+
 		if (tid != MAX_TID_COUNT)
 			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
 		if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
@@ -3276,13 +3280,18 @@
 	cancel_delayed_work(&priv->scan_check);
 
 	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-		       (priv->scan_bands == 2) ? "2.4" : "5.2",
+		       (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+						"2.4" : "5.2",
 		       jiffies_to_msecs(elapsed_jiffies
 					(priv->scan_pass_start, jiffies)));
 
-	/* Remove this scanned band from the list
-	 * of pending bands to scan */
-	priv->scan_bands--;
+	/* Remove this scanned band from the list of pending
+	 * bands to scan, band G precedes A in order of scanning
+	 * as seen in iwl_bg_request_scan */
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+	else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
 	/* If a request to abort was given, or the scan did not succeed
 	 * then we reset the scan state machine and terminate,
@@ -3292,7 +3301,7 @@
 		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
 	} else {
 		/* If there are more bands on this scan pass reschedule */
-		if (priv->scan_bands > 0)
+		if (priv->scan_bands)
 			goto reschedule;
 	}
 
@@ -4635,10 +4644,9 @@
 
 		scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq);
 
-		ch_info = iwl_get_channel_info(priv, band,
-					 scan_ch->channel);
+		ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
 		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
 				       scan_ch->channel);
 			continue;
 		}
@@ -5830,8 +5838,7 @@
 	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
 
-	switch (priv->scan_bands) {
-	case 2:
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
 		scan->tx_cmd.rate_n_flags =
 				iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
@@ -5839,17 +5846,13 @@
 
 		scan->good_CRC_th = 0;
 		band = IEEE80211_BAND_2GHZ;
-		break;
-
-	case 1:
+	} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
 		scan->tx_cmd.rate_n_flags =
 				iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
 				RATE_MCS_ANT_B_MSK);
 		scan->good_CRC_th = IWL_GOOD_CRC_TH;
 		band = IEEE80211_BAND_5GHZ;
-		break;
-
-	default:
+	} else {
 		IWL_WARNING("Invalid scan band count\n");
 		goto done;
 	}
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 762e85b..e43bae9 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -290,7 +290,7 @@
 
 		avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
 		avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
-		avs->mactime = cpu_to_be64(le64_to_cpu(clock));
+		avs->mactime = cpu_to_be64(clock);
 		avs->hosttime = cpu_to_be64(jiffies);
 		avs->phytype = cpu_to_be32(6);	/*OFDM: 6 for (g), 8 for (a) */
 		avs->channel = cpu_to_be32(channel_of_freq(freq));
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index fdbd0ef..61e59c1 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -138,11 +138,8 @@
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the data into the BBP.
@@ -155,6 +152,13 @@
 	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -168,10 +172,8 @@
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-		return;
-	}
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the request into the BBP.
@@ -186,17 +188,21 @@
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-		*value = 0xff;
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+		goto exit_fail;
 
 	rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
 	*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
 
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+	*value = 0xff;
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 611d983..b4bf1e0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -821,6 +821,7 @@
 	/*
 	 * Scheduled work.
 	 */
+	struct workqueue_struct *workqueue;
 	struct work_struct intf_work;
 	struct work_struct filter_work;
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2673d56..c997d4f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -75,7 +75,7 @@
 
 	rt2x00lib_reset_link_tuner(rt2x00dev);
 
-	queue_delayed_work(rt2x00dev->hw->workqueue,
+	queue_delayed_work(rt2x00dev->workqueue,
 			   &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
@@ -137,14 +137,6 @@
 		return;
 
 	/*
-	 * Stop all scheduled work.
-	 */
-	if (work_pending(&rt2x00dev->intf_work))
-		cancel_work_sync(&rt2x00dev->intf_work);
-	if (work_pending(&rt2x00dev->filter_work))
-		cancel_work_sync(&rt2x00dev->filter_work);
-
-	/*
 	 * Stop the TX queues.
 	 */
 	ieee80211_stop_queues(rt2x00dev->hw);
@@ -398,8 +390,8 @@
 	 * Increase tuner counter, and reschedule the next link tuner run.
 	 */
 	rt2x00dev->link.count++;
-	queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
-			   LINK_TUNE_INTERVAL);
+	queue_delayed_work(rt2x00dev->workqueue,
+			   &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
 static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -433,6 +425,15 @@
 
 	spin_unlock(&intf->lock);
 
+	/*
+	 * It is possible the radio was disabled while the work had been
+	 * scheduled. If that happens we should return here immediately,
+	 * note that in the spinlock protected area above the delayed_flags
+	 * have been cleared correctly.
+	 */
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
 	if (delayed_flags & DELAYED_UPDATE_BEACON) {
 		skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
 		if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
@@ -441,7 +442,7 @@
 	}
 
 	if (delayed_flags & DELAYED_CONFIG_ERP)
-		rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf);
+		rt2x00lib_config_erp(rt2x00dev, intf, &conf);
 
 	if (delayed_flags & DELAYED_LED_ASSOC)
 		rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
@@ -487,7 +488,7 @@
 						   rt2x00lib_beacondone_iter,
 						   rt2x00dev);
 
-	queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+	queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
 
@@ -1130,6 +1131,10 @@
 	/*
 	 * Initialize configuration work.
 	 */
+	rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
+	if (!rt2x00dev->workqueue)
+		goto exit;
+
 	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
 	INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
 	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
@@ -1190,6 +1195,13 @@
 	rt2x00leds_unregister(rt2x00dev);
 
 	/*
+	 * Stop all queued work. Note that most tasks will already be halted
+	 * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
+	 */
+	flush_workqueue(rt2x00dev->workqueue);
+	destroy_workqueue(rt2x00dev->workqueue);
+
+	/*
 	 * Free ieee80211_hw memory.
 	 */
 	rt2x00lib_remove_hw(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 87e280a..9cb023e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -428,7 +428,7 @@
 	if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
 		rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
 	else
-		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
 
@@ -509,7 +509,7 @@
 	memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
 	if (delayed) {
 		intf->delayed_flags |= delayed;
-		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
 	}
 	spin_unlock(&intf->lock);
 }
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index fff8386e..83cc014 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -134,11 +134,8 @@
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the data into the BBP.
@@ -151,6 +148,13 @@
 
 	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
 }
 
 static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -164,11 +168,8 @@
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the request into the BBP.
@@ -184,14 +185,19 @@
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-		*value = 0xff;
-		return;
-	}
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+		goto exit_fail;
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+	*value = 0xff;
 }
 
 static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index ec8f700..39bb96b 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -178,8 +178,7 @@
 	int ret;
 	int begin, end, i;
 
-	if (pos < 0 || pos > PCI_VPD_PCI22_SIZE ||
-	    size > PCI_VPD_PCI22_SIZE  - pos)
+	if (pos < 0 || pos > vpd->base.len || size > vpd->base.len  - pos)
 		return -EINVAL;
 	if (size == 0)
 		return 0;
@@ -223,8 +222,8 @@
 	u32 val;
 	int ret;
 
-	if (pos < 0 || pos > PCI_VPD_PCI22_SIZE || pos & 3 ||
-	    size > PCI_VPD_PCI22_SIZE - pos || size < 4)
+	if (pos < 0 || pos > vpd->base.len || pos & 3 ||
+	    size > vpd->base.len - pos || size < 4)
 		return -EINVAL;
 
 	val = (u8) *buf++;
@@ -255,11 +254,6 @@
 	return 4;
 }
 
-static int pci_vpd_pci22_get_size(struct pci_dev *dev)
-{
-	return PCI_VPD_PCI22_SIZE;
-}
-
 static void pci_vpd_pci22_release(struct pci_dev *dev)
 {
 	kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
@@ -268,7 +262,6 @@
 static struct pci_vpd_ops pci_vpd_pci22_ops = {
 	.read = pci_vpd_pci22_read,
 	.write = pci_vpd_pci22_write,
-	.get_size = pci_vpd_pci22_get_size,
 	.release = pci_vpd_pci22_release,
 };
 
@@ -284,6 +277,7 @@
 	if (!vpd)
 		return -ENOMEM;
 
+	vpd->base.len = PCI_VPD_PCI22_SIZE;
 	vpd->base.ops = &pci_vpd_pci22_ops;
 	spin_lock_init(&vpd->lock);
 	vpd->cap = cap;
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 648596d..91156f8 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -700,9 +700,10 @@
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
 				cleanup_p2p_bridge, NULL, NULL);
 
-	if (!(bridge = acpiphp_handle_to_bridge(handle)))
-		return AE_OK;
-	cleanup_bridge(bridge);
+	bridge = acpiphp_handle_to_bridge(handle);
+	if (bridge)
+		cleanup_bridge(bridge);
+
 	return AE_OK;
 }
 
@@ -715,9 +716,19 @@
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
 				(u32)1, cleanup_p2p_bridge, NULL, NULL);
 
+	/*
+	 * On root bridges with hotplug slots directly underneath (ie,
+	 * no p2p bridge inbetween), we call cleanup_bridge(). 
+	 *
+	 * The else clause cleans up root bridges that either had no
+	 * hotplug slots at all, or had a p2p bridge underneath.
+	 */
 	bridge = acpiphp_handle_to_bridge(handle);
 	if (bridge)
 		cleanup_bridge(bridge);
+	else
+		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					   handle_hotplug_event_bridge);
 }
 
 static struct pci_dev * get_apic_pci_info(acpi_handle handle)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 6f3c744..9c71858 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -736,9 +736,9 @@
 		attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
 		if (attr) {
 			pdev->vpd->attr = attr;
-			attr->size = pdev->vpd->ops->get_size(pdev);
+			attr->size = pdev->vpd->len;
 			attr->attr.name = "vpd";
-			attr->attr.mode = S_IRUGO | S_IWUSR;
+			attr->attr.mode = S_IRUSR | S_IWUSR;
 			attr->read = pci_read_vpd;
 			attr->write = pci_write_vpd;
 			retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0a497c1b..00408c9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -21,11 +21,11 @@
 struct pci_vpd_ops {
 	int (*read)(struct pci_dev *dev, int pos, int size, char *buf);
 	int (*write)(struct pci_dev *dev, int pos, int size, const char *buf);
-	int (*get_size)(struct pci_dev *dev);
 	void (*release)(struct pci_dev *dev);
 };
 
 struct pci_vpd {
+	unsigned int len;
 	struct pci_vpd_ops *ops;
 	struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
 };
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index dabb563..338a3f9 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1670,6 +1670,48 @@
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
 
+/*
+ * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
+ * VPD end tag will hang the device.  This problem was initially
+ * observed when a vpd entry was created in sysfs
+ * ('/sys/bus/pci/devices/<id>/vpd').   A read to this sysfs entry
+ * will dump 32k of data.  Reading a full 32k will cause an access
+ * beyond the VPD end tag causing the device to hang.  Once the device
+ * is hung, the bnx2 driver will not be able to reset the device.
+ * We believe that it is legal to read beyond the end tag and
+ * therefore the solution is to limit the read/write length.
+ */
+static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev)
+{
+	/*  Only disable the VPD capability for 5706, 5708, and 5709 rev. A */
+	if ((dev->device == PCI_DEVICE_ID_NX2_5706) ||
+	    (dev->device == PCI_DEVICE_ID_NX2_5708) ||
+	    ((dev->device == PCI_DEVICE_ID_NX2_5709) &&
+	     (dev->revision & 0xf0) == 0x0)) {
+		if (dev->vpd)
+			dev->vpd->len = 0x80;
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5706,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5706S,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5708,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5708S,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5709,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5709S,
+			 quirk_brcm_570x_limit_vpd);
+
 #ifdef CONFIG_PCI_MSI
 /* Some chipsets do not support MSI. We cannot easily rely on setting
  * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
@@ -1685,6 +1727,7 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
 
 /* Disable MSI on chipsets that are known to not support it */
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 7e3ad4f..58b7336 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -126,12 +126,25 @@
 	int err;
 	struct rtc_time before, now;
 	int first_time = 1;
+	unsigned long t_now, t_alm;
+	enum { none, day, month, year } missing = none;
+	unsigned days;
 
-	/* The lower level RTC driver may not be capable of filling
-	 * in all fields of the rtc_time struct (eg. rtc-cmos),
-	 * and so might instead return -1 in some fields.
-	 * We deal with that here by grabbing a current RTC timestamp
-	 * and using values from that for any missing (-1) values.
+	/* The lower level RTC driver may return -1 in some fields,
+	 * creating invalid alarm->time values, for reasons like:
+	 *
+	 *   - The hardware may not be capable of filling them in;
+	 *     many alarms match only on time-of-day fields, not
+	 *     day/month/year calendar data.
+	 *
+	 *   - Some hardware uses illegal values as "wildcard" match
+	 *     values, which non-Linux firmware (like a BIOS) may try
+	 *     to set up as e.g. "alarm 15 minutes after each hour".
+	 *     Linux uses only oneshot alarms.
+	 *
+	 * When we see that here, we deal with it by using values from
+	 * a current RTC timestamp for any missing (-1) values.  The
+	 * RTC driver prevents "periodic alarm" modes.
 	 *
 	 * But this can be racey, because some fields of the RTC timestamp
 	 * may have wrapped in the interval since we read the RTC alarm,
@@ -174,6 +187,10 @@
 		if (!alarm->enabled)
 			return 0;
 
+		/* full-function RTCs won't have such missing fields */
+		if (rtc_valid_tm(&alarm->time) == 0)
+			return 0;
+
 		/* get the "after" timestamp, to detect wrapped fields */
 		err = rtc_read_time(rtc, &now);
 		if (err < 0)
@@ -183,22 +200,85 @@
 	} while (   before.tm_min   != now.tm_min
 		 || before.tm_hour  != now.tm_hour
 		 || before.tm_mon   != now.tm_mon
-		 || before.tm_year  != now.tm_year
-		 || before.tm_isdst != now.tm_isdst);
+		 || before.tm_year  != now.tm_year);
 
-	/* Fill in any missing alarm fields using the timestamp */
+	/* Fill in the missing alarm fields using the timestamp; we
+	 * know there's at least one since alarm->time is invalid.
+	 */
 	if (alarm->time.tm_sec == -1)
 		alarm->time.tm_sec = now.tm_sec;
 	if (alarm->time.tm_min == -1)
 		alarm->time.tm_min = now.tm_min;
 	if (alarm->time.tm_hour == -1)
 		alarm->time.tm_hour = now.tm_hour;
-	if (alarm->time.tm_mday == -1)
+
+	/* For simplicity, only support date rollover for now */
+	if (alarm->time.tm_mday == -1) {
 		alarm->time.tm_mday = now.tm_mday;
-	if (alarm->time.tm_mon == -1)
+		missing = day;
+	}
+	if (alarm->time.tm_mon == -1) {
 		alarm->time.tm_mon = now.tm_mon;
-	if (alarm->time.tm_year == -1)
+		if (missing == none)
+			missing = month;
+	}
+	if (alarm->time.tm_year == -1) {
 		alarm->time.tm_year = now.tm_year;
+		if (missing == none)
+			missing = year;
+	}
+
+	/* with luck, no rollover is needed */
+	rtc_tm_to_time(&now, &t_now);
+	rtc_tm_to_time(&alarm->time, &t_alm);
+	if (t_now < t_alm)
+		goto done;
+
+	switch (missing) {
+
+	/* 24 hour rollover ... if it's now 10am Monday, an alarm that
+	 * that will trigger at 5am will do so at 5am Tuesday, which
+	 * could also be in the next month or year.  This is a common
+	 * case, especially for PCs.
+	 */
+	case day:
+		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
+		t_alm += 24 * 60 * 60;
+		rtc_time_to_tm(t_alm, &alarm->time);
+		break;
+
+	/* Month rollover ... if it's the 31th, an alarm on the 3rd will
+	 * be next month.  An alarm matching on the 30th, 29th, or 28th
+	 * may end up in the month after that!  Many newer PCs support
+	 * this type of alarm.
+	 */
+	case month:
+		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
+		do {
+			if (alarm->time.tm_mon < 11)
+				alarm->time.tm_mon++;
+			else {
+				alarm->time.tm_mon = 0;
+				alarm->time.tm_year++;
+			}
+			days = rtc_month_days(alarm->time.tm_mon,
+					alarm->time.tm_year);
+		} while (days < alarm->time.tm_mday);
+		break;
+
+	/* Year rollover ... easy except for leap years! */
+	case year:
+		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
+		do {
+			alarm->time.tm_year++;
+		} while (!rtc_valid_tm(&alarm->time));
+		break;
+
+	default:
+		dev_warn(&rtc->dev, "alarm rollover not handled\n");
+	}
+
+done:
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 82f62d2..67421b0d 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -331,14 +331,14 @@
 		RCNR = 0;
 	}
 
+	device_init_wakeup(&pdev->dev, 1);
+
 	rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
 				THIS_MODULE);
 
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
 
-	device_init_wakeup(&pdev->dev, 1);
-
 	platform_set_drvdata(pdev, rtc);
 
 	return 0;
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index eaf5594..7dcfba1 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -71,6 +71,7 @@
 #define X1205_SR_RTCF		0x01	/* Clock failure */
 #define X1205_SR_WEL		0x02	/* Write Enable Latch */
 #define X1205_SR_RWEL		0x04	/* Register Write Enable */
+#define X1205_SR_AL0		0x20	/* Alarm 0 match */
 
 #define X1205_DTR_DTR0		0x01
 #define X1205_DTR_DTR1		0x02
@@ -78,6 +79,8 @@
 
 #define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
 
+#define X1205_INT_AL0E		0x20	/* Alarm 0 enable */
+
 static struct i2c_driver x1205_driver;
 
 /*
@@ -89,8 +92,8 @@
 				unsigned char reg_base)
 {
 	unsigned char dt_addr[2] = { 0, reg_base };
-
 	unsigned char buf[8];
+	int i;
 
 	struct i2c_msg msgs[] = {
 		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
@@ -98,7 +101,7 @@
 	};
 
 	/* read date registers */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -110,6 +113,11 @@
 		buf[0], buf[1], buf[2], buf[3],
 		buf[4], buf[5], buf[6], buf[7]);
 
+	/* Mask out the enable bits if these are alarm registers */
+	if (reg_base < X1205_CCR_BASE)
+		for (i = 0; i <= 4; i++)
+			buf[i] &= 0x7F;
+
 	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
 	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
 	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
@@ -138,7 +146,7 @@
 	};
 
 	/* read status register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -147,10 +155,11 @@
 }
 
 static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
-				int datetoo, u8 reg_base)
+			int datetoo, u8 reg_base, unsigned char alm_enable)
 {
-	int i, xfer;
+	int i, xfer, nbytes;
 	unsigned char buf[8];
+	unsigned char rdata[10] = { 0, reg_base };
 
 	static const unsigned char wel[3] = { 0, X1205_REG_SR,
 						X1205_SR_WEL };
@@ -189,6 +198,11 @@
 		buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
 	}
 
+	/* If writing alarm registers, set compare bits on registers 0-4 */
+	if (reg_base < X1205_CCR_BASE)
+		for (i = 0; i <= 4; i++)
+			buf[i] |= 0x80;
+
 	/* this sequence is required to unlock the chip */
 	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
 		dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
@@ -200,19 +214,57 @@
 		return -EIO;
 	}
 
-	/* write register's data */
-	for (i = 0; i < (datetoo ? 8 : 3); i++) {
-		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
 
-		xfer = i2c_master_send(client, rdata, 3);
+	/* write register's data */
+	if (datetoo)
+		nbytes = 8;
+	else
+		nbytes = 3;
+	for (i = 0; i < nbytes; i++)
+		rdata[2+i] = buf[i];
+
+	xfer = i2c_master_send(client, rdata, nbytes+2);
+	if (xfer != nbytes+2) {
+		dev_err(&client->dev,
+			"%s: result=%d addr=%02x, data=%02x\n",
+			__func__,
+			 xfer, rdata[1], rdata[2]);
+		return -EIO;
+	}
+
+	/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
+	if (reg_base < X1205_CCR_BASE) {
+		unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };
+
+		msleep(10);
+
+		/* ...and set or clear the AL0E bit in the INT register */
+
+		/* Need to set RWEL again as the write has cleared it */
+		xfer = i2c_master_send(client, rwel, 3);
 		if (xfer != 3) {
 			dev_err(&client->dev,
-				"%s: xfer=%d addr=%02x, data=%02x\n",
+				"%s: aloe rwel - %d\n",
 				__func__,
-				 xfer, rdata[1], rdata[2]);
+				xfer);
 			return -EIO;
 		}
-	};
+
+		if (alm_enable)
+			al0e[2] = X1205_INT_AL0E;
+
+		xfer = i2c_master_send(client, al0e, 3);
+		if (xfer != 3) {
+			dev_err(&client->dev,
+				"%s: al0e - %d\n",
+				__func__,
+				xfer);
+			return -EIO;
+		}
+
+		/* and wait 10msec again for this write to complete */
+		msleep(10);
+	}
 
 	/* disable further writes */
 	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
@@ -230,9 +282,9 @@
 
 	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
 
-	if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
-		dev_err(&client->dev,
-			"unable to restart the oscillator\n");
+	err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
+	if (err < 0)
+		dev_err(&client->dev, "unable to restart the oscillator\n");
 
 	return err;
 }
@@ -248,7 +300,7 @@
 	};
 
 	/* read dtr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -280,7 +332,7 @@
 	};
 
 	/* read atr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -403,14 +455,33 @@
 
 static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
-	return x1205_get_datetime(to_i2c_client(dev),
-		&alrm->time, X1205_ALM0_BASE);
+	int err;
+	unsigned char intreg, status;
+	static unsigned char int_addr[2] = { 0, X1205_REG_INT };
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, int_addr },        /* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, &intreg },  /* read INT register */
+	};
+
+	/* read interrupt register and status register */
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __func__);
+		return -EIO;
+	}
+	err = x1205_get_status(client, &status);
+	if (err == 0) {
+		alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
+		alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
+		err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
+	}
+	return err;
 }
 
 static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
 	return x1205_set_datetime(to_i2c_client(dev),
-		&alrm->time, 1, X1205_ALM0_BASE);
+		&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
 }
 
 static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -422,7 +493,7 @@
 static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 	return x1205_set_datetime(to_i2c_client(dev),
-		tm, 1, X1205_CCR_BASE);
+		tm, 1, X1205_CCR_BASE, 0);
 }
 
 static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index a0b6d41..59fbef0 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2359,6 +2359,24 @@
 }
 EXPORT_SYMBOL(scsi_esp_unregister);
 
+static int esp_target_alloc(struct scsi_target *starget)
+{
+	struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+	struct esp_target_data *tp = &esp->target[starget->id];
+
+	tp->starget = starget;
+
+	return 0;
+}
+
+static void esp_target_destroy(struct scsi_target *starget)
+{
+	struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+	struct esp_target_data *tp = &esp->target[starget->id];
+
+	tp->starget = NULL;
+}
+
 static int esp_slave_alloc(struct scsi_device *dev)
 {
 	struct esp *esp = shost_priv(dev->host);
@@ -2370,8 +2388,6 @@
 		return -ENOMEM;
 	dev->hostdata = lp;
 
-	tp->starget = dev->sdev_target;
-
 	spi_min_period(tp->starget) = esp->min_period;
 	spi_max_offset(tp->starget) = 15;
 
@@ -2608,6 +2624,8 @@
 	.name			= "esp",
 	.info			= esp_info,
 	.queuecommand		= esp_queuecommand,
+	.target_alloc		= esp_target_alloc,
+	.target_destroy		= esp_target_destroy,
 	.slave_alloc		= esp_slave_alloc,
 	.slave_configure	= esp_slave_configure,
 	.slave_destroy		= esp_slave_destroy,
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 45df83b..0fe031f 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -61,7 +61,7 @@
 	return err;
 }
 
-#define SES_TIMEOUT 30
+#define SES_TIMEOUT (30 * HZ)
 #define SES_RETRIES 3
 
 static int ses_recv_diag(struct scsi_device *sdev, int page_code,
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index f20952c..fd9bb77 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -49,6 +49,7 @@
 #define DMA_RX_YCOUNT		(PAGE_SIZE / DMA_RX_XCOUNT)
 
 #define DMA_RX_FLUSH_JIFFIES	(HZ / 50)
+#define CTS_CHECK_JIFFIES	(HZ / 50)
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
 static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
@@ -290,11 +291,6 @@
 {
 	struct circ_buf *xmit = &uart->port.info->xmit;
 
-	if (uart->port.x_char) {
-		UART_PUT_CHAR(uart, uart->port.x_char);
-		uart->port.icount.tx++;
-		uart->port.x_char = 0;
-	}
 	/*
 	 * Check the modem control lines before
 	 * transmitting anything.
@@ -306,6 +302,12 @@
 		return;
 	}
 
+	if (uart->port.x_char) {
+		UART_PUT_CHAR(uart, uart->port.x_char);
+		uart->port.icount.tx++;
+		uart->port.x_char = 0;
+	}
+
 	while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
 		UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -345,15 +347,6 @@
 }
 #endif
 
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-static void bfin_serial_do_work(struct work_struct *work)
-{
-	struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
-
-	bfin_serial_mctrl_check(uart);
-}
-#endif
-
 #ifdef CONFIG_SERIAL_BFIN_DMA
 static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
 {
@@ -361,6 +354,12 @@
 
 	uart->tx_done = 0;
 
+	/*
+	 * Check the modem control lines before
+	 * transmitting anything.
+	 */
+	bfin_serial_mctrl_check(uart);
+
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
 		uart->tx_count = 0;
 		uart->tx_done = 1;
@@ -373,12 +372,6 @@
 		uart->port.x_char = 0;
 	}
 
-	/*
-	 * Check the modem control lines before
-	 * transmitting anything.
-	 */
-	bfin_serial_mctrl_check(uart);
-
 	uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
 	if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
 		uart->tx_count = UART_XMIT_SIZE - xmit->tail;
@@ -565,7 +558,10 @@
 	uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
 	if (!(status & TIOCM_CTS)) {
 		tty->hw_stopped = 1;
-		schedule_work(&uart->cts_workqueue);
+		uart->cts_timer.data = (unsigned long)(uart);
+		uart->cts_timer.function = (void *)bfin_serial_mctrl_check;
+		uart->cts_timer.expires = jiffies + CTS_CHECK_JIFFIES;
+		add_timer(&(uart->cts_timer));
 	} else {
 		tty->hw_stopped = 0;
 	}
@@ -885,7 +881,7 @@
 		init_timer(&(bfin_serial_ports[i].rx_dma_timer));
 #endif
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-		INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
+		init_timer(&(bfin_serial_ports[i].cts_timer));
 		bfin_serial_ports[i].cts_pin	    =
 			bfin_serial_resource[i].uart_cts_pin;
 		bfin_serial_ports[i].rts_pin	    =
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index c9b64e7..42d2e10 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1991,7 +1991,9 @@
 static int serial_match_port(struct device *dev, void *data)
 {
 	struct uart_match *match = data;
-	dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line;
+	struct tty_driver *tty_drv = match->driver->tty_driver;
+	dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
+		match->port->line;
 
 	return dev->devt == devt; /* Actually, only one tty per port */
 }
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 799337f..f5b60c7 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -167,14 +167,14 @@
 
 	mutex_lock(&spidev->buf_lock);
 	status = spidev_sync_read(spidev, count);
-	if (status == 0) {
+	if (status > 0) {
 		unsigned long	missing;
 
-		missing = copy_to_user(buf, spidev->buffer, count);
-		if (count && missing == count)
+		missing = copy_to_user(buf, spidev->buffer, status);
+		if (missing == status)
 			status = -EFAULT;
 		else
-			status = count - missing;
+			status = status - missing;
 	}
 	mutex_unlock(&spidev->buf_lock);
 
@@ -200,8 +200,6 @@
 	missing = copy_from_user(spidev->buffer, buf, count);
 	if (missing == 0) {
 		status = spidev_sync_write(spidev, count);
-		if (status == 0)
-			status = count;
 	} else
 		status = -EFAULT;
 	mutex_unlock(&spidev->buf_lock);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 4b62852..a86e952 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -12,3 +12,12 @@
 	  cooling devices.
 	  All platforms with ACPI thermal support can use this driver.
 	  If you want this support, you should say Y or M here.
+
+config THERMAL_HWMON
+	bool "Hardware monitoring support"
+	depends on HWMON=y || HWMON=THERMAL
+	help
+	  The generic thermal sysfs driver's hardware monitoring support
+	  requires a 2.10.7/3.0.2 or later lm-sensors userspace.
+
+	  Say Y if your user-space is new enough.
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 6098787..fe07462 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -295,8 +295,8 @@
 
 /* Device management */
 
-#if defined(CONFIG_HWMON) ||	\
-	(defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+#if defined(CONFIG_THERMAL_HWMON)
+
 /* hwmon sys I/F */
 #include <linux/hwmon.h>
 static LIST_HEAD(thermal_hwmon_list);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 63c3404..c3201aff 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1125,9 +1125,6 @@
 	for (i = 0; i < acm->rx_buflimit; i++)
 		usb_kill_urb(acm->ru[i].urb);
 
-	INIT_LIST_HEAD(&acm->filled_read_bufs);
-	INIT_LIST_HEAD(&acm->spare_read_bufs);
-
 	tasklet_enable(&acm->urb_task);
 
 	cancel_work_sync(&acm->work);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 09a53e7..7158dbb 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1684,19 +1684,30 @@
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
 	struct usb_hcd		*hcd = __hcd;
-	int			start = hcd->state;
+	unsigned long		flags;
+	irqreturn_t		rc;
 
-	if (unlikely(start == HC_STATE_HALT ||
-	    !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
-		return IRQ_NONE;
-	if (hcd->driver->irq (hcd) == IRQ_NONE)
-		return IRQ_NONE;
+	/* IRQF_DISABLED doesn't work correctly with shared IRQs
+	 * when the first handler doesn't use it.  So let's just
+	 * assume it's never used.
+	 */
+	local_irq_save(flags);
 
-	set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+	if (unlikely(hcd->state == HC_STATE_HALT ||
+		     !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+		rc = IRQ_NONE;
+	} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
+		rc = IRQ_NONE;
+	} else {
+		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 
-	if (unlikely(hcd->state == HC_STATE_HALT))
-		usb_hc_died (hcd);
-	return IRQ_HANDLED;
+		if (unlikely(hcd->state == HC_STATE_HALT))
+			usb_hc_died(hcd);
+		rc = IRQ_HANDLED;
+	}
+
+	local_irq_restore(flags);
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1860,6 +1871,13 @@
 
 	/* enable irqs just before we start the controller */
 	if (hcd->driver->irq) {
+
+		/* IRQF_DISABLED doesn't work as advertised when used together
+		 * with IRQF_SHARED. As usb_hcd_irq() will always disable
+		 * interrupts we can remove it here.
+		 */
+		irqflags &= ~IRQF_DISABLED;
+
 		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
 				hcd->driver->description, hcd->self.busnum);
 		if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 94789be..512d2d5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -713,18 +713,11 @@
 		}
 
 		/* Was the power session lost while we were suspended? */
-		switch (type) {
-		case HUB_RESET_RESUME:
-			portstatus = 0;
-			portchange = USB_PORT_STAT_C_CONNECTION;
-			break;
+		status = hub_port_status(hub, port1, &portstatus, &portchange);
 
-		case HUB_RESET:
-		case HUB_RESUME:
-			status = hub_port_status(hub, port1,
-					&portstatus, &portchange);
-			break;
-		}
+		/* If the device is gone, khubd will handle it later */
+		if (status == 0 && !(portstatus & USB_PORT_STAT_CONNECTION))
+			continue;
 
 		/* For "USB_PERSIST"-enabled children we must
 		 * mark the child device for reset-resume and
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 35a0309..90245fd 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -177,6 +177,15 @@
 static inline void
 timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
 {
+	/* Don't override timeouts which shrink or (later) disable
+	 * the async ring; just the I/O watchdog.  Note that if a
+	 * SHRINK were pending, OFF would never be requested.
+	 */
+	if (timer_pending(&ehci->watchdog)
+			&& ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
+				& ehci->actions))
+		return;
+
 	if (!test_and_set_bit (action, &ehci->actions)) {
 		unsigned long t;
 
@@ -192,15 +201,7 @@
 			t = EHCI_SHRINK_JIFFIES;
 			break;
 		}
-		t += jiffies;
-		// all timings except IAA watchdog can be overridden.
-		// async queue SHRINK often precedes IAA.  while it's ready
-		// to go OFF neither can matter, and afterwards the IO
-		// watchdog stops unless there's still periodic traffic.
-		if (time_before_eq(t, ehci->watchdog.expires)
-				&& timer_pending (&ehci->watchdog))
-			return;
-		mod_timer (&ehci->watchdog, t);
+		mod_timer(&ehci->watchdog, t + jiffies);
 	}
 }
 
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 33f1c1c..a8160d6 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1054,7 +1054,7 @@
 
 #ifdef CONFIG_MFD_SM501
 #include "ohci-sm501.c"
-#define PLATFORM_DRIVER		ohci_hcd_sm501_driver
+#define SM501_OHCI_DRIVER	ohci_hcd_sm501_driver
 #endif
 
 #if	!defined(PCI_DRIVER) &&		\
@@ -1062,6 +1062,7 @@
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_DRIVER) &&	\
 	!defined(PS3_SYSTEM_BUS_DRIVER) && \
+	!defined(SM501_OHCI_DRIVER) && \
 	!defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
@@ -1121,9 +1122,18 @@
 		goto error_ssb;
 #endif
 
+#ifdef SM501_OHCI_DRIVER
+	retval = platform_driver_register(&SM501_OHCI_DRIVER);
+	if (retval < 0)
+		goto error_sm501;
+#endif
+
 	return retval;
 
 	/* Error path */
+#ifdef SM501_OHCI_DRIVER
+ error_sm501:
+#endif
 #ifdef SSB_OHCI_DRIVER
  error_ssb:
 #endif
@@ -1159,6 +1169,9 @@
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SM501_OHCI_DRIVER
+	platform_driver_unregister(&SM501_OHCI_DRIVER);
+#endif
 #ifdef SSB_OHCI_DRIVER
 	ssb_driver_unregister(&SSB_OHCI_DRIVER);
 #endif
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 9c9f3b5..9b54740 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -952,6 +952,7 @@
 			struct urb	*urb;
 			urb_priv_t	*urb_priv;
 			__hc32		savebits;
+			u32		tdINFO;
 
 			td = list_entry (entry, struct td, td_list);
 			urb = td->urb;
@@ -966,6 +967,17 @@
 			savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK);
 			*prev = td->hwNextTD | savebits;
 
+			/* If this was unlinked, the TD may not have been
+			 * retired ... so manually save the data toggle.
+			 * The controller ignores the value we save for
+			 * control and ISO endpoints.
+			 */
+			tdINFO = hc32_to_cpup(ohci, &td->hwINFO);
+			if ((tdINFO & TD_T) == TD_T_DATA0)
+				ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_C);
+			else if ((tdINFO & TD_T) == TD_T_DATA1)
+				ed->hwHeadP |= cpu_to_hc32(ohci, ED_C);
+
 			/* HC may have partly processed this TD */
 			td_done (ohci, urb, td);
 			urb_priv->td_cnt++;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index cb7fa0e..33182f4 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3264,8 +3264,6 @@
 
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
-
-	dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 5234e7a..0ff4a39 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -637,6 +637,7 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
+	{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 06e0eca..8302eca 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -828,6 +828,9 @@
 /* Propox devices */
 #define FTDI_PROPOX_JTAGCABLEII_PID	0xD738
 
+/* Rig Expert Ukraine devices */
+#define FTDI_REU_TINY_PID		0xED22	/* RigExpert Tiny */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index ea924dc..d9fb376 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -570,7 +570,12 @@
 	.description =		"PocketPC PDA",
 	.usb_driver = 		&ipaq_driver,
 	.id_table =		ipaq_id_table,
-	.num_ports =		2,
+	/*
+	 * some devices have an extra endpoint, which
+	 * must be ignored as it would make the core
+	 * create a second port which oopses when used
+	 */
+	.num_ports =		1,
 	.open =			ipaq_open,
 	.close =		ipaq_close,
 	.attach =		ipaq_startup,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 43cfde8..a73420d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -306,6 +306,7 @@
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
 	{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 103195a..2a0dd1b 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -57,6 +57,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index cff160a..6ac3bbc 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -15,6 +15,7 @@
 #define PL2303_PRODUCT_ID_RSAQ3		0xaaa2
 #define PL2303_PRODUCT_ID_ALDIGA	0x0611
 #define PL2303_PRODUCT_ID_MMX		0x0612
+#define PL2303_PRODUCT_ID_GPRS		0x0609
 
 #define ATEN_VENDOR_ID		0x0557
 #define ATEN_VENDOR_ID2		0x0547
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 45fe366..39a7c11 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -402,11 +402,19 @@
 		US_FL_IGNORE_RESIDUE ),
 
 #ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+/* CY7C68300 : support atacb */
 UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
 		"Cypress",
 		"Cypress AT2LP",
 		US_SC_CYP_ATACB, US_PR_DEVICE, NULL,
 		0),
+
+/* CY7C68310 : support atacb and atacb2 */
+UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress ISD-300LP",
+		US_SC_CYP_ATACB, US_PR_DEVICE, NULL,
+		0),
 #endif
 
 /* Reported by Simon Levitt <simon@whattf.com>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 002b61b..e0c5f96 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1825,12 +1825,13 @@
 
 config FB_W100
 	tristate "W100 frame buffer support"
-	depends on FB && PXA_SHARPSL
+	depends on FB && ARCH_PXA
  	select FB_CFB_FILLRECT
  	select FB_CFB_COPYAREA
  	select FB_CFB_IMAGEBLIT
 	---help---
 	  Frame buffer driver for the w100 as found on the Sharp SL-Cxx series.
+	  It can also drive the w3220 chip found on iPAQ hx4700.
 
 	  This driver is also available as a module ( = code which can be
 	  inserted and removed from the running kernel whenever you want). The
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 0a27853..712dabc 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -286,7 +286,7 @@
  *	rheap and make the furture large allocation fail.
  */
 
-void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
+static void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
 {
 	void *virt;
 
@@ -311,12 +311,12 @@
 		memset(virt, 0, size);
 	}
 
-	pr_debug("rh virt=%p phys=%lx\n", virt, *phys);
+	pr_debug("rh virt=%p phys=%llx\n", virt, (unsigned long long)*phys);
 
 	return virt;
 }
 
-void fsl_diu_free(void *p, unsigned long size)
+static void fsl_diu_free(void *p, unsigned long size)
 {
 	pr_debug("p=%p size=%lu\n", p, size);
 
@@ -770,7 +770,7 @@
 	info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
 	pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
 	info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
-	if (info->screen_base == 0) {
+	if (info->screen_base == NULL) {
 		printk(KERN_ERR "Unable to allocate fb memory\n");
 		return -ENOMEM;
 	}
@@ -788,7 +788,7 @@
 static void unmap_video_memory(struct fb_info *info)
 {
 	fsl_diu_free(info->screen_base, info->fix.smem_len);
-	info->screen_base = 0;
+	info->screen_base = NULL;
 	info->fix.smem_start = 0;
 	info->fix.smem_len = 0;
 }
@@ -1158,7 +1158,7 @@
 	return 0;
 }
 
-static int install_fb(struct fb_info *info)
+static int __devinit install_fb(struct fb_info *info)
 {
 	int rc;
 	struct mfb_info *mfbi = info->par;
@@ -1233,7 +1233,7 @@
 	return 0;
 }
 
-static void __exit uninstall_fb(struct fb_info *info)
+static void uninstall_fb(struct fb_info *info)
 {
 	struct mfb_info *mfbi = info->par;
 
@@ -1287,7 +1287,7 @@
 	/* Read to clear the status */
 	status = in_be32(&hw->int_status);
 
-	ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0);
+	ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
 	if (ret)
 		pr_info("Request diu IRQ failed.\n");
 	else {
@@ -1312,7 +1312,7 @@
 	/* Disable all LCDC interrupt */
 	out_be32(&hw->int_mask, 0x1f);
 
-	free_irq(irq, 0);
+	free_irq(irq, NULL);
 }
 
 #ifdef CONFIG_PM
@@ -1324,7 +1324,7 @@
 {
 	struct fsl_diu_data *machine_data;
 
-	machine_data = dev_get_drvdata(&ofdev->dev);
+	machine_data = dev_get_drvdata(&dev->dev);
 	disable_lcdc(machine_data->fsl_diu_info[0]);
 
 	return 0;
@@ -1334,7 +1334,7 @@
 {
 	struct fsl_diu_data *machine_data;
 
-	machine_data = dev_get_drvdata(&ofdev->dev);
+	machine_data = dev_get_drvdata(&dev->dev);
 	enable_lcdc(machine_data->fsl_diu_info[0]);
 
 	return 0;
@@ -1353,7 +1353,8 @@
 	dma_addr_t paddr = 0;
 
 	ssize = size + bytes_align;
-	buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO);
+	buf->vaddr = dma_alloc_coherent(NULL, ssize, &paddr, GFP_DMA |
+							     __GFP_ZERO);
 	if (!buf->vaddr)
 		return -ENOMEM;
 
@@ -1371,7 +1372,7 @@
 
 static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
 {
-	dma_free_coherent(0, size + bytes_align,
+	dma_free_coherent(NULL, size + bytes_align,
 				buf->vaddr, (buf->paddr - buf->offset));
 	return;
 }
@@ -1411,7 +1412,7 @@
 	return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
 }
 
-static int fsl_diu_probe(struct of_device *ofdev,
+static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->node;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 7dcda18..fafe7db 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1246,7 +1246,7 @@
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
+static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
 {
 	/*
 	 * We reserve one page for the palette, plus the size
@@ -1348,7 +1348,7 @@
 	pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
 }
 
-static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
+static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
 {
 	struct pxafb_info *fbi;
 	void *addr;
@@ -1410,7 +1410,7 @@
 }
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
-static int __init parse_opt_mode(struct device *dev, const char *this_opt)
+static int __devinit parse_opt_mode(struct device *dev, const char *this_opt)
 {
 	struct pxafb_mach_info *inf = dev->platform_data;
 
@@ -1469,7 +1469,7 @@
 	return 0;
 }
 
-static int __init parse_opt(struct device *dev, char *this_opt)
+static int __devinit parse_opt(struct device *dev, char *this_opt)
 {
 	struct pxafb_mach_info *inf = dev->platform_data;
 	struct pxafb_mode_info *mode = &inf->modes[0];
@@ -1567,7 +1567,7 @@
 	return 0;
 }
 
-static int __init pxafb_parse_options(struct device *dev, char *options)
+static int __devinit pxafb_parse_options(struct device *dev, char *options)
 {
 	char *this_opt;
 	int ret;
@@ -1588,8 +1588,8 @@
 
 static char g_options[256] __devinitdata = "";
 
-#ifndef CONFIG_MODULES
-static int __devinit pxafb_setup_options(void)
+#ifndef MODULE
+static int __init pxafb_setup_options(void)
 {
 	char *options = NULL;
 
@@ -1613,7 +1613,7 @@
 #define pxafb_setup_options()		(0)
 #endif
 
-static int __init pxafb_probe(struct platform_device *dev)
+static int __devinit pxafb_probe(struct platform_device *dev)
 {
 	struct pxafb_info *fbi;
 	struct pxafb_mach_info *inf;
@@ -1685,14 +1685,14 @@
 	if (r == NULL) {
 		dev_err(&dev->dev, "no I/O memory resource defined\n");
 		ret = -ENODEV;
-		goto failed;
+		goto failed_fbi;
 	}
 
 	r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
 	if (r == NULL) {
 		dev_err(&dev->dev, "failed to request I/O memory\n");
 		ret = -EBUSY;
-		goto failed;
+		goto failed_fbi;
 	}
 
 	fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
@@ -1735,8 +1735,17 @@
 	 * This makes sure that our colour bitfield
 	 * descriptors are correctly initialised.
 	 */
-	pxafb_check_var(&fbi->fb.var, &fbi->fb);
-	pxafb_set_par(&fbi->fb);
+	ret = pxafb_check_var(&fbi->fb.var, &fbi->fb);
+	if (ret) {
+		dev_err(&dev->dev, "failed to get suitable mode\n");
+		goto failed_free_irq;
+	}
+
+	ret = pxafb_set_par(&fbi->fb);
+	if (ret) {
+		dev_err(&dev->dev, "Failed to set parameters\n");
+		goto failed_free_irq;
+	}
 
 	platform_set_drvdata(dev, fbi);
 
@@ -1744,7 +1753,7 @@
 	if (ret < 0) {
 		dev_err(&dev->dev,
 			"Failed to register framebuffer device: %d\n", ret);
-		goto failed_free_irq;
+		goto failed_free_cmap;
 	}
 
 #ifdef CONFIG_CPU_FREQ
@@ -1763,18 +1772,23 @@
 
 	return 0;
 
+failed_free_cmap:
+	if (fbi->fb.cmap.len)
+		fb_dealloc_cmap(&fbi->fb.cmap);
 failed_free_irq:
 	free_irq(irq, fbi);
-failed_free_res:
-	release_mem_region(r->start, r->end - r->start + 1);
-failed_free_io:
-	iounmap(fbi->mmio_base);
 failed_free_mem:
 	dma_free_writecombine(&dev->dev, fbi->map_size,
 			fbi->map_cpu, fbi->map_dma);
-failed:
+failed_free_io:
+	iounmap(fbi->mmio_base);
+failed_free_res:
+	release_mem_region(r->start, r->end - r->start + 1);
+failed_fbi:
+	clk_put(fbi->clk);
 	platform_set_drvdata(dev, NULL);
 	kfree(fbi);
+failed:
 	return ret;
 }
 
@@ -1787,7 +1801,7 @@
 	},
 };
 
-static int __devinit pxafb_init(void)
+static int __init pxafb_init(void)
 {
 	if (pxafb_setup_options())
 		return -EINVAL;
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 30469bf..d0674f1 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -1003,6 +1003,7 @@
 static struct w100_pll_info xtal_16000000[] = {
 	/*freq     M   N_int    N_fac  tfgoal  lock_time */
 	{ 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
+	{ 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
 	{ 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
 	{ 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
 	{  0,      0,   0,       0,        0,         0},
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 8662a6b..25b352b 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -68,7 +68,6 @@
 obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
 obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
-CFLAGS_hpwdt.o += -O
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 2686f3e..eaa3f2a 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -140,49 +140,53 @@
 };
 MODULE_DEVICE_TABLE(pci, hpwdt_devices);
 
+extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, unsigned long *pRomEntry);
+
 #ifndef CONFIG_X86_64
 /* --32 Bit Bios------------------------------------------------------------ */
 
 #define HPWDT_ARCH	32
 
-asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
-			       unsigned long *pRomEntry)
-{
-	asm("pushl       %ebp               \n\t"
-	    "movl        %esp, %ebp         \n\t"
-	    "pusha                          \n\t"
-	    "pushf                          \n\t"
-	    "push        %es                \n\t"
-	    "push        %ds                \n\t"
-	    "pop         %es                \n\t"
-	    "movl        8(%ebp),%eax       \n\t"
-	    "movl        4(%eax),%ebx       \n\t"
-	    "movl        8(%eax),%ecx       \n\t"
-	    "movl        12(%eax),%edx      \n\t"
-	    "movl        16(%eax),%esi      \n\t"
-	    "movl        20(%eax),%edi      \n\t"
-	    "movl        (%eax),%eax        \n\t"
-	    "push        %cs                \n\t"
-	    "call        *12(%ebp)          \n\t"
-	    "pushf                          \n\t"
-	    "pushl       %eax               \n\t"
-	    "movl        8(%ebp),%eax       \n\t"
-	    "movl        %ebx,4(%eax)       \n\t"
-	    "movl        %ecx,8(%eax)       \n\t"
-	    "movl        %edx,12(%eax)      \n\t"
-	    "movl        %esi,16(%eax)      \n\t"
-	    "movl        %edi,20(%eax)      \n\t"
-	    "movw        %ds,24(%eax)       \n\t"
-	    "movw        %es,26(%eax)       \n\t"
-	    "popl        %ebx               \n\t"
-	    "movl        %ebx,(%eax)        \n\t"
-	    "popl        %ebx               \n\t"
-	    "movl        %ebx,28(%eax)      \n\t"
-	    "pop         %es                \n\t"
-	    "popf                           \n\t"
-	    "popa                           \n\t"
-	    "leave                          \n\t" "ret");
-}
+asm(".text                          \n\t"
+    ".align 4                       \n"
+    "asminline_call:                \n\t"
+    "pushl       %ebp               \n\t"
+    "movl        %esp, %ebp         \n\t"
+    "pusha                          \n\t"
+    "pushf                          \n\t"
+    "push        %es                \n\t"
+    "push        %ds                \n\t"
+    "pop         %es                \n\t"
+    "movl        8(%ebp),%eax       \n\t"
+    "movl        4(%eax),%ebx       \n\t"
+    "movl        8(%eax),%ecx       \n\t"
+    "movl        12(%eax),%edx      \n\t"
+    "movl        16(%eax),%esi      \n\t"
+    "movl        20(%eax),%edi      \n\t"
+    "movl        (%eax),%eax        \n\t"
+    "push        %cs                \n\t"
+    "call        *12(%ebp)          \n\t"
+    "pushf                          \n\t"
+    "pushl       %eax               \n\t"
+    "movl        8(%ebp),%eax       \n\t"
+    "movl        %ebx,4(%eax)       \n\t"
+    "movl        %ecx,8(%eax)       \n\t"
+    "movl        %edx,12(%eax)      \n\t"
+    "movl        %esi,16(%eax)      \n\t"
+    "movl        %edi,20(%eax)      \n\t"
+    "movw        %ds,24(%eax)       \n\t"
+    "movw        %es,26(%eax)       \n\t"
+    "popl        %ebx               \n\t"
+    "movl        %ebx,(%eax)        \n\t"
+    "popl        %ebx               \n\t"
+    "movl        %ebx,28(%eax)      \n\t"
+    "pop         %es                \n\t"
+    "popf                           \n\t"
+    "popa                           \n\t"
+    "leave                          \n\t"
+    "ret                            \n\t"
+    ".previous");
+
 
 /*
  *	cru_detect
@@ -333,43 +337,44 @@
 
 #define HPWDT_ARCH	64
 
-asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
-			       unsigned long *pRomEntry)
-{
-	asm("pushq      %rbp            \n\t"
-	    "movq       %rsp, %rbp      \n\t"
-	    "pushq      %rax            \n\t"
-	    "pushq      %rbx            \n\t"
-	    "pushq      %rdx            \n\t"
-	    "pushq      %r12            \n\t"
-	    "pushq      %r9             \n\t"
-	    "movq       %rsi, %r12      \n\t"
-	    "movq       %rdi, %r9       \n\t"
-	    "movl       4(%r9),%ebx     \n\t"
-	    "movl       8(%r9),%ecx     \n\t"
-	    "movl       12(%r9),%edx    \n\t"
-	    "movl       16(%r9),%esi    \n\t"
-	    "movl       20(%r9),%edi    \n\t"
-	    "movl       (%r9),%eax      \n\t"
-	    "call       *%r12           \n\t"
-	    "pushfq                     \n\t"
-	    "popq        %r12           \n\t"
-	    "popfq                      \n\t"
-	    "movl       %eax, (%r9)     \n\t"
-	    "movl       %ebx, 4(%r9)    \n\t"
-	    "movl       %ecx, 8(%r9)    \n\t"
-	    "movl       %edx, 12(%r9)   \n\t"
-	    "movl       %esi, 16(%r9)   \n\t"
-	    "movl       %edi, 20(%r9)   \n\t"
-	    "movq       %r12, %rax      \n\t"
-	    "movl       %eax, 28(%r9)   \n\t"
-	    "popq       %r9             \n\t"
-	    "popq       %r12            \n\t"
-	    "popq       %rdx            \n\t"
-	    "popq       %rbx            \n\t"
-	    "popq       %rax            \n\t"
-	    "leave                      \n\t" "ret");
-}
+asm(".text                      \n\t"
+    ".align 4                   \n"
+    "asminline_call:            \n\t"
+    "pushq      %rbp            \n\t"
+    "movq       %rsp, %rbp      \n\t"
+    "pushq      %rax            \n\t"
+    "pushq      %rbx            \n\t"
+    "pushq      %rdx            \n\t"
+    "pushq      %r12            \n\t"
+    "pushq      %r9             \n\t"
+    "movq       %rsi, %r12      \n\t"
+    "movq       %rdi, %r9       \n\t"
+    "movl       4(%r9),%ebx     \n\t"
+    "movl       8(%r9),%ecx     \n\t"
+    "movl       12(%r9),%edx    \n\t"
+    "movl       16(%r9),%esi    \n\t"
+    "movl       20(%r9),%edi    \n\t"
+    "movl       (%r9),%eax      \n\t"
+    "call       *%r12           \n\t"
+    "pushfq                     \n\t"
+    "popq        %r12           \n\t"
+    "popfq                      \n\t"
+    "movl       %eax, (%r9)     \n\t"
+    "movl       %ebx, 4(%r9)    \n\t"
+    "movl       %ecx, 8(%r9)    \n\t"
+    "movl       %edx, 12(%r9)   \n\t"
+    "movl       %esi, 16(%r9)   \n\t"
+    "movl       %edi, 20(%r9)   \n\t"
+    "movq       %r12, %rax      \n\t"
+    "movl       %eax, 28(%r9)   \n\t"
+    "popq       %r9             \n\t"
+    "popq       %r12            \n\t"
+    "popq       %rdx            \n\t"
+    "popq       %rbx            \n\t"
+    "popq       %rax            \n\t"
+    "leave                      \n\t"
+    "ret                        \n\t"
+    ".previous");
 
 /*
  *	dmi_find_cru
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index fd01d90..57997fa 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -51,4 +51,4 @@
 int v9fs_file_open(struct inode *inode, struct file *file);
 void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat);
 void v9fs_dentry_release(struct dentry *);
-int v9fs_uflags2omode(int uflags);
+int v9fs_uflags2omode(int uflags, int extended);
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 0d55aff..52944d2 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -59,7 +59,7 @@
 
 	P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
 	v9ses = v9fs_inode2v9ses(inode);
-	omode = v9fs_uflags2omode(file->f_flags);
+	omode = v9fs_uflags2omode(file->f_flags, v9fs_extended(v9ses));
 	fid = file->private_data;
 	if (!fid) {
 		fid = v9fs_fid_clone(file->f_path.dentry);
@@ -75,6 +75,8 @@
 			inode->i_size = 0;
 			inode->i_blocks = 0;
 		}
+		if ((file->f_flags & O_APPEND) && (!v9fs_extended(v9ses)))
+			generic_file_llseek(file, 0, SEEK_END);
 	}
 
 	file->private_data = fid;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 40fa807..c95295c 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -132,10 +132,10 @@
 /**
  * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits
  * @uflags: flags to convert
- *
+ * @extended: if .u extensions are active
  */
 
-int v9fs_uflags2omode(int uflags)
+int v9fs_uflags2omode(int uflags, int extended)
 {
 	int ret;
 
@@ -155,14 +155,16 @@
 		break;
 	}
 
-	if (uflags & O_EXCL)
-		ret |= P9_OEXCL;
-
 	if (uflags & O_TRUNC)
 		ret |= P9_OTRUNC;
 
-	if (uflags & O_APPEND)
-		ret |= P9_OAPPEND;
+	if (extended) {
+		if (uflags & O_EXCL)
+			ret |= P9_OEXCL;
+
+		if (uflags & O_APPEND)
+			ret |= P9_OAPPEND;
+	}
 
 	return ret;
 }
@@ -506,7 +508,7 @@
 		flags = O_RDWR;
 
 	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
-						v9fs_uflags2omode(flags));
+				v9fs_uflags2omode(flags, v9fs_extended(v9ses)));
 	if (IS_ERR(fid)) {
 		err = PTR_ERR(fid);
 		fid = NULL;
diff --git a/fs/Kconfig b/fs/Kconfig
index cf12c40..2694648 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -830,7 +830,7 @@
 	  from the project web site.
 
 	  For more information see <file:Documentation/filesystems/ntfs.txt>
-	  and <http://linux-ntfs.sourceforge.net/>.
+	  and <http://www.linux-ntfs.org/>.
 
 	  To compile this file system support as a module, choose M here: the
 	  module will be called ntfs.
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 470c10c..10d8a0a 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -931,8 +931,16 @@
 	struct gendisk *disk;
 	int ret;
 	int part;
+	int perm = 0;
 
-	ret = devcgroup_inode_permission(bdev->bd_inode, file->f_mode);
+	if (file->f_mode & FMODE_READ)
+		perm |= MAY_READ;
+	if (file->f_mode & FMODE_WRITE)
+		perm |= MAY_WRITE;
+	/*
+	 * hooks: /n/, see "layering violations".
+	 */
+	ret = devcgroup_inode_permission(bdev->bd_inode, perm);
 	if (ret != 0)
 		return ret;
 
diff --git a/fs/buffer.c b/fs/buffer.c
index a073f3f..0f51c0f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -821,7 +821,7 @@
 				 * contents - it is a noop if I/O is still in
 				 * flight on potentially older contents.
 				 */
-				ll_rw_block(SWRITE, 1, &bh);
+				ll_rw_block(SWRITE_SYNC, 1, &bh);
 				brelse(bh);
 				spin_lock(lock);
 			}
@@ -2940,16 +2940,19 @@
 	for (i = 0; i < nr; i++) {
 		struct buffer_head *bh = bhs[i];
 
-		if (rw == SWRITE)
+		if (rw == SWRITE || rw == SWRITE_SYNC)
 			lock_buffer(bh);
 		else if (test_set_buffer_locked(bh))
 			continue;
 
-		if (rw == WRITE || rw == SWRITE) {
+		if (rw == WRITE || rw == SWRITE || rw == SWRITE_SYNC) {
 			if (test_clear_buffer_dirty(bh)) {
 				bh->b_end_io = end_buffer_write_sync;
 				get_bh(bh);
-				submit_bh(WRITE, bh);
+				if (rw == SWRITE_SYNC)
+					submit_bh(WRITE_SYNC, bh);
+				else
+					submit_bh(WRITE, bh);
 				continue;
 			}
 		} else {
@@ -2978,7 +2981,7 @@
 	if (test_clear_buffer_dirty(bh)) {
 		get_bh(bh);
 		bh->b_end_io = end_buffer_write_sync;
-		ret = submit_bh(WRITE, bh);
+		ret = submit_bh(WRITE_SYNC, bh);
 		wait_on_buffer(bh);
 		if (buffer_eopnotsupp(bh)) {
 			clear_buffer_eopnotsupp(bh);
diff --git a/fs/dcache.c b/fs/dcache.c
index 3ee588d5..6068c25 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -17,6 +17,7 @@
 #include <linux/syscalls.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/fsnotify.h>
 #include <linux/slab.h>
@@ -106,9 +107,10 @@
 /*
  * Release the dentry's inode, using the filesystem
  * d_iput() operation if defined.
- * Called with dcache_lock and per dentry lock held, drops both.
  */
 static void dentry_iput(struct dentry * dentry)
+	__releases(dentry->d_lock)
+	__releases(dcache_lock)
 {
 	struct inode *inode = dentry->d_inode;
 	if (inode) {
@@ -132,12 +134,13 @@
  * d_kill - kill dentry and return parent
  * @dentry: dentry to kill
  *
- * Called with dcache_lock and d_lock, releases both.  The dentry must
- * already be unhashed and removed from the LRU.
+ * The dentry must already be unhashed and removed from the LRU.
  *
  * If this is the root of the dentry tree, return NULL.
  */
 static struct dentry *d_kill(struct dentry *dentry)
+	__releases(dentry->d_lock)
+	__releases(dcache_lock)
 {
 	struct dentry *parent;
 
@@ -383,11 +386,11 @@
  * Try to prune ancestors as well.  This is necessary to prevent
  * quadratic behavior of shrink_dcache_parent(), but is also expected
  * to be beneficial in reducing dentry cache fragmentation.
- *
- * Called with dcache_lock, drops it and then regains.
- * Called with dentry->d_lock held, drops it.
  */
 static void prune_one_dentry(struct dentry * dentry)
+	__releases(dentry->d_lock)
+	__releases(dcache_lock)
+	__acquires(dcache_lock)
 {
 	__d_drop(dentry);
 	dentry = d_kill(dentry);
@@ -1604,10 +1607,9 @@
  *
  * Note: If ever the locking in lock_rename() changes, then please
  * remember to update this too...
- *
- * On return, dcache_lock will have been unlocked.
  */
 static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
+	__releases(dcache_lock)
 {
 	struct mutex *m1 = NULL, *m2 = NULL;
 	struct dentry *ret;
@@ -1743,11 +1745,9 @@
 shouldnt_be_hashed:
 	spin_unlock(&dcache_lock);
 	BUG();
-	goto shouldnt_be_hashed;
 }
 
-static int prepend(char **buffer, int *buflen, const char *str,
-			  int namelen)
+static int prepend(char **buffer, int *buflen, const char *str, int namelen)
 {
 	*buflen -= namelen;
 	if (*buflen < 0)
@@ -1757,8 +1757,13 @@
 	return 0;
 }
 
+static int prepend_name(char **buffer, int *buflen, struct qstr *name)
+{
+	return prepend(buffer, buflen, name->name, name->len);
+}
+
 /**
- * d_path - return the path of a dentry
+ * __d_path - return the path of a dentry
  * @path: the dentry/vfsmount to report
  * @root: root vfsmnt/dentry (may be modified by this function)
  * @buffer: buffer to return value in
@@ -1779,9 +1784,10 @@
 {
 	struct dentry *dentry = path->dentry;
 	struct vfsmount *vfsmnt = path->mnt;
-	char * end = buffer+buflen;
-	char * retval;
+	char *end = buffer + buflen;
+	char *retval;
 
+	spin_lock(&vfsmount_lock);
 	prepend(&end, &buflen, "\0", 1);
 	if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
 		(prepend(&end, &buflen, " (deleted)", 10) != 0))
@@ -1800,38 +1806,37 @@
 			break;
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
 			/* Global root? */
-			spin_lock(&vfsmount_lock);
 			if (vfsmnt->mnt_parent == vfsmnt) {
-				spin_unlock(&vfsmount_lock);
 				goto global_root;
 			}
 			dentry = vfsmnt->mnt_mountpoint;
 			vfsmnt = vfsmnt->mnt_parent;
-			spin_unlock(&vfsmount_lock);
 			continue;
 		}
 		parent = dentry->d_parent;
 		prefetch(parent);
-		if ((prepend(&end, &buflen, dentry->d_name.name,
-				dentry->d_name.len) != 0) ||
+		if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
 		    (prepend(&end, &buflen, "/", 1) != 0))
 			goto Elong;
 		retval = end;
 		dentry = parent;
 	}
 
+out:
+	spin_unlock(&vfsmount_lock);
 	return retval;
 
 global_root:
 	retval += 1;	/* hit the slash */
-	if (prepend(&retval, &buflen, dentry->d_name.name,
-		    dentry->d_name.len) != 0)
+	if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)
 		goto Elong;
 	root->mnt = vfsmnt;
 	root->dentry = dentry;
-	return retval;
+	goto out;
+
 Elong:
-	return ERR_PTR(-ENAMETOOLONG);
+	retval = ERR_PTR(-ENAMETOOLONG);
+	goto out;
 }
 
 /**
@@ -1845,9 +1850,9 @@
  *
  * Returns the buffer or an error code if the path was too long.
  *
- * "buflen" should be positive. Caller holds the dcache_lock.
+ * "buflen" should be positive.
  */
-char *d_path(struct path *path, char *buf, int buflen)
+char *d_path(const struct path *path, char *buf, int buflen)
 {
 	char *res;
 	struct path root;
@@ -1915,16 +1920,11 @@
 	retval = end-1;
 	*retval = '/';
 
-	for (;;) {
-		struct dentry *parent;
-		if (IS_ROOT(dentry))
-			break;
+	while (!IS_ROOT(dentry)) {
+		struct dentry *parent = dentry->d_parent;
 
-		parent = dentry->d_parent;
 		prefetch(parent);
-
-		if ((prepend(&end, &buflen, dentry->d_name.name,
-				dentry->d_name.len) != 0) ||
+		if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
 		    (prepend(&end, &buflen, "/", 1) != 0))
 			goto Elong;
 
@@ -1975,7 +1975,7 @@
 	error = -ENOENT;
 	/* Has the current directory has been unlinked? */
 	spin_lock(&dcache_lock);
-	if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) {
+	if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) {
 		unsigned long len;
 		struct path tmp = root;
 		char * cwd;
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index 50c994a..09a4522 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -575,13 +575,11 @@
 	int rc;
 
 	atomic_set(&ecryptfs_num_miscdev_opens, 0);
-	mutex_lock(&ecryptfs_daemon_hash_mux);
 	rc = misc_register(&ecryptfs_miscdev);
 	if (rc)
 		printk(KERN_ERR "%s: Failed to register miscellaneous device "
 		       "for communications with userspace daemons; rc = [%d]\n",
 		       __func__, rc);
-	mutex_unlock(&ecryptfs_daemon_hash_mux);
 	return rc;
 }
 
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index fe3119a..2845425 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2875,8 +2875,10 @@
 		blk++;
 	}
 out:
-	if (len == towrite)
+	if (len == towrite) {
+		mutex_unlock(&inode->i_mutex);
 		return err;
+	}
 	if (inode->i_size < off+len-towrite) {
 		i_size_write(inode, off+len-towrite);
 		EXT3_I(inode)->i_disksize = inode->i_size;
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 9ecb92f..9ff7b1c 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -855,7 +855,8 @@
 	 */
 
 	/* Update group descriptor block for new group */
-	gdp = (struct ext4_group_desc *)primary->b_data + gdb_off;
+	gdp = (struct ext4_group_desc *)((char *)primary->b_data +
+					 gdb_off * EXT4_DESC_SIZE(sb));
 
 	ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */
 	ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index cb96f127c..02bf243 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3337,8 +3337,10 @@
 		blk++;
 	}
 out:
-	if (len == towrite)
+	if (len == towrite) {
+		mutex_unlock(&inode->i_mutex);
 		return err;
+	}
 	if (inode->i_size < off+len-towrite) {
 		i_size_write(inode, off+len-towrite);
 		EXT4_I(inode)->i_disksize = inode->i_size;
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index c19184f..bec76b1 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -246,15 +246,11 @@
 
 }
 
-static inline unsigned int zero_metapath_length(const struct metapath *mp,
-						unsigned height)
+static inline unsigned int metapath_branch_start(const struct metapath *mp)
 {
-	unsigned int i;
-	for (i = 0; i < height - 1; i++) {
-		if (mp->mp_list[i] != 0)
-			return i;
-	}
-	return height;
+	if (mp->mp_list[0] == 0)
+		return 2;
+	return 1;
 }
 
 /**
@@ -436,7 +432,7 @@
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct buffer_head *dibh = mp->mp_bh[0];
 	u64 bn, dblock = 0;
-	unsigned n, i, blks, alloced = 0, iblks = 0, zmpl = 0;
+	unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
 	unsigned dblks = 0;
 	unsigned ptrs_per_blk;
 	const unsigned end_of_metadata = height - 1;
@@ -471,9 +467,8 @@
 			/* Building up tree height */
 			state = ALLOC_GROW_HEIGHT;
 			iblks = height - ip->i_height;
-			zmpl = zero_metapath_length(mp, height);
-			iblks -= zmpl;
-			iblks += height;
+			branch_start = metapath_branch_start(mp);
+			iblks += (height - branch_start);
 		}
 	}
 
@@ -509,13 +504,13 @@
 					sizeof(struct gfs2_meta_header));
 				*ptr = zero_bn;
 				state = ALLOC_GROW_DEPTH;
-				for(i = zmpl; i < height; i++) {
+				for(i = branch_start; i < height; i++) {
 					if (mp->mp_bh[i] == NULL)
 						break;
 					brelse(mp->mp_bh[i]);
 					mp->mp_bh[i] = NULL;
 				}
-				i = zmpl;
+				i = branch_start;
 			}
 			if (n == 0)
 				break;
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 6387523..3401628 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -195,7 +195,7 @@
 	   depending on architecture.  I've experimented with several ways
 	   of writing this section such as using an else before the goto
 	   but this one seems to be the fastest. */
-	while ((unsigned char *)plong < end - 1) {
+	while ((unsigned char *)plong < end - sizeof(unsigned long)) {
 		prefetch(plong + 1);
 		if (((*plong) & LBITMASK) != lskipval)
 			break;
diff --git a/fs/libfs.c b/fs/libfs.c
index 892d41c..baeb71e 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -512,6 +512,20 @@
 	mntput(mnt);
 }
 
+/**
+ * simple_read_from_buffer - copy data from the buffer to user space
+ * @to: the user space buffer to read to
+ * @count: the maximum number of bytes to read
+ * @ppos: the current position in the buffer
+ * @from: the buffer to read from
+ * @available: the size of the buffer
+ *
+ * The simple_read_from_buffer() function reads up to @count bytes from the
+ * buffer @from at offset @ppos into the user space address starting at @to.
+ *
+ * On success, the number of bytes read is returned and the offset @ppos is
+ * advanced by this number, or negative value is returned on error.
+ **/
 ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos,
 				const void *from, size_t available)
 {
@@ -528,6 +542,20 @@
 	return count;
 }
 
+/**
+ * memory_read_from_buffer - copy data from the buffer
+ * @to: the kernel space buffer to read to
+ * @count: the maximum number of bytes to read
+ * @ppos: the current position in the buffer
+ * @from: the buffer to read from
+ * @available: the size of the buffer
+ *
+ * The memory_read_from_buffer() function reads up to @count bytes from the
+ * buffer @from at offset @ppos into the kernel space address starting at @to.
+ *
+ * On success, the number of bytes read is returned and the offset @ppos is
+ * advanced by this number, or negative value is returned on error.
+ **/
 ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos,
 				const void *from, size_t available)
 {
diff --git a/fs/locks.c b/fs/locks.c
index 11dbf08..dce8c747 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -561,9 +561,6 @@
 	/* insert into file's list */
 	fl->fl_next = *pos;
 	*pos = fl;
-
-	if (fl->fl_ops && fl->fl_ops->fl_insert)
-		fl->fl_ops->fl_insert(fl);
 }
 
 /*
@@ -586,9 +583,6 @@
 		fl->fl_fasync = NULL;
 	}
 
-	if (fl->fl_ops && fl->fl_ops->fl_remove)
-		fl->fl_ops->fl_remove(fl);
-
 	if (fl->fl_nspid) {
 		put_pid(fl->fl_nspid);
 		fl->fl_nspid = NULL;
diff --git a/fs/namei.c b/fs/namei.c
index c7e4353..01e67dd 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -581,15 +581,13 @@
 	int result;
 
 	/* make sure the stuff we saved doesn't go away */
-	dget(save.dentry);
-	mntget(save.mnt);
+	path_get(&save);
 
 	result = __link_path_walk(name, nd);
 	if (result == -ESTALE) {
 		/* nd->path had been dropped */
 		nd->path = save;
-		dget(nd->path.dentry);
-		mntget(nd->path.mnt);
+		path_get(&nd->path);
 		nd->flags |= LOOKUP_REVAL;
 		result = __link_path_walk(name, nd);
 	}
@@ -1216,8 +1214,9 @@
 	nd->flags = flags;
 	nd->depth = 0;
 
-	nd->path.mnt = mntget(mnt);
-	nd->path.dentry = dget(dentry);
+	nd->path.dentry = dentry;
+	nd->path.mnt = mnt;
+	path_get(&nd->path);
 
 	retval = path_walk(name, nd);
 	if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
@@ -2857,16 +2856,17 @@
 {
 	struct nameidata nd;
 	void *cookie;
+	int res;
 
 	nd.depth = 0;
 	cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
-	if (!IS_ERR(cookie)) {
-		int res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
-		if (dentry->d_inode->i_op->put_link)
-			dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
-		cookie = ERR_PTR(res);
-	}
-	return PTR_ERR(cookie);
+	if (IS_ERR(cookie))
+		return PTR_ERR(cookie);
+
+	res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
+	if (dentry->d_inode->i_op->put_link)
+		dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
+	return res;
 }
 
 int vfs_follow_link(struct nameidata *nd, const char *link)
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index 49c7cd0..779d2eb 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -130,10 +130,11 @@
 				struct mnt_fhstatus *res)
 {
 	struct nfs_fh *fh = res->fh;
+	unsigned size;
 
 	if ((res->status = ntohl(*p++)) == 0) {
-		int size = ntohl(*p++);
-		if (size <= NFS3_FHSIZE) {
+		size = ntohl(*p++);
+		if (size <= NFS3_FHSIZE && size != 0) {
 			fh->size = size;
 			memcpy(fh->data, p, size);
 		} else
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2a4a024..614efee 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1216,8 +1216,6 @@
 {
 	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
 
-	memset(args, 0, sizeof(*args));
-
 	if (data == NULL)
 		goto out_no_data;
 
@@ -1251,13 +1249,13 @@
 	case 5:
 		memset(data->context, 0, sizeof(data->context));
 	case 6:
-		if (data->flags & NFS_MOUNT_VER3)
+		if (data->flags & NFS_MOUNT_VER3) {
+			if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
+				goto out_invalid_fh;
 			mntfh->size = data->root.size;
-		else
+		} else
 			mntfh->size = NFS2_FHSIZE;
 
-		if (mntfh->size > sizeof(mntfh->data))
-			goto out_invalid_fh;
 
 		memcpy(mntfh->data, data->root.data, mntfh->size);
 		if (mntfh->size < sizeof(mntfh->data))
@@ -1585,24 +1583,29 @@
 {
 	struct nfs_server *server = NULL;
 	struct super_block *s;
-	struct nfs_fh mntfh;
-	struct nfs_parsed_mount_data data;
+	struct nfs_parsed_mount_data *data;
+	struct nfs_fh *mntfh;
 	struct dentry *mntroot;
 	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
 	struct nfs_sb_mountdata sb_mntdata = {
 		.mntflags = flags,
 	};
-	int error;
+	int error = -ENOMEM;
 
-	security_init_mnt_opts(&data.lsm_opts);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
+	if (data == NULL || mntfh == NULL)
+		goto out_free_fh;
+
+	security_init_mnt_opts(&data->lsm_opts);
 
 	/* Validate the mount data */
-	error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name);
+	error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
 	if (error < 0)
 		goto out;
 
 	/* Get a volume representation */
-	server = nfs_create_server(&data, &mntfh);
+	server = nfs_create_server(data, mntfh);
 	if (IS_ERR(server)) {
 		error = PTR_ERR(server);
 		goto out;
@@ -1630,16 +1633,16 @@
 
 	if (!s->s_root) {
 		/* initial superblock/root creation */
-		nfs_fill_super(s, &data);
+		nfs_fill_super(s, data);
 	}
 
-	mntroot = nfs_get_root(s, &mntfh);
+	mntroot = nfs_get_root(s, mntfh);
 	if (IS_ERR(mntroot)) {
 		error = PTR_ERR(mntroot);
 		goto error_splat_super;
 	}
 
-	error = security_sb_set_mnt_opts(s, &data.lsm_opts);
+	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
 	if (error)
 		goto error_splat_root;
 
@@ -1649,9 +1652,12 @@
 	error = 0;
 
 out:
-	kfree(data.nfs_server.hostname);
-	kfree(data.mount_server.hostname);
-	security_free_mnt_opts(&data.lsm_opts);
+	kfree(data->nfs_server.hostname);
+	kfree(data->mount_server.hostname);
+	security_free_mnt_opts(&data->lsm_opts);
+out_free_fh:
+	kfree(mntfh);
+	kfree(data);
 	return error;
 
 out_err_nosb:
@@ -1800,8 +1806,6 @@
 	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
 	char *c;
 
-	memset(args, 0, sizeof(*args));
-
 	if (data == NULL)
 		goto out_no_data;
 
@@ -1959,26 +1963,31 @@
 static int nfs4_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
 {
-	struct nfs_parsed_mount_data data;
+	struct nfs_parsed_mount_data *data;
 	struct super_block *s;
 	struct nfs_server *server;
-	struct nfs_fh mntfh;
+	struct nfs_fh *mntfh;
 	struct dentry *mntroot;
 	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
 	struct nfs_sb_mountdata sb_mntdata = {
 		.mntflags = flags,
 	};
-	int error;
+	int error = -ENOMEM;
 
-	security_init_mnt_opts(&data.lsm_opts);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
+	if (data == NULL || mntfh == NULL)
+		goto out_free_fh;
+
+	security_init_mnt_opts(&data->lsm_opts);
 
 	/* Validate the mount data */
-	error = nfs4_validate_mount_data(raw_data, &data, dev_name);
+	error = nfs4_validate_mount_data(raw_data, data, dev_name);
 	if (error < 0)
 		goto out;
 
 	/* Get a volume representation */
-	server = nfs4_create_server(&data, &mntfh);
+	server = nfs4_create_server(data, mntfh);
 	if (IS_ERR(server)) {
 		error = PTR_ERR(server);
 		goto out;
@@ -2009,13 +2018,13 @@
 		nfs4_fill_super(s);
 	}
 
-	mntroot = nfs4_get_root(s, &mntfh);
+	mntroot = nfs4_get_root(s, mntfh);
 	if (IS_ERR(mntroot)) {
 		error = PTR_ERR(mntroot);
 		goto error_splat_super;
 	}
 
-	error = security_sb_set_mnt_opts(s, &data.lsm_opts);
+	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
 	if (error)
 		goto error_splat_root;
 
@@ -2025,10 +2034,13 @@
 	error = 0;
 
 out:
-	kfree(data.client_address);
-	kfree(data.nfs_server.export_path);
-	kfree(data.nfs_server.hostname);
-	security_free_mnt_opts(&data.lsm_opts);
+	kfree(data->client_address);
+	kfree(data->nfs_server.export_path);
+	kfree(data->nfs_server.hostname);
+	security_free_mnt_opts(&data->lsm_opts);
+out_free_fh:
+	kfree(mntfh);
+	kfree(data);
 	return error;
 
 out_free:
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 6d8ace3..f333848 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -739,12 +739,13 @@
 	}
 
 	status = nfs_writepage_setup(ctx, page, offset, count);
-	__set_page_dirty_nobuffers(page);
+	if (status < 0)
+		nfs_set_pageerror(page);
+	else
+		__set_page_dirty_nobuffers(page);
 
         dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
 			status, (long long)i_size_read(inode));
-	if (status < 0)
-		nfs_set_pageerror(page);
 	return status;
 }
 
diff --git a/fs/open.c b/fs/open.c
index a145008..a99ad09 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -16,6 +16,7 @@
 #include <linux/namei.h>
 #include <linux/backing-dev.h>
 #include <linux/capability.h>
+#include <linux/securebits.h>
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
@@ -425,7 +426,7 @@
 {
 	struct nameidata nd;
 	int old_fsuid, old_fsgid;
-	kernel_cap_t old_cap;
+	kernel_cap_t uninitialized_var(old_cap);  /* !SECURE_NO_SETUID_FIXUP */
 	int res;
 
 	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
@@ -433,23 +434,27 @@
 
 	old_fsuid = current->fsuid;
 	old_fsgid = current->fsgid;
-	old_cap = current->cap_effective;
 
 	current->fsuid = current->uid;
 	current->fsgid = current->gid;
 
-	/*
-	 * Clear the capabilities if we switch to a non-root user
-	 *
-	 * FIXME: There is a race here against sys_capset.  The
-	 * capabilities can change yet we will restore the old
-	 * value below.  We should hold task_capabilities_lock,
-	 * but we cannot because user_path_walk can sleep.
-	 */
-	if (current->uid)
-		cap_clear(current->cap_effective);
-	else
-		current->cap_effective = current->cap_permitted;
+	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
+		/*
+		 * Clear the capabilities if we switch to a non-root user
+		 */
+#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
+		/*
+		 * FIXME: There is a race here against sys_capset.  The
+		 * capabilities can change yet we will restore the old
+		 * value below.  We should hold task_capabilities_lock,
+		 * but we cannot because user_path_walk can sleep.
+		 */
+#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
+		if (current->uid)
+			old_cap = cap_set_effective(__cap_empty_set);
+		else
+			old_cap = cap_set_effective(current->cap_permitted);
+	}
 
 	res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
 	if (res)
@@ -478,7 +483,9 @@
 out:
 	current->fsuid = old_fsuid;
 	current->fsgid = old_fsgid;
-	current->cap_effective = old_cap;
+
+	if (!issecure(SECURE_NO_SETUID_FIXUP))
+		cap_set_effective(old_cap);
 
 	return res;
 }
diff --git a/fs/pipe.c b/fs/pipe.c
index ec228bc..700f4e0 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1003,8 +1003,7 @@
 void free_write_pipe(struct file *f)
 {
 	free_pipe_info(f->f_dentry->d_inode);
-	dput(f->f_path.dentry);
-	mntput(f->f_path.mnt);
+	path_put(&f->f_path);
 	put_filp(f);
 }
 
@@ -1015,8 +1014,8 @@
 		return ERR_PTR(-ENFILE);
 
 	/* Grab pipe from the writer */
-	f->f_path.mnt = mntget(wrf->f_path.mnt);
-	f->f_path.dentry = dget(wrf->f_path.dentry);
+	f->f_path = wrf->f_path;
+	path_get(&wrf->f_path);
 	f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
 
 	f->f_pos = 0;
@@ -1068,8 +1067,7 @@
  err_fdr:
 	put_unused_fd(fdr);
  err_read_pipe:
-	dput(fr->f_dentry);
-	mntput(fr->f_vfsmnt);
+	path_put(&fr->f_path);
 	put_filp(fr);
  err_write_pipe:
 	free_write_pipe(fw);
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index ed424d7..1d40f2b 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -2165,8 +2165,10 @@
 		blk++;
 	}
 out:
-	if (len == towrite)
+	if (len == towrite) {
+		mutex_unlock(&inode->i_mutex);
 		return err;
+	}
 	if (inode->i_size < off + len - towrite)
 		i_size_write(inode, off + len - towrite);
 	inode->i_version++;
diff --git a/fs/select.c b/fs/select.c
index 8dda969..da0e882 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -249,7 +249,6 @@
 						retval++;
 					}
 				}
-				cond_resched();
 			}
 			if (res_in)
 				*rinp = res_in;
@@ -257,6 +256,7 @@
 				*routp = res_out;
 			if (res_ex)
 				*rexp = res_ex;
+			cond_resched();
 		}
 		wait = NULL;
 		if (retval || !*timeout || signal_pending(current))
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 7a5f69b..44cc702 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -682,38 +682,26 @@
 /*
  * Check whether there is an anchor block in the given block
  */
-static int udf_check_anchor_block(struct super_block *sb, sector_t block,
-					bool varconv)
+static int udf_check_anchor_block(struct super_block *sb, sector_t block)
 {
-	struct buffer_head *bh = NULL;
-	tag *t;
+	struct buffer_head *bh;
 	uint16_t ident;
-	uint32_t location;
 
-	if (varconv) {
-		if (udf_fixed_to_variable(block) >=
-		    sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
-			return 0;
-		bh = sb_bread(sb, udf_fixed_to_variable(block));
-	}
-	else
-		bh = sb_bread(sb, block);
+	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
+	    udf_fixed_to_variable(block) >=
+	    sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
+		return 0;
 
+	bh = udf_read_tagged(sb, block, block, &ident);
 	if (!bh)
 		return 0;
-
-	t = (tag *)bh->b_data;
-	ident = le16_to_cpu(t->tagIdent);
-	location = le32_to_cpu(t->tagLocation);
 	brelse(bh);
-	if (ident != TAG_IDENT_AVDP)
-		return 0;
-	return location == block;
+
+	return ident == TAG_IDENT_AVDP;
 }
 
 /* Search for an anchor volume descriptor pointer */
-static sector_t udf_scan_anchors(struct super_block *sb, bool varconv,
-					sector_t lastblock)
+static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock)
 {
 	sector_t last[6];
 	int i;
@@ -739,7 +727,7 @@
 				sb->s_blocksize_bits)
 			continue;
 
-		if (udf_check_anchor_block(sb, last[i], varconv)) {
+		if (udf_check_anchor_block(sb, last[i])) {
 			sbi->s_anchor[0] = last[i];
 			sbi->s_anchor[1] = last[i] - 256;
 			return last[i];
@@ -748,17 +736,17 @@
 		if (last[i] < 256)
 			continue;
 
-		if (udf_check_anchor_block(sb, last[i] - 256, varconv)) {
+		if (udf_check_anchor_block(sb, last[i] - 256)) {
 			sbi->s_anchor[1] = last[i] - 256;
 			return last[i];
 		}
 	}
 
-	if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) {
+	if (udf_check_anchor_block(sb, sbi->s_session + 256)) {
 		sbi->s_anchor[0] = sbi->s_session + 256;
 		return last[0];
 	}
-	if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) {
+	if (udf_check_anchor_block(sb, sbi->s_session + 512)) {
 		sbi->s_anchor[0] = sbi->s_session + 512;
 		return last[0];
 	}
@@ -780,23 +768,24 @@
 	int i;
 	struct udf_sb_info *sbi = UDF_SB(sb);
 
-	lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block);
+	lastblock = udf_scan_anchors(sb, sbi->s_last_block);
 	if (lastblock)
 		goto check_anchor;
 
 	/* No anchor found? Try VARCONV conversion of block numbers */
+	UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
 	/* Firstly, we try to not convert number of the last block */
-	lastblock = udf_scan_anchors(sb, 1,
+	lastblock = udf_scan_anchors(sb,
 				udf_variable_to_fixed(sbi->s_last_block));
-	if (lastblock) {
-		UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+	if (lastblock)
 		goto check_anchor;
-	}
 
 	/* Secondly, we try with converted number of the last block */
-	lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block);
-	if (lastblock)
-		UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+	lastblock = udf_scan_anchors(sb, sbi->s_last_block);
+	if (!lastblock) {
+		/* VARCONV didn't help. Clear it. */
+		UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
+	}
 
 check_anchor:
 	/*
diff --git a/fs/utimes.c b/fs/utimes.c
index af059d5..b6b664e 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -40,14 +40,9 @@
 
 #endif
 
-static bool nsec_special(long nsec)
-{
-	return nsec == UTIME_OMIT || nsec == UTIME_NOW;
-}
-
 static bool nsec_valid(long nsec)
 {
-	if (nsec_special(nsec))
+	if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
 		return true;
 
 	return nsec >= 0 && nsec <= 999999999;
@@ -102,7 +97,11 @@
 	if (error)
 		goto dput_and_out;
 
-	/* Don't worry, the checks are done in inode_change_ok() */
+	if (times && times[0].tv_nsec == UTIME_NOW &&
+		     times[1].tv_nsec == UTIME_NOW)
+		times = NULL;
+
+	/* In most cases, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (times) {
 		error = -EPERM;
@@ -124,28 +123,34 @@
 			newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
 			newattrs.ia_valid |= ATTR_MTIME_SET;
 		}
-	}
 
-	/*
-	 * If times is NULL or both times are either UTIME_OMIT or
-	 * UTIME_NOW, then need to check permissions, because
-	 * inode_change_ok() won't do it.
-	 */
-	if (!times || (nsec_special(times[0].tv_nsec) &&
-		       nsec_special(times[1].tv_nsec))) {
+		/*
+		 * For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT
+		 * cases, we need to make an extra check that is not done by
+		 * inode_change_ok().
+		 */
+		if (((times[0].tv_nsec == UTIME_NOW &&
+			    times[1].tv_nsec == UTIME_OMIT)
+		     ||
+		     (times[0].tv_nsec == UTIME_OMIT &&
+			    times[1].tv_nsec == UTIME_NOW))
+		    && !is_owner_or_cap(inode))
+			goto mnt_drop_write_and_out;
+	} else {
+
+		/*
+		 * If times is NULL (or both times are UTIME_NOW),
+		 * then we need to check permissions, because
+		 * inode_change_ok() won't do it.
+		 */
 		error = -EACCES;
                 if (IS_IMMUTABLE(inode))
 			goto mnt_drop_write_and_out;
 
 		if (!is_owner_or_cap(inode)) {
-			if (f) {
-				if (!(f->f_mode & FMODE_WRITE))
-					goto mnt_drop_write_and_out;
-			} else {
-				error = vfs_permission(&nd, MAY_WRITE);
-				if (error)
-					goto mnt_drop_write_and_out;
-			}
+			error = permission(inode, MAY_WRITE, NULL);
+			if (error)
+				goto mnt_drop_write_and_out;
 		}
 	}
 	mutex_lock(&inode->i_mutex);
@@ -169,14 +174,6 @@
 	if (utimes) {
 		if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
 			return -EFAULT;
-		if ((tstimes[0].tv_nsec == UTIME_OMIT ||
-		     tstimes[0].tv_nsec == UTIME_NOW) &&
-		    tstimes[0].tv_sec != 0)
-			return -EINVAL;
-		if ((tstimes[1].tv_nsec == UTIME_OMIT ||
-		     tstimes[1].tv_nsec == UTIME_NOW) &&
-		    tstimes[1].tv_sec != 0)
-			return -EINVAL;
 
 		/* Nothing to do, we must not even check the path.  */
 		if (tstimes[0].tv_nsec == UTIME_OMIT &&
diff --git a/include/asm-alpha/core_mcpcia.h b/include/asm-alpha/core_mcpcia.h
index 525b4f6..acf55b4 100644
--- a/include/asm-alpha/core_mcpcia.h
+++ b/include/asm-alpha/core_mcpcia.h
@@ -261,7 +261,7 @@
 	}
 #endif
 
-static inline int __mcpcia_is_mmio(unsigned long addr)
+extern inline int __mcpcia_is_mmio(unsigned long addr)
 {
 	return (addr & 0x80000000UL) == 0;
 }
diff --git a/include/asm-alpha/core_t2.h b/include/asm-alpha/core_t2.h
index 90e6b5d..46bfff5 100644
--- a/include/asm-alpha/core_t2.h
+++ b/include/asm-alpha/core_t2.h
@@ -356,13 +356,13 @@
 #define vip	volatile int *
 #define vuip	volatile unsigned int *
 
-static inline u8 t2_inb(unsigned long addr)
+extern inline u8 t2_inb(unsigned long addr)
 {
 	long result = *(vip) ((addr << 5) + T2_IO + 0x00);
 	return __kernel_extbl(result, addr & 3);
 }
 
-static inline void t2_outb(u8 b, unsigned long addr)
+extern inline void t2_outb(u8 b, unsigned long addr)
 {
 	unsigned long w;
 
@@ -371,13 +371,13 @@
 	mb();
 }
 
-static inline u16 t2_inw(unsigned long addr)
+extern inline u16 t2_inw(unsigned long addr)
 {
 	long result = *(vip) ((addr << 5) + T2_IO + 0x08);
 	return __kernel_extwl(result, addr & 3);
 }
 
-static inline void t2_outw(u16 b, unsigned long addr)
+extern inline void t2_outw(u16 b, unsigned long addr)
 {
 	unsigned long w;
 
@@ -386,12 +386,12 @@
 	mb();
 }
 
-static inline u32 t2_inl(unsigned long addr)
+extern inline u32 t2_inl(unsigned long addr)
 {
 	return *(vuip) ((addr << 5) + T2_IO + 0x18);
 }
 
-static inline void t2_outl(u32 b, unsigned long addr)
+extern inline void t2_outl(u32 b, unsigned long addr)
 {
 	*(vuip) ((addr << 5) + T2_IO + 0x18) = b;
 	mb();
@@ -435,7 +435,7 @@
 	set_hae(msb); \
 }
 
-static DEFINE_SPINLOCK(t2_hae_lock);
+extern spinlock_t t2_hae_lock;
 
 /*
  * NOTE: take T2_DENSE_MEM off in each readX/writeX routine, since
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
index 38f18cf..e971ab0 100644
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -35,7 +35,7 @@
  * register not being up-to-date with respect to the hardware
  * value.
  */
-static inline void __set_hae(unsigned long new_hae)
+extern inline void __set_hae(unsigned long new_hae)
 {
 	unsigned long flags;
 	local_irq_save(flags);
@@ -49,7 +49,7 @@
 	local_irq_restore(flags);
 }
 
-static inline void set_hae(unsigned long new_hae)
+extern inline void set_hae(unsigned long new_hae)
 {
 	if (new_hae != alpha_mv.hae_cache)
 		__set_hae(new_hae);
@@ -176,7 +176,7 @@
 #undef REMAP1
 #undef REMAP2
 
-static inline void __iomem *generic_ioportmap(unsigned long a)
+extern inline void __iomem *generic_ioportmap(unsigned long a)
 {
 	return alpha_mv.mv_ioportmap(a);
 }
diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h
index 6a5be1f..86c08a0 100644
--- a/include/asm-alpha/mmu_context.h
+++ b/include/asm-alpha/mmu_context.h
@@ -23,7 +23,7 @@
 #endif
 
 
-extern inline unsigned long
+static inline unsigned long
 __reload_thread(struct pcb_struct *pcb)
 {
 	register unsigned long a0 __asm__("$16");
@@ -114,7 +114,7 @@
 #define __MMU_EXTERN_INLINE
 #endif
 
-static inline unsigned long
+extern inline unsigned long
 __get_new_mm_context(struct mm_struct *mm, long cpu)
 {
 	unsigned long asn = cpu_last_asn(cpu);
@@ -226,7 +226,7 @@
 # endif
 #endif
 
-extern inline int
+static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
 	int i;
diff --git a/include/asm-alpha/percpu.h b/include/asm-alpha/percpu.h
index 48348fe..3495e8e 100644
--- a/include/asm-alpha/percpu.h
+++ b/include/asm-alpha/percpu.h
@@ -1,6 +1,78 @@
 #ifndef __ALPHA_PERCPU_H
 #define __ALPHA_PERCPU_H
+#include <linux/compiler.h>
+#include <linux/threads.h>
 
-#include <asm-generic/percpu.h>
+/*
+ * Determine the real variable name from the name visible in the
+ * kernel sources.
+ */
+#define per_cpu_var(var) per_cpu__##var
+
+#ifdef CONFIG_SMP
+
+/*
+ * per_cpu_offset() is the offset that has to be added to a
+ * percpu variable to get to the instance for a certain processor.
+ */
+extern unsigned long __per_cpu_offset[NR_CPUS];
+
+#define per_cpu_offset(x) (__per_cpu_offset[x])
+
+#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
+#ifdef CONFIG_DEBUG_PREEMPT
+#define my_cpu_offset per_cpu_offset(smp_processor_id())
+#else
+#define my_cpu_offset __my_cpu_offset
+#endif
+
+#ifndef MODULE
+#define SHIFT_PERCPU_PTR(var, offset) RELOC_HIDE(&per_cpu_var(var), (offset))
+#define PER_CPU_ATTRIBUTES
+#else
+/*
+ * To calculate addresses of locally defined variables, GCC uses 32-bit
+ * displacement from the GP. Which doesn't work for per cpu variables in
+ * modules, as an offset to the kernel per cpu area is way above 4G.
+ *
+ * This forces allocation of a GOT entry for per cpu variable using
+ * ldq instruction with a 'literal' relocation.
+ */
+#define SHIFT_PERCPU_PTR(var, offset) ({		\
+	extern int simple_identifier_##var(void);	\
+	unsigned long __ptr, tmp_gp;			\
+	asm (  "br	%1, 1f		  	      \n\
+	1:	ldgp	%1, 0(%1)	    	      \n\
+		ldq %0, per_cpu__" #var"(%1)\t!literal"		\
+		: "=&r"(__ptr), "=&r"(tmp_gp));		\
+	(typeof(&per_cpu_var(var)))(__ptr + (offset)); })
+
+#define PER_CPU_ATTRIBUTES	__used
+
+#endif /* MODULE */
+
+/*
+ * A percpu variable may point to a discarded regions. The following are
+ * established ways to produce a usable pointer from the percpu variable
+ * offset.
+ */
+#define per_cpu(var, cpu) \
+	(*SHIFT_PERCPU_PTR(var, per_cpu_offset(cpu)))
+#define __get_cpu_var(var) \
+	(*SHIFT_PERCPU_PTR(var, my_cpu_offset))
+#define __raw_get_cpu_var(var) \
+	(*SHIFT_PERCPU_PTR(var, __my_cpu_offset))
+
+#else /* ! SMP */
+
+#define per_cpu(var, cpu)		(*((void)(cpu), &per_cpu_var(var)))
+#define __get_cpu_var(var)		per_cpu_var(var)
+#define __raw_get_cpu_var(var)		per_cpu_var(var)
+
+#define PER_CPU_ATTRIBUTES
+
+#endif /* SMP */
+
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu_var(name)
 
 #endif /* __ALPHA_PERCPU_H */
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index ed221d6..afe20fa 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -184,7 +184,7 @@
    __amask; })
 
 #define __CALL_PAL_R0(NAME, TYPE)				\
-static inline TYPE NAME(void)					\
+extern inline TYPE NAME(void)					\
 {								\
 	register TYPE __r0 __asm__("$0");			\
 	__asm__ __volatile__(					\
@@ -196,7 +196,7 @@
 }
 
 #define __CALL_PAL_W1(NAME, TYPE0)				\
-static inline void NAME(TYPE0 arg0)				\
+extern inline void NAME(TYPE0 arg0)				\
 {								\
 	register TYPE0 __r16 __asm__("$16") = arg0;		\
 	__asm__ __volatile__(					\
@@ -207,7 +207,7 @@
 }
 
 #define __CALL_PAL_W2(NAME, TYPE0, TYPE1)			\
-static inline void NAME(TYPE0 arg0, TYPE1 arg1)			\
+extern inline void NAME(TYPE0 arg0, TYPE1 arg1)			\
 {								\
 	register TYPE0 __r16 __asm__("$16") = arg0;		\
 	register TYPE1 __r17 __asm__("$17") = arg1;		\
@@ -219,7 +219,7 @@
 }
 
 #define __CALL_PAL_RW1(NAME, RTYPE, TYPE0)			\
-static inline RTYPE NAME(TYPE0 arg0)				\
+extern inline RTYPE NAME(TYPE0 arg0)				\
 {								\
 	register RTYPE __r0 __asm__("$0");			\
 	register TYPE0 __r16 __asm__("$16") = arg0;		\
@@ -232,7 +232,7 @@
 }
 
 #define __CALL_PAL_RW2(NAME, RTYPE, TYPE0, TYPE1)		\
-static inline RTYPE NAME(TYPE0 arg0, TYPE1 arg1)		\
+extern inline RTYPE NAME(TYPE0 arg0, TYPE1 arg1)		\
 {								\
 	register RTYPE __r0 __asm__("$0");			\
 	register TYPE0 __r16 __asm__("$16") = arg0;		\
diff --git a/include/asm-alpha/vga.h b/include/asm-alpha/vga.h
index e8df1e7..c00106b 100644
--- a/include/asm-alpha/vga.h
+++ b/include/asm-alpha/vga.h
@@ -13,7 +13,7 @@
 #define VT_BUF_HAVE_MEMSETW
 #define VT_BUF_HAVE_MEMCPYW
 
-extern inline void scr_writew(u16 val, volatile u16 *addr)
+static inline void scr_writew(u16 val, volatile u16 *addr)
 {
 	if (__is_ioaddr(addr))
 		__raw_writew(val, (volatile u16 __iomem *) addr);
@@ -21,7 +21,7 @@
 		*addr = val;
 }
 
-extern inline u16 scr_readw(volatile const u16 *addr)
+static inline u16 scr_readw(volatile const u16 *addr)
 {
 	if (__is_ioaddr(addr))
 		return __raw_readw((volatile const u16 __iomem *) addr);
@@ -29,7 +29,7 @@
 		return *addr;
 }
 
-extern inline void scr_memsetw(u16 *s, u16 c, unsigned int count)
+static inline void scr_memsetw(u16 *s, u16 c, unsigned int count)
 {
 	if (__is_ioaddr(s))
 		memsetw_io((u16 __iomem *) s, c, count);
diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
index 96bd09e..2526b6e 100644
--- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
@@ -96,7 +96,7 @@
 	struct work_struct tx_dma_workqueue;
 #endif
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	struct work_struct cts_workqueue;
+	struct timer_list cts_timer;
 	int cts_pin;
 	int rts_pin;
 #endif
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
index e924569..ebf592b 100644
--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -88,7 +88,7 @@
 # endif
 #endif
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	struct work_struct 	cts_workqueue;
+	struct timer_list       cts_timer;
 	int			cts_pin;
 	int			rts_pin;
 #endif
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
index 41d7b64..1bf56ff 100644
--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -96,7 +96,7 @@
 	struct work_struct	tx_dma_workqueue;
 #endif
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	struct work_struct 	cts_workqueue;
+	struct timer_list 	cts_timer;
 	int		cts_pin;
 	int 		rts_pin;
 #endif
diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
index 59b4ad4..5e29446 100644
--- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
@@ -99,7 +99,7 @@
 	struct work_struct	tx_dma_workqueue;
 #endif
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	struct work_struct 	cts_workqueue;
+	struct timer_list 	cts_timer;
 	int		cts_pin;
 	int 		rts_pin;
 #endif
@@ -187,7 +187,7 @@
 
 #ifdef CONFIG_BFIN_UART1_CTSRTS
 	peripheral_request(P_UART1_RTS, DRIVER_NAME);
-	peripheral_request(P_UART1_CTS DRIVER_NAME);
+	peripheral_request(P_UART1_CTS, DRIVER_NAME);
 #endif
 #endif
 
@@ -202,7 +202,7 @@
 
 #ifdef CONFIG_BFIN_UART3_CTSRTS
 	peripheral_request(P_UART3_RTS, DRIVER_NAME);
-	peripheral_request(P_UART3_CTS DRIVER_NAME);
+	peripheral_request(P_UART3_CTS, DRIVER_NAME);
 #endif
 #endif
 	SSYNC();
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
index 30d90b5..8aa0278 100644
--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -88,7 +88,7 @@
 # endif
 #endif
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	struct work_struct 	cts_workqueue;
+	struct timer_list       cts_timer;
 	int			cts_pin;
 	int			rts_pin;
 #endif
diff --git a/include/asm-generic/Kbuild.asm b/include/asm-generic/Kbuild.asm
index 92a6d91..7cd25b8 100644
--- a/include/asm-generic/Kbuild.asm
+++ b/include/asm-generic/Kbuild.asm
@@ -1,6 +1,6 @@
 header-y  += kvm.h
 
-ifeq ($(wildcard include/asm-$(SRCARCH)/a.out.h),include/asm-$(SRCARCH)/a.out.h)
+ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
 unifdef-y += auxvec.h
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index 85fd0aa..4ec0a29 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -2,7 +2,7 @@
 #define _ASM_GENERIC_ATOMIC_H
 /*
  * Copyright (C) 2005 Silicon Graphics, Inc.
- *	Christoph Lameter <clameter@sgi.com>
+ *	Christoph Lameter
  *
  * Allows to provide arch independent atomic definitions without the need to
  * edit all arch specific atomic.h files.
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index a798d62..1232be3 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -283,10 +283,10 @@
 		"	beqz	%0, 2f					\n"
 		"	 subu	%0, %1, %3				\n"
 		"	.set	reorder					\n"
-		"1:							\n"
 		"	.subsection 2					\n"
 		"2:	b	1b					\n"
 		"	.previous					\n"
+		"1:							\n"
 		"	.set	mips0					\n"
 		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
 		: "Ir" (i), "m" (v->counter)
@@ -664,10 +664,10 @@
 		"	beqz	%0, 2f					\n"
 		"	 dsubu	%0, %1, %3				\n"
 		"	.set	reorder					\n"
-		"1:							\n"
 		"	.subsection 2					\n"
 		"2:	b	1b					\n"
 		"	.previous					\n"
+		"1:							\n"
 		"	.set	mips0					\n"
 		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
 		: "Ir" (i), "m" (v->counter)
diff --git a/include/asm-powerpc/Kbuild b/include/asm-powerpc/Kbuild
index 7381916..bca352e 100644
--- a/include/asm-powerpc/Kbuild
+++ b/include/asm-powerpc/Kbuild
@@ -1,6 +1,5 @@
 include include/asm-generic/Kbuild.asm
 
-header-y += a.out.h
 header-y += auxvec.h
 header-y += ioctls.h
 header-y += mman.h
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index 1d8cd01..844f2a8 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -18,6 +18,7 @@
 #include <linux/kvm_para.h>
 #include <linux/kvm_types.h>
 
+#include <asm/pvclock-abi.h>
 #include <asm/desc.h>
 
 #define KVM_MAX_VCPUS 16
@@ -282,7 +283,8 @@
 	struct x86_emulate_ctxt emulate_ctxt;
 
 	gpa_t time;
-	struct kvm_vcpu_time_info hv_clock;
+	struct pvclock_vcpu_time_info hv_clock;
+	unsigned int hv_clock_tsc_khz;
 	unsigned int time_offset;
 	struct page *time_page;
 };
diff --git a/include/asm-x86/kvm_para.h b/include/asm-x86/kvm_para.h
index 5098459..bfd9900 100644
--- a/include/asm-x86/kvm_para.h
+++ b/include/asm-x86/kvm_para.h
@@ -48,24 +48,6 @@
 #ifdef __KERNEL__
 #include <asm/processor.h>
 
-/* xen binary-compatible interface. See xen headers for details */
-struct kvm_vcpu_time_info {
-	uint32_t version;
-	uint32_t pad0;
-	uint64_t tsc_timestamp;
-	uint64_t system_time;
-	uint32_t tsc_to_system_mul;
-	int8_t   tsc_shift;
-	int8_t	 pad[3];
-} __attribute__((__packed__)); /* 32 bytes */
-
-struct kvm_wall_clock {
-	uint32_t wc_version;
-	uint32_t wc_sec;
-	uint32_t wc_nsec;
-} __attribute__((__packed__));
-
-
 extern void kvmclock_init(void);
 
 
diff --git a/include/asm-x86/pvclock-abi.h b/include/asm-x86/pvclock-abi.h
new file mode 100644
index 0000000..6857f84
--- /dev/null
+++ b/include/asm-x86/pvclock-abi.h
@@ -0,0 +1,42 @@
+#ifndef _ASM_X86_PVCLOCK_ABI_H_
+#define _ASM_X86_PVCLOCK_ABI_H_
+#ifndef __ASSEMBLY__
+
+/*
+ * These structs MUST NOT be changed.
+ * They are the ABI between hypervisor and guest OS.
+ * Both Xen and KVM are using this.
+ *
+ * pvclock_vcpu_time_info holds the system time and the tsc timestamp
+ * of the last update. So the guest can use the tsc delta to get a
+ * more precise system time.  There is one per virtual cpu.
+ *
+ * pvclock_wall_clock references the point in time when the system
+ * time was zero (usually boot time), thus the guest calculates the
+ * current wall clock by adding the system time.
+ *
+ * Protocol for the "version" fields is: hypervisor raises it (making
+ * it uneven) before it starts updating the fields and raises it again
+ * (making it even) when it is done.  Thus the guest can make sure the
+ * time values it got are consistent by checking the version before
+ * and after reading them.
+ */
+
+struct pvclock_vcpu_time_info {
+	u32   version;
+	u32   pad0;
+	u64   tsc_timestamp;
+	u64   system_time;
+	u32   tsc_to_system_mul;
+	s8    tsc_shift;
+	u8    pad[3];
+} __attribute__((__packed__)); /* 32 bytes */
+
+struct pvclock_wall_clock {
+	u32   version;
+	u32   sec;
+	u32   nsec;
+} __attribute__((__packed__));
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_X86_PVCLOCK_ABI_H_ */
diff --git a/include/asm-x86/pvclock.h b/include/asm-x86/pvclock.h
new file mode 100644
index 0000000..85b1bba
--- /dev/null
+++ b/include/asm-x86/pvclock.h
@@ -0,0 +1,13 @@
+#ifndef _ASM_X86_PVCLOCK_H_
+#define _ASM_X86_PVCLOCK_H_
+
+#include <linux/clocksource.h>
+#include <asm/pvclock-abi.h>
+
+/* some helper functions for xen and kvm pv clock sources */
+cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
+void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
+			    struct pvclock_vcpu_time_info *vcpu,
+			    struct timespec *ts);
+
+#endif /* _ASM_X86_PVCLOCK_H_ */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index b6fbb25..71d70d1 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -166,7 +166,7 @@
 unifdef-y += adb.h
 unifdef-y += adfs_fs.h
 unifdef-y += agpgart.h
-ifeq ($(wildcard include/asm-$(SRCARCH)/a.out.h),include/asm-$(SRCARCH)/a.out.h)
+ifneq ($(wildcard $(srctree)/include/asm-$(SRCARCH)/a.out.h),)
 unifdef-y += a.out.h
 endif
 unifdef-y += apm_bios.h
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 63c3bb9..8b82974 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -571,7 +571,7 @@
 extern int		    audit_update_lsm_rules(void);
 
 				/* Private API (for audit.c only) */
-extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
+extern int audit_filter_user(struct netlink_skb_parms *cb);
 extern int audit_filter_type(int type);
 extern int  audit_receive_filter(int type, int pid, int uid, int seq,
 				void *data, size_t datasz, uid_t loginuid,
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 6a5dbdc..686895b 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -94,7 +94,7 @@
 				       unsigned long freepfn,
 				       unsigned long startpfn,
 				       unsigned long endpfn);
-extern void reserve_bootmem_node(pg_data_t *pgdat,
+extern int reserve_bootmem_node(pg_data_t *pgdat,
 				 unsigned long physaddr,
 				 unsigned long size,
 				 int flags);
diff --git a/include/linux/capability.h b/include/linux/capability.h
index fa830f8..0267384 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -501,6 +501,8 @@
 extern const kernel_cap_t __cap_full_set;
 extern const kernel_cap_t __cap_init_eff_set;
 
+kernel_cap_t cap_set_effective(const kernel_cap_t pE_new);
+
 int capable(int cap);
 int __capable(struct task_struct *t, int cap);
 
diff --git a/include/linux/cfag12864b.h b/include/linux/cfag12864b.h
index 1605dd8..6f9f19d 100644
--- a/include/linux/cfag12864b.h
+++ b/include/linux/cfag12864b.h
@@ -4,7 +4,7 @@
  * Description: cfag12864b LCD driver header
  *     License: GPLv2
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-12
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 5df3db5..c24875b 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -353,6 +353,10 @@
 	for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 #endif /* NR_CPUS */
 
+#define next_cpu_nr(n, src)		next_cpu(n, src)
+#define cpus_weight_nr(cpumask)		cpus_weight(cpumask)
+#define for_each_cpu_mask_nr(cpu, mask)	for_each_cpu_mask(cpu, mask)
+
 /*
  * The following particular system cpumasks and operations manage
  * possible, present and online cpus.  Each of them is a fixed size
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 2a66394..d982eb8 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -300,7 +300,7 @@
 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 
 extern char *__d_path(const struct path *path, struct path *root, char *, int);
-extern char *d_path(struct path *, char *, int);
+extern char *d_path(const struct path *, char *, int);
 extern char *dentry_path(struct dentry *, char *, int);
 
 /* Allocation counts.. */
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 4d10c73..6c7eff2 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -13,7 +13,7 @@
 
 struct device;
 
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
+#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE))
 int request_firmware(const struct firmware **fw, const char *name,
 		     struct device *device);
 int request_firmware_nowait(
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d490779..d8e2762 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -83,6 +83,7 @@
 #define READ_SYNC	(READ | (1 << BIO_RW_SYNC))
 #define READ_META	(READ | (1 << BIO_RW_META))
 #define WRITE_SYNC	(WRITE | (1 << BIO_RW_SYNC))
+#define SWRITE_SYNC	(SWRITE | (1 << BIO_RW_SYNC))
 #define WRITE_BARRIER	((1 << BIO_RW) | (1 << BIO_RW_BARRIER))
 
 #define SEL_IN		1
@@ -894,8 +895,6 @@
 typedef struct files_struct *fl_owner_t;
 
 struct file_lock_operations {
-	void (*fl_insert)(struct file_lock *);	/* lock insertion callback */
-	void (*fl_remove)(struct file_lock *);	/* lock removal callback */
 	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
 	void (*fl_release_private)(struct file_lock *);
 };
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index fb9af6a..8dc7301 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -171,7 +171,7 @@
 	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
 	struct i2c_driver *driver;	/* and our access routines	*/
 	struct device dev;		/* the device structure		*/
-	int irq;			/* irq issued by device (or -1) */
+	int irq;			/* irq issued by device		*/
 	struct list_head list;		/* DEPRECATED */
 	struct completion released;
 };
diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h
index 80335b7..c4335fa 100644
--- a/include/linux/inet_lro.h
+++ b/include/linux/inet_lro.h
@@ -84,7 +84,11 @@
 				    from received packets and eth protocol
 				    is still ETH_P_8021Q */
 
-	u32 ip_summed;      /* Set in non generated SKBs in page mode */
+	/*
+	 * Set for generated SKBs that are not added to
+	 * the frag list in fragmented mode
+	 */
+	u32 ip_summed;
 	u32 ip_summed_aggr; /* Set in aggregated SKBs: CHECKSUM_UNNECESSARY
 			     * or CHECKSUM_NONE */
 
diff --git a/include/linux/input.h b/include/linux/input.h
index e075c4b..d150c57 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -534,8 +534,8 @@
 
 #define KEY_FRAMEBACK		0x1b4	/* Consumer - transport controls */
 #define KEY_FRAMEFORWARD	0x1b5
-
 #define KEY_CONTEXT_MENU	0x1b6	/* GenDesc - system context menu */
+#define KEY_MEDIA_REPEAT	0x1b7	/* Consumer - transport control */
 
 #define KEY_DEL_EOL		0x1c0
 #define KEY_DEL_EOS		0x1c1
diff --git a/include/linux/ks0108.h b/include/linux/ks0108.h
index a2c54ac..cb31179 100644
--- a/include/linux/ks0108.h
+++ b/include/linux/ks0108.h
@@ -4,7 +4,7 @@
  * Description: ks0108 LCD Controller driver header
  *     License: GPLv2
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 092b1b2..de9d1df 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -33,6 +33,7 @@
 #define KVM_REQ_REPORT_TPR_ACCESS  2
 #define KVM_REQ_MMU_RELOAD         3
 #define KVM_REQ_TRIPLE_FAULT       4
+#define KVM_REQ_PENDING_TIMER      5
 
 struct kvm_vcpu;
 extern struct kmem_cache *kvm_vcpu_cache;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f27fd20..25f8710 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -88,6 +88,8 @@
 #define NETDEV_TX_BUSY 1	/* driver tx path was busy*/
 #define NETDEV_TX_LOCKED -1	/* driver tx lock was already taken */
 
+#ifdef  __KERNEL__
+
 /*
  *	Compute the worst case header length according to the protocols
  *	used.
@@ -114,6 +116,8 @@
 #define MAX_HEADER (LL_MAX_HEADER + 48)
 #endif
 
+#endif  /*  __KERNEL__  */
+
 struct net_device_subqueue
 {
 	/* Give a control state for each queue.  This struct may contain
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index eafc9d6..6595382 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1520,6 +1520,7 @@
 #define PCI_DEVICE_ID_MARVELL_GT64260	0x6430
 #define PCI_DEVICE_ID_MARVELL_MV64360	0x6460
 #define PCI_DEVICE_ID_MARVELL_MV64460	0x6480
+#define PCI_DEVICE_ID_MARVELL_CAFE_SD	0x4101
 
 #define PCI_VENDOR_ID_V3		0x11b0
 #define PCI_DEVICE_ID_V3_V960		0x0001
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
new file mode 100644
index 0000000..bde4586
--- /dev/null
+++ b/include/linux/rculist.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_RCULIST_H
+#define _LINUX_RCULIST_H
+
+#include <linux/list.h>
+
+#endif	/* _LINUX_RCULIST_H */
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index c1f19db..92f09bd 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -7,14 +7,15 @@
    inheritance of root-permissions and suid-root executable under
    compatibility mode. We raise the effective and inheritable bitmasks
    *of the executable file* if the effective uid of the new process is
-   0. If the real uid is 0, we raise the inheritable bitmask of the
+   0. If the real uid is 0, we raise the effective (legacy) bit of the
    executable file. */
 #define SECURE_NOROOT			0
 #define SECURE_NOROOT_LOCKED		1  /* make bit-0 immutable */
 
-/* When set, setuid to/from uid 0 does not trigger capability-"fixes"
-   to be compatible with old programs relying on set*uid to loose
-   privileges. When unset, setuid doesn't change privileges. */
+/* When set, setuid to/from uid 0 does not trigger capability-"fixup".
+   When unset, to provide compatiblility with old programs relying on
+   set*uid to gain/lose privilege, transitions to/from uid 0 cause
+   capabilities to be gained/lost. */
 #define SECURE_NO_SETUID_FIXUP		2
 #define SECURE_NO_SETUID_FIXUP_LOCKED	3  /* make bit-2 immutable */
 
@@ -26,10 +27,10 @@
 #define SECURE_KEEP_CAPS		4
 #define SECURE_KEEP_CAPS_LOCKED		5  /* make bit-4 immutable */
 
-/* Each securesetting is implemented using two bits. One bit specify
+/* Each securesetting is implemented using two bits. One bit specifies
    whether the setting is on or off. The other bit specify whether the
-   setting is fixed or not. A setting which is fixed cannot be changed
-   from user-level. */
+   setting is locked or not. A setting which is locked cannot be
+   changed from user-level. */
 #define issecure_mask(X)	(1 << (X))
 #define issecure(X)		(issecure_mask(X) & current->securebits)
 
diff --git a/include/linux/slab.h b/include/linux/slab.h
index c2ad350..9aa90a6 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -1,7 +1,7 @@
 /*
  * Written by Mark Hemment, 1996 (markhe@nextd.demon.co.uk).
  *
- * (C) SGI 2006, Christoph Lameter <clameter@sgi.com>
+ * (C) SGI 2006, Christoph Lameter
  * 	Cleaned up and restructured to ease the addition of alternative
  * 	implementations of SLAB allocators.
  */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 71e43a1..d117ea2 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -4,7 +4,7 @@
 /*
  * SLUB : A Slab allocator without object queues.
  *
- * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
+ * (C) 2007 SGI, Christoph Lameter
  */
 #include <linux/types.h>
 #include <linux/gfp.h>
@@ -137,10 +137,12 @@
 	if (size <= KMALLOC_MIN_SIZE)
 		return KMALLOC_SHIFT_LOW;
 
+#if KMALLOC_MIN_SIZE <= 64
 	if (size > 64 && size <= 96)
 		return 1;
 	if (size > 128 && size <= 192)
 		return 2;
+#endif
 	if (size <=          8) return 3;
 	if (size <=         16) return 4;
 	if (size <=         32) return 5;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 06d3e6e..917707e 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -66,8 +66,7 @@
 				((long)t-2732+5)/10 : ((long)t-2732-5)/10)
 #define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
 
-#if defined(CONFIG_HWMON) ||	\
-	(defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+#if defined(CONFIG_THERMAL_HWMON)
 /* thermal zone devices with the same type share one hwmon device */
 struct thermal_hwmon_device {
 	char type[THERMAL_NAME_LENGTH];
@@ -94,8 +93,7 @@
 	struct idr idr;
 	struct mutex lock;	/* protect cooling devices list */
 	struct list_head node;
-#if defined(CONFIG_HWMON) ||	\
-	(defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+#if defined(CONFIG_THERMAL_HWMON)
 	struct list_head hwmon_node;
 	struct thermal_hwmon_device *hwmon;
 	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 59f1c0b..d2a0035 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -27,8 +27,7 @@
  * 	This routine is called by the kernel to write a series of
  * 	characters to the tty device.  The characters may come from
  * 	user space or kernel space.  This routine will return the
- *	number of characters actually accepted for writing.  This
- *	routine is mandatory.
+ *	number of characters actually accepted for writing.
  *
  *	Optional: Required for writable devices.
  *
@@ -134,7 +133,7 @@
  * 	This routine notifies the tty driver that it should hangup the
  * 	tty device.
  *
- *	Required:
+ *	Optional:
  *
  * void (*break_ctl)(struct tty_stuct *tty, int state);
  *
diff --git a/include/media/cx25840.h b/include/media/cx25840.h
index cd599ad..db431d5 100644
--- a/include/media/cx25840.h
+++ b/include/media/cx25840.h
@@ -32,12 +32,16 @@
 	CX25840_COMPOSITE7,
 	CX25840_COMPOSITE8,
 
-	/* S-Video inputs consist of one luma input (In1-In4) ORed with one
+	/* S-Video inputs consist of one luma input (In1-In8) ORed with one
 	   chroma input (In5-In8) */
 	CX25840_SVIDEO_LUMA1 = 0x10,
 	CX25840_SVIDEO_LUMA2 = 0x20,
 	CX25840_SVIDEO_LUMA3 = 0x30,
 	CX25840_SVIDEO_LUMA4 = 0x40,
+	CX25840_SVIDEO_LUMA5 = 0x50,
+	CX25840_SVIDEO_LUMA6 = 0x60,
+	CX25840_SVIDEO_LUMA7 = 0x70,
+	CX25840_SVIDEO_LUMA8 = 0x80,
 	CX25840_SVIDEO_CHROMA4 = 0x400,
 	CX25840_SVIDEO_CHROMA5 = 0x500,
 	CX25840_SVIDEO_CHROMA6 = 0x600,
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index bfee8be..b8e8aa9 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -146,6 +146,7 @@
 extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE];
 
 #endif
 
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 33f01ae..859f7a6 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -40,9 +40,9 @@
 #define VFL_TYPE_VTX		3
 
 /*  Video standard functions  */
-extern char *v4l2_norm_to_name(v4l2_std_id id);
+extern const char *v4l2_norm_to_name(v4l2_std_id id);
 extern int v4l2_video_std_construct(struct v4l2_standard *vs,
-				    int id, char *name);
+				    int id, const char *name);
 /* Prints the ioctl in a human-readable format */
 extern void v4l_printk_ioctl(unsigned int cmd);
 
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index e0a612b..f422f72 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -367,6 +367,12 @@
 		 a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
 }
 
+static inline int ipv6_addr_loopback(const struct in6_addr *a)
+{
+	return ((a->s6_addr32[0] | a->s6_addr32[1] |
+		 a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0);
+}
+
 static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
 {
 	return ((a->s6_addr32[0] | a->s6_addr32[1] |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dae3f9e..bcd1623 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -595,6 +595,15 @@
 	ALG_CCMP,
 };
 
+/**
+ * enum ieee80211_key_len - key length
+ * @WEP40: WEP 5 byte long key
+ * @WEP104: WEP 13 byte long key
+ */
+enum ieee80211_key_len {
+	LEN_WEP40 = 5,
+	LEN_WEP104 = 13,
+};
 
 /**
  * enum ieee80211_key_flags - key flags
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index aa540e6..d9dd0f7 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -95,6 +95,11 @@
 #ifdef CONFIG_NET_NS
 extern void __put_net(struct net *net);
 
+static inline int net_alive(struct net *net)
+{
+	return net && atomic_read(&net->count);
+}
+
 static inline struct net *get_net(struct net *net)
 {
 	atomic_inc(&net->count);
@@ -125,6 +130,12 @@
 	return net1 == net2;
 }
 #else
+
+static inline int net_alive(struct net *net)
+{
+	return 1;
+}
+
 static inline struct net *get_net(struct net *net)
 {
 	return net;
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index ab502ec..a87fc03 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -178,7 +178,7 @@
 extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
 				       struct Qdisc_ops *ops, u32 parentid);
 extern void tcf_destroy(struct tcf_proto *tp);
-extern void tcf_destroy_chain(struct tcf_proto *fl);
+extern void tcf_destroy_chain(struct tcf_proto **fl);
 
 static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 				       struct sk_buff_head *list)
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 9b018da..819a033 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -10,6 +10,7 @@
 #define __XEN_PUBLIC_XEN_H__
 
 #include <asm/xen/interface.h>
+#include <asm/pvclock-abi.h>
 
 /*
  * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
@@ -336,7 +337,7 @@
 	uint8_t evtchn_upcall_mask;
 	unsigned long evtchn_pending_sel;
 	struct arch_vcpu_info arch;
-	struct vcpu_time_info time;
+	struct pvclock_vcpu_time_info time;
 }; /* 64 bytes (x86) */
 
 /*
@@ -384,9 +385,7 @@
 	 * Wallclock time: updated only by control software. Guests should base
 	 * their gettimeofday() syscall on this wallclock-base value.
 	 */
-	uint32_t wc_version;      /* Version counter: see vcpu_time_info_t. */
-	uint32_t wc_sec;          /* Secs  00:00:00 UTC, Jan 1, 1970.  */
-	uint32_t wc_nsec;         /* Nsecs 00:00:00 UTC, Jan 1, 1970.  */
+	struct pvclock_wall_clock wc;
 
 	struct arch_shared_info arch;
 
diff --git a/kernel/audit.c b/kernel/audit.c
index e8692a5..e092f1c 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -738,7 +738,7 @@
 		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
 			return 0;
 
-		err = audit_filter_user(&NETLINK_CB(skb), msg_type);
+		err = audit_filter_user(&NETLINK_CB(skb));
 		if (err == 1) {
 			err = 0;
 			if (msg_type == AUDIT_USER_TTY) {
@@ -779,7 +779,7 @@
 		}
 		/* fallthrough */
 	case AUDIT_LIST:
-		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
+		err = audit_receive_filter(msg_type, NETLINK_CB(skb).pid,
 					   uid, seq, data, nlmsg_len(nlh),
 					   loginuid, sessionid, sid);
 		break;
@@ -798,7 +798,7 @@
 		}
 		/* fallthrough */
 	case AUDIT_LIST_RULES:
-		err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
+		err = audit_receive_filter(msg_type, NETLINK_CB(skb).pid,
 					   uid, seq, data, nlmsg_len(nlh),
 					   loginuid, sessionid, sid);
 		break;
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 0e0bd27e..98c50cc 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1544,6 +1544,7 @@
  * @data: payload data
  * @datasz: size of payload data
  * @loginuid: loginuid of sender
+ * @sessionid: sessionid for netlink audit message
  * @sid: SE Linux Security ID of sender
  */
 int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
@@ -1720,7 +1721,7 @@
 	return 1;
 }
 
-int audit_filter_user(struct netlink_skb_parms *cb, int type)
+int audit_filter_user(struct netlink_skb_parms *cb)
 {
 	enum audit_state state = AUDIT_DISABLED;
 	struct audit_entry *e;
diff --git a/kernel/capability.c b/kernel/capability.c
index cfbe442..901e0fd 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -121,6 +121,27 @@
  * uninteresting and/or not to be changed.
  */
 
+/*
+ * Atomically modify the effective capabilities returning the original
+ * value. No permission check is performed here - it is assumed that the
+ * caller is permitted to set the desired effective capabilities.
+ */
+kernel_cap_t cap_set_effective(const kernel_cap_t pE_new)
+{
+	kernel_cap_t pE_old;
+
+	spin_lock(&task_capability_lock);
+
+	pE_old = current->cap_effective;
+	current->cap_effective = pE_new;
+
+	spin_unlock(&task_capability_lock);
+
+	return pE_old;
+}
+
+EXPORT_SYMBOL(cap_set_effective);
+
 /**
  * sys_capget - get the capabilities of a given process.
  * @header: pointer to struct that contains capability version and
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 039baa4..9fceb97 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1037,8 +1037,8 @@
 
 static int update_relax_domain_level(struct cpuset *cs, s64 val)
 {
-	if ((int)val < 0)
-		val = -1;
+	if (val < -1 || val >= SD_LV_MAX)
+		return -EINVAL;
 
 	if (val != cs->relax_domain_level) {
 		cs->relax_domain_level = val;
@@ -1890,6 +1890,12 @@
 	top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 	scan_for_empty_cpusets(&top_cpuset);
 
+	/*
+	 * Scheduler destroys domains on hotplug events.
+	 * Rebuild them based on the current settings.
+	 */
+	rebuild_sched_domains();
+
 	cgroup_unlock();
 }
 
diff --git a/kernel/futex.c b/kernel/futex.c
index 449def8..7d1136e 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1096,21 +1096,64 @@
  * private futexes.
  */
 static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-				struct task_struct *newowner)
+				struct task_struct *newowner,
+				struct rw_semaphore *fshared)
 {
 	u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
 	struct futex_pi_state *pi_state = q->pi_state;
+	struct task_struct *oldowner = pi_state->owner;
 	u32 uval, curval, newval;
-	int ret;
+	int ret, attempt = 0;
 
 	/* Owner died? */
+	if (!pi_state->owner)
+		newtid |= FUTEX_OWNER_DIED;
+
+	/*
+	 * We are here either because we stole the rtmutex from the
+	 * pending owner or we are the pending owner which failed to
+	 * get the rtmutex. We have to replace the pending owner TID
+	 * in the user space variable. This must be atomic as we have
+	 * to preserve the owner died bit here.
+	 *
+	 * Note: We write the user space value _before_ changing the
+	 * pi_state because we can fault here. Imagine swapped out
+	 * pages or a fork, which was running right before we acquired
+	 * mmap_sem, that marked all the anonymous memory readonly for
+	 * cow.
+	 *
+	 * Modifying pi_state _before_ the user space value would
+	 * leave the pi_state in an inconsistent state when we fault
+	 * here, because we need to drop the hash bucket lock to
+	 * handle the fault. This might be observed in the PID check
+	 * in lookup_pi_state.
+	 */
+retry:
+	if (get_futex_value_locked(&uval, uaddr))
+		goto handle_fault;
+
+	while (1) {
+		newval = (uval & FUTEX_OWNER_DIED) | newtid;
+
+		curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
+
+		if (curval == -EFAULT)
+			goto handle_fault;
+		if (curval == uval)
+			break;
+		uval = curval;
+	}
+
+	/*
+	 * We fixed up user space. Now we need to fix the pi_state
+	 * itself.
+	 */
 	if (pi_state->owner != NULL) {
 		spin_lock_irq(&pi_state->owner->pi_lock);
 		WARN_ON(list_empty(&pi_state->list));
 		list_del_init(&pi_state->list);
 		spin_unlock_irq(&pi_state->owner->pi_lock);
-	} else
-		newtid |= FUTEX_OWNER_DIED;
+	}
 
 	pi_state->owner = newowner;
 
@@ -1118,26 +1161,35 @@
 	WARN_ON(!list_empty(&pi_state->list));
 	list_add(&pi_state->list, &newowner->pi_state_list);
 	spin_unlock_irq(&newowner->pi_lock);
+	return 0;
 
 	/*
-	 * We own it, so we have to replace the pending owner
-	 * TID. This must be atomic as we have preserve the
-	 * owner died bit here.
+	 * To handle the page fault we need to drop the hash bucket
+	 * lock here. That gives the other task (either the pending
+	 * owner itself or the task which stole the rtmutex) the
+	 * chance to try the fixup of the pi_state. So once we are
+	 * back from handling the fault we need to check the pi_state
+	 * after reacquiring the hash bucket lock and before trying to
+	 * do another fixup. When the fixup has been done already we
+	 * simply return.
 	 */
-	ret = get_futex_value_locked(&uval, uaddr);
+handle_fault:
+	spin_unlock(q->lock_ptr);
 
-	while (!ret) {
-		newval = (uval & FUTEX_OWNER_DIED) | newtid;
+	ret = futex_handle_fault((unsigned long)uaddr, fshared, attempt++);
 
-		curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
+	spin_lock(q->lock_ptr);
 
-		if (curval == -EFAULT)
-			ret = -EFAULT;
-		if (curval == uval)
-			break;
-		uval = curval;
-	}
-	return ret;
+	/*
+	 * Check if someone else fixed it for us:
+	 */
+	if (pi_state->owner != oldowner)
+		return 0;
+
+	if (ret)
+		return ret;
+
+	goto retry;
 }
 
 /*
@@ -1507,7 +1559,7 @@
 		 * that case:
 		 */
 		if (q.pi_state->owner != curr)
-			ret = fixup_pi_state_owner(uaddr, &q, curr);
+			ret = fixup_pi_state_owner(uaddr, &q, curr, fshared);
 	} else {
 		/*
 		 * Catch the rare case, where the lock was released
@@ -1539,7 +1591,8 @@
 				int res;
 
 				owner = rt_mutex_owner(&q.pi_state->pi_mutex);
-				res = fixup_pi_state_owner(uaddr, &q, owner);
+				res = fixup_pi_state_owner(uaddr, &q, owner,
+							   fshared);
 
 				/* propagate -EFAULT, if the fixup failed */
 				if (res)
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 421be5f..ab80515 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1003,10 +1003,18 @@
 	 */
 	raise = timer->state == HRTIMER_STATE_PENDING;
 
+	/*
+	 * We use preempt_disable to prevent this task from migrating after
+	 * setting up the softirq and raising it. Otherwise, if me migrate
+	 * we will raise the softirq on the wrong CPU.
+	 */
+	preempt_disable();
+
 	unlock_hrtimer_base(timer, &flags);
 
 	if (raise)
 		hrtimer_raise_softirq();
+	preempt_enable();
 
 	return ret;
 }
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 79e3c90..3ec23c3 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -1499,7 +1499,8 @@
 	return 1;
 }
 
-void kgdb_console_write(struct console *co, const char *s, unsigned count)
+static void kgdb_console_write(struct console *co, const char *s,
+   unsigned count)
 {
 	unsigned long flags;
 
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c
index f4ffbd0..a38895a 100644
--- a/kernel/rcuclassic.c
+++ b/kernel/rcuclassic.c
@@ -89,8 +89,22 @@
 		/*
 		 * Don't send IPI to itself. With irqs disabled,
 		 * rdp->cpu is the current cpu.
+		 *
+		 * cpu_online_map is updated by the _cpu_down()
+		 * using stop_machine_run(). Since we're in irqs disabled
+		 * section, stop_machine_run() is not exectuting, hence
+		 * the cpu_online_map is stable.
+		 *
+		 * However,  a cpu might have been offlined _just_ before
+		 * we disabled irqs while entering here.
+		 * And rcu subsystem might not yet have handled the CPU_DEAD
+		 * notification, leading to the offlined cpu's bit
+		 * being set in the rcp->cpumask.
+		 *
+		 * Hence cpumask = (rcp->cpumask & cpu_online_map) to prevent
+		 * sending smp_reschedule() to an offlined CPU.
 		 */
-		cpumask = rcp->cpumask;
+		cpus_and(cpumask, rcp->cpumask, cpu_online_map);
 		cpu_clear(rdp->cpu, cpumask);
 		for_each_cpu_mask(cpu, cpumask)
 			smp_send_reschedule(cpu);
diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c
index e1cdf19..5e02b774 100644
--- a/kernel/rcupreempt.c
+++ b/kernel/rcupreempt.c
@@ -217,8 +217,6 @@
 }
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
 
-EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
-
 void __rcu_read_lock(void)
 {
 	int idx;
diff --git a/kernel/sched.c b/kernel/sched.c
index eaf6751..94ead43 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1127,6 +1127,7 @@
 	return HRTIMER_NORESTART;
 }
 
+#ifdef CONFIG_SMP
 static void hotplug_hrtick_disable(int cpu)
 {
 	struct rq *rq = cpu_rq(cpu);
@@ -1182,6 +1183,7 @@
 {
 	hotcpu_notifier(hotplug_hrtick, 0);
 }
+#endif /* CONFIG_SMP */
 
 static void init_rq_hrtick(struct rq *rq)
 {
@@ -4396,22 +4398,20 @@
 			     signal_pending(current)) ||
 			    (state == TASK_KILLABLE &&
 			     fatal_signal_pending(current))) {
-				__remove_wait_queue(&x->wait, &wait);
-				return -ERESTARTSYS;
+				timeout = -ERESTARTSYS;
+				break;
 			}
 			__set_current_state(state);
 			spin_unlock_irq(&x->wait.lock);
 			timeout = schedule_timeout(timeout);
 			spin_lock_irq(&x->wait.lock);
-			if (!timeout) {
-				__remove_wait_queue(&x->wait, &wait);
-				return timeout;
-			}
-		} while (!x->done);
+		} while (!x->done && timeout);
 		__remove_wait_queue(&x->wait, &wait);
+		if (!x->done)
+			return timeout;
 	}
 	x->done--;
-	return timeout;
+	return timeout ?: 1;
 }
 
 static long __sched
@@ -5887,6 +5887,7 @@
 		next = pick_next_task(rq, rq->curr);
 		if (!next)
 			break;
+		next->sched_class->put_prev_task(rq, next);
 		migrate_dead(dead_cpu, next);
 
 	}
@@ -6877,7 +6878,12 @@
 
 static int __init setup_relax_domain_level(char *str)
 {
-	default_relax_domain_level = simple_strtoul(str, NULL, 0);
+	unsigned long val;
+
+	val = simple_strtoul(str, NULL, 0);
+	if (val < SD_LV_MAX)
+		default_relax_domain_level = val;
+
 	return 1;
 }
 __setup("relax_domain_level=", setup_relax_domain_level);
@@ -7236,6 +7242,18 @@
 }
 
 /*
+ * Free current domain masks.
+ * Called after all cpus are attached to NULL domain.
+ */
+static void free_sched_domains(void)
+{
+	ndoms_cur = 0;
+	if (doms_cur != &fallback_doms)
+		kfree(doms_cur);
+	doms_cur = &fallback_doms;
+}
+
+/*
  * Set up scheduler domains and groups. Callers must hold the hotplug lock.
  * For now this just excludes isolated cpus, but could be used to
  * exclude other special cases in the future.
@@ -7382,6 +7400,7 @@
 	get_online_cpus();
 	mutex_lock(&sched_domains_mutex);
 	detach_destroy_domains(&cpu_online_map);
+	free_sched_domains();
 	err = arch_init_sched_domains(&cpu_online_map);
 	mutex_unlock(&sched_domains_mutex);
 	put_online_cpus();
@@ -7467,6 +7486,7 @@
 	case CPU_DOWN_PREPARE:
 	case CPU_DOWN_PREPARE_FROZEN:
 		detach_destroy_domains(&cpu_online_map);
+		free_sched_domains();
 		return NOTIFY_OK;
 
 	case CPU_UP_CANCELED:
@@ -7485,8 +7505,16 @@
 		return NOTIFY_DONE;
 	}
 
+#ifndef CONFIG_CPUSETS
+	/*
+	 * Create default domain partitioning if cpusets are disabled.
+	 * Otherwise we let cpusets rebuild the domains based on the
+	 * current setup.
+	 */
+
 	/* The hotplug lock is already held by cpu_up/cpu_down */
 	arch_init_sched_domains(&cpu_online_map);
+#endif
 
 	return NOTIFY_OK;
 }
@@ -7626,7 +7654,6 @@
 	else
 		rt_se->rt_rq = parent->my_q;
 
-	rt_se->rt_rq = &rq->rt;
 	rt_se->my_q = rt_rq;
 	rt_se->parent = parent;
 	INIT_LIST_HEAD(&rt_se->run_list);
@@ -8348,7 +8375,7 @@
 #ifdef CONFIG_CGROUP_SCHED
 static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
 {
-	struct task_group *tgi, *parent = tg->parent;
+	struct task_group *tgi, *parent = tg ? tg->parent : NULL;
 	unsigned long total = 0;
 
 	if (!parent) {
@@ -8475,6 +8502,9 @@
 	rt_period = (u64)rt_period_us * NSEC_PER_USEC;
 	rt_runtime = tg->rt_bandwidth.rt_runtime;
 
+	if (rt_period == 0)
+		return -EINVAL;
+
 	return tg_set_bandwidth(tg, rt_period, rt_runtime);
 }
 
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index 3432d57..0f3c191 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -250,7 +250,8 @@
 			if (rt_rq->rt_time || rt_rq->rt_nr_running)
 				idle = 0;
 			spin_unlock(&rt_rq->rt_runtime_lock);
-		}
+		} else if (rt_rq->rt_nr_running)
+			idle = 0;
 
 		if (enqueue)
 			sched_rt_rq_enqueue(rt_rq);
@@ -449,13 +450,19 @@
 #endif
 }
 
-static void enqueue_rt_entity(struct sched_rt_entity *rt_se)
+static void __enqueue_rt_entity(struct sched_rt_entity *rt_se)
 {
 	struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
 	struct rt_prio_array *array = &rt_rq->active;
 	struct rt_rq *group_rq = group_rt_rq(rt_se);
 
-	if (group_rq && rt_rq_throttled(group_rq))
+	/*
+	 * Don't enqueue the group if its throttled, or when empty.
+	 * The latter is a consequence of the former when a child group
+	 * get throttled and the current group doesn't have any other
+	 * active members.
+	 */
+	if (group_rq && (rt_rq_throttled(group_rq) || !group_rq->rt_nr_running))
 		return;
 
 	list_add_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se));
@@ -464,7 +471,7 @@
 	inc_rt_tasks(rt_se, rt_rq);
 }
 
-static void dequeue_rt_entity(struct sched_rt_entity *rt_se)
+static void __dequeue_rt_entity(struct sched_rt_entity *rt_se)
 {
 	struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
 	struct rt_prio_array *array = &rt_rq->active;
@@ -480,11 +487,10 @@
  * Because the prio of an upper entry depends on the lower
  * entries, we must remove entries top - down.
  */
-static void dequeue_rt_stack(struct task_struct *p)
+static void dequeue_rt_stack(struct sched_rt_entity *rt_se)
 {
-	struct sched_rt_entity *rt_se, *back = NULL;
+	struct sched_rt_entity *back = NULL;
 
-	rt_se = &p->rt;
 	for_each_sched_rt_entity(rt_se) {
 		rt_se->back = back;
 		back = rt_se;
@@ -492,7 +498,26 @@
 
 	for (rt_se = back; rt_se; rt_se = rt_se->back) {
 		if (on_rt_rq(rt_se))
-			dequeue_rt_entity(rt_se);
+			__dequeue_rt_entity(rt_se);
+	}
+}
+
+static void enqueue_rt_entity(struct sched_rt_entity *rt_se)
+{
+	dequeue_rt_stack(rt_se);
+	for_each_sched_rt_entity(rt_se)
+		__enqueue_rt_entity(rt_se);
+}
+
+static void dequeue_rt_entity(struct sched_rt_entity *rt_se)
+{
+	dequeue_rt_stack(rt_se);
+
+	for_each_sched_rt_entity(rt_se) {
+		struct rt_rq *rt_rq = group_rt_rq(rt_se);
+
+		if (rt_rq && rt_rq->rt_nr_running)
+			__enqueue_rt_entity(rt_se);
 	}
 }
 
@@ -506,32 +531,15 @@
 	if (wakeup)
 		rt_se->timeout = 0;
 
-	dequeue_rt_stack(p);
-
-	/*
-	 * enqueue everybody, bottom - up.
-	 */
-	for_each_sched_rt_entity(rt_se)
-		enqueue_rt_entity(rt_se);
+	enqueue_rt_entity(rt_se);
 }
 
 static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep)
 {
 	struct sched_rt_entity *rt_se = &p->rt;
-	struct rt_rq *rt_rq;
 
 	update_curr_rt(rq);
-
-	dequeue_rt_stack(p);
-
-	/*
-	 * re-enqueue all non-empty rt_rq entities.
-	 */
-	for_each_sched_rt_entity(rt_se) {
-		rt_rq = group_rt_rq(rt_se);
-		if (rt_rq && rt_rq->rt_nr_running)
-			enqueue_rt_entity(rt_se);
-	}
+	dequeue_rt_entity(rt_se);
 }
 
 /*
@@ -542,8 +550,10 @@
 void requeue_rt_entity(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se)
 {
 	struct rt_prio_array *array = &rt_rq->active;
+	struct list_head *queue = array->queue + rt_se_prio(rt_se);
 
-	list_move_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se));
+	if (on_rt_rq(rt_se))
+		list_move_tail(&rt_se->run_list, queue);
 }
 
 static void requeue_task_rt(struct rq *rq, struct task_struct *p)
diff --git a/kernel/sched_stats.h b/kernel/sched_stats.h
index a38878e..80179ef 100644
--- a/kernel/sched_stats.h
+++ b/kernel/sched_stats.h
@@ -198,6 +198,9 @@
 /*
  * Called when a process ceases being the active-running process, either
  * voluntarily or involuntarily.  Now we can calculate how long we ran.
+ * Also, if the process is still in the TASK_RUNNING state, call
+ * sched_info_queued() to mark that it has now again started waiting on
+ * the runqueue.
  */
 static inline void sched_info_depart(struct task_struct *t)
 {
@@ -206,6 +209,9 @@
 
 	t->sched_info.cpu_time += delta;
 	rq_sched_info_depart(task_rq(t), delta);
+
+	if (t->state == TASK_RUNNING)
+		sched_info_queued(t);
 }
 
 /*
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 01b6522..c828c23 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -49,12 +49,17 @@
 	return cpu_clock(this_cpu) >> 30LL;  /* 2^30 ~= 10^9 */
 }
 
-void touch_softlockup_watchdog(void)
+static void __touch_softlockup_watchdog(void)
 {
 	int this_cpu = raw_smp_processor_id();
 
 	__raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu);
 }
+
+void touch_softlockup_watchdog(void)
+{
+	__raw_get_cpu_var(touch_timestamp) = 0;
+}
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
 void touch_all_softlockup_watchdogs(void)
@@ -80,7 +85,7 @@
 	unsigned long now;
 
 	if (touch_timestamp == 0) {
-		touch_softlockup_watchdog();
+		__touch_softlockup_watchdog();
 		return;
 	}
 
@@ -95,7 +100,7 @@
 
 	/* do not print during early bootup: */
 	if (unlikely(system_state != SYSTEM_RUNNING)) {
-		touch_softlockup_watchdog();
+		__touch_softlockup_watchdog();
 		return;
 	}
 
@@ -214,7 +219,7 @@
 	sched_setscheduler(current, SCHED_FIFO, &param);
 
 	/* initialize timestamp */
-	touch_softlockup_watchdog();
+	__touch_softlockup_watchdog();
 
 	set_current_state(TASK_INTERRUPTIBLE);
 	/*
@@ -223,7 +228,7 @@
 	 * debug-printout triggers in softlockup_tick().
 	 */
 	while (!kthread_should_stop()) {
-		touch_softlockup_watchdog();
+		__touch_softlockup_watchdog();
 		schedule();
 
 		if (kthread_should_stop())
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 29fc39f..ce77995 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -13,7 +13,7 @@
  *   Kai Petzke <wpp@marie.physik.tu-berlin.de>
  *   Theodore Ts'o <tytso@mit.edu>
  *
- * Made to use alloc_percpu by Christoph Lameter <clameter@sgi.com>.
+ * Made to use alloc_percpu by Christoph Lameter.
  */
 
 #include <linux/module.h>
diff --git a/lib/bug.c b/lib/bug.c
index 530f38f..bfeafd6 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -37,6 +37,7 @@
  */
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/bug.h>
 #include <linux/sched.h>
 
@@ -149,6 +150,7 @@
 			       (void *)bugaddr);
 
 		show_regs(regs);
+		add_taint(TAINT_WARN);
 		return BUG_TRAP_TYPE_WARN;
 	}
 
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index a76a5e1..85b18d7 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -68,6 +68,7 @@
 {
 	gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
 	struct debug_obj *new;
+	unsigned long flags;
 
 	if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))
 		return obj_pool_free;
@@ -81,10 +82,10 @@
 		if (!new)
 			return obj_pool_free;
 
-		spin_lock(&pool_lock);
+		spin_lock_irqsave(&pool_lock, flags);
 		hlist_add_head(&new->node, &obj_pool);
 		obj_pool_free++;
-		spin_unlock(&pool_lock);
+		spin_unlock_irqrestore(&pool_lock, flags);
 	}
 	return obj_pool_free;
 }
@@ -110,16 +111,13 @@
 }
 
 /*
- * Allocate a new object. If the pool is empty and no refill possible,
- * switch off the debugger.
+ * Allocate a new object. If the pool is empty, switch off the debugger.
  */
 static struct debug_obj *
 alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
 {
 	struct debug_obj *obj = NULL;
-	int retry = 0;
 
-repeat:
 	spin_lock(&pool_lock);
 	if (obj_pool.first) {
 		obj	    = hlist_entry(obj_pool.first, typeof(*obj), node);
@@ -141,9 +139,6 @@
 	}
 	spin_unlock(&pool_lock);
 
-	if (fill_pool() && !obj && !retry++)
-		goto repeat;
-
 	return obj;
 }
 
@@ -261,6 +256,8 @@
 	struct debug_obj *obj;
 	unsigned long flags;
 
+	fill_pool();
+
 	db = get_bucket((unsigned long) addr);
 
 	spin_lock_irqsave(&db->lock, flags);
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 169a2f8..56ec21a 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2001 Momchil Velikov
  * Portions Copyright (C) 2001 Christoph Hellwig
- * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
+ * Copyright (C) 2005 SGI, Christoph Lameter
  * Copyright (C) 2006 Nick Piggin
  *
  * This program is free software; you can redistribute it and/or
diff --git a/lib/ts_bm.c b/lib/ts_bm.c
index d90822c..4a7fce7 100644
--- a/lib/ts_bm.c
+++ b/lib/ts_bm.c
@@ -63,7 +63,7 @@
 	struct ts_bm *bm = ts_config_priv(conf);
 	unsigned int i, text_len, consumed = state->offset;
 	const u8 *text;
-	int shift = bm->patlen, bs;
+	int shift = bm->patlen - 1, bs;
 
 	for (;;) {
 		text_len = conf->get_next_block(consumed, &text, conf, state);
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
index f4026ba..05f2b40 100644
--- a/mm/allocpercpu.c
+++ b/mm/allocpercpu.c
@@ -1,7 +1,7 @@
 /*
  * linux/mm/allocpercpu.c
  *
- * Separated from slab.c August 11, 2006 Christoph Lameter <clameter@sgi.com>
+ * Separated from slab.c August 11, 2006 Christoph Lameter
  */
 #include <linux/mm.h>
 #include <linux/module.h>
diff --git a/mm/bootmem.c b/mm/bootmem.c
index e8fb927..8d9f60e 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -442,15 +442,17 @@
 	return init_bootmem_core(pgdat, freepfn, startpfn, endpfn);
 }
 
-void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
+int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
 				 unsigned long size, int flags)
 {
 	int ret;
 
 	ret = can_reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
 	if (ret < 0)
-		return;
+		return -ENOMEM;
 	reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
+
+	return 0;
 }
 
 void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
diff --git a/mm/memory.c b/mm/memory.c
index 19e0ae9..2302d22 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -999,17 +999,15 @@
 		goto no_page_table;
 
 	ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
-	if (!ptep)
-		goto out;
 
 	pte = *ptep;
 	if (!pte_present(pte))
-		goto unlock;
+		goto no_page;
 	if ((flags & FOLL_WRITE) && !pte_write(pte))
 		goto unlock;
 	page = vm_normal_page(vma, address, pte);
 	if (unlikely(!page))
-		goto unlock;
+		goto bad_page;
 
 	if (flags & FOLL_GET)
 		get_page(page);
@@ -1024,6 +1022,15 @@
 out:
 	return page;
 
+bad_page:
+	pte_unmap_unlock(ptep, ptl);
+	return ERR_PTR(-EFAULT);
+
+no_page:
+	pte_unmap_unlock(ptep, ptl);
+	if (!pte_none(pte))
+		return page;
+	/* Fall through to ZERO_PAGE handling */
 no_page_table:
 	/*
 	 * When core dumping an enormous anonymous area that nobody
@@ -1038,6 +1045,26 @@
 	return page;
 }
 
+/* Can we do the FOLL_ANON optimization? */
+static inline int use_zero_page(struct vm_area_struct *vma)
+{
+	/*
+	 * We don't want to optimize FOLL_ANON for make_pages_present()
+	 * when it tries to page in a VM_LOCKED region. As to VM_SHARED,
+	 * we want to get the page from the page tables to make sure
+	 * that we serialize and update with any other user of that
+	 * mapping.
+	 */
+	if (vma->vm_flags & (VM_LOCKED | VM_SHARED))
+		return 0;
+	/*
+	 * And if we have a fault or a nopfn routine, it's not an
+	 * anonymous region.
+	 */
+	return !vma->vm_ops ||
+		(!vma->vm_ops->fault && !vma->vm_ops->nopfn);
+}
+
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 		unsigned long start, int len, int write, int force,
 		struct page **pages, struct vm_area_struct **vmas)
@@ -1112,8 +1139,7 @@
 		foll_flags = FOLL_TOUCH;
 		if (pages)
 			foll_flags |= FOLL_GET;
-		if (!write && !(vma->vm_flags & VM_LOCKED) &&
-		    (!vma->vm_ops || !vma->vm_ops->fault))
+		if (!write && use_zero_page(vma))
 			foll_flags |= FOLL_ANON;
 
 		do {
@@ -1125,7 +1151,7 @@
 			 * be processed until returning to user space.
 			 */
 			if (unlikely(test_tsk_thread_flag(tsk, TIF_MEMDIE)))
-				return -ENOMEM;
+				return i ? i : -ENOMEM;
 
 			if (write)
 				foll_flags |= FOLL_WRITE;
@@ -1159,6 +1185,8 @@
 
 				cond_resched();
 			}
+			if (IS_ERR(page))
+				return i ? i : PTR_ERR(page);
 			if (pages) {
 				pages[i] = page;
 
@@ -1669,8 +1697,19 @@
 	struct page *dirty_page = NULL;
 
 	old_page = vm_normal_page(vma, address, orig_pte);
-	if (!old_page)
+	if (!old_page) {
+		/*
+		 * VM_MIXEDMAP !pfn_valid() case
+		 *
+		 * We should not cow pages in a shared writeable mapping.
+		 * Just mark the pages writable as we can't do any dirty
+		 * accounting on raw pfn maps.
+		 */
+		if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
+				     (VM_WRITE|VM_SHARED))
+			goto reuse;
 		goto gotten;
+	}
 
 	/*
 	 * Take out anonymous pages first, anonymous shared vmas are
@@ -1723,6 +1762,7 @@
 	}
 
 	if (reuse) {
+reuse:
 		flush_cache_page(vma, address, pte_pfn(orig_pte));
 		entry = pte_mkyoung(orig_pte);
 		entry = maybe_mkwrite(pte_mkdirty(entry), vma);
@@ -1757,7 +1797,6 @@
 	page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
 	if (likely(pte_same(*page_table, orig_pte))) {
 		if (old_page) {
-			page_remove_rmap(old_page, vma);
 			if (!PageAnon(old_page)) {
 				dec_mm_counter(mm, file_rss);
 				inc_mm_counter(mm, anon_rss);
@@ -1779,6 +1818,32 @@
 		lru_cache_add_active(new_page);
 		page_add_new_anon_rmap(new_page, vma, address);
 
+		if (old_page) {
+			/*
+			 * Only after switching the pte to the new page may
+			 * we remove the mapcount here. Otherwise another
+			 * process may come and find the rmap count decremented
+			 * before the pte is switched to the new page, and
+			 * "reuse" the old page writing into it while our pte
+			 * here still points into it and can be read by other
+			 * threads.
+			 *
+			 * The critical issue is to order this
+			 * page_remove_rmap with the ptp_clear_flush above.
+			 * Those stores are ordered by (if nothing else,)
+			 * the barrier present in the atomic_add_negative
+			 * in page_remove_rmap.
+			 *
+			 * Then the TLB flush in ptep_clear_flush ensures that
+			 * no process can access the old page before the
+			 * decremented mapcount is visible. And the old page
+			 * cannot be reused until after the decremented
+			 * mapcount is visible. So transitively, TLBs to
+			 * old page will be flushed before it can be reused.
+			 */
+			page_remove_rmap(old_page, vma);
+		}
+
 		/* Free the old page.. */
 		new_page = old_page;
 		ret |= VM_FAULT_WRITE;
diff --git a/mm/migrate.c b/mm/migrate.c
index 449d77d..55bd355 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -9,7 +9,7 @@
  * IWAMOTO Toshihiro <iwamoto@valinux.co.jp>
  * Hirokazu Takahashi <taka@valinux.co.jp>
  * Dave Hansen <haveblue@us.ibm.com>
- * Christoph Lameter <clameter@sgi.com>
+ * Christoph Lameter
  */
 
 #include <linux/migrate.h>
@@ -865,6 +865,11 @@
 			goto set_status;
 
 		page = follow_page(vma, pp->addr, FOLL_GET);
+
+		err = PTR_ERR(page);
+		if (IS_ERR(page))
+			goto set_status;
+
 		err = -ENOENT;
 		if (!page)
 			goto set_status;
@@ -928,6 +933,11 @@
 			goto set_status;
 
 		page = follow_page(vma, pm->addr, 0);
+
+		err = PTR_ERR(page);
+		if (IS_ERR(page))
+			goto set_status;
+
 		err = -ENOENT;
 		/* Use PageReserved to check for zero page */
 		if (!page || PageReserved(page))
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 2f55295..f32fae3 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2328,7 +2328,6 @@
 static void build_zonelist_cache(pg_data_t *pgdat)
 {
 	pgdat->node_zonelists[0].zlcache_ptr = NULL;
-	pgdat->node_zonelists[1].zlcache_ptr = NULL;
 }
 
 #endif	/* CONFIG_NUMA */
diff --git a/mm/slab.c b/mm/slab.c
index 06236e4..046607f 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3263,9 +3263,12 @@
 
 		if (cpuset_zone_allowed_hardwall(zone, flags) &&
 			cache->nodelists[nid] &&
-			cache->nodelists[nid]->free_objects)
+			cache->nodelists[nid]->free_objects) {
 				obj = ____cache_alloc_node(cache,
 					flags | GFP_THISNODE, nid);
+				if (obj)
+					break;
+		}
 	}
 
 	if (!obj) {
diff --git a/mm/slub.c b/mm/slub.c
index 0987d1c..1a427c0 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -5,7 +5,7 @@
  * The allocator synchronizes using per slab locks and only
  * uses a centralized lock to manage a pool of partial slabs.
  *
- * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
+ * (C) 2007 SGI, Christoph Lameter
  */
 
 #include <linux/mm.h>
@@ -2995,8 +2995,6 @@
 		create_kmalloc_cache(&kmalloc_caches[1],
 				"kmalloc-96", 96, GFP_KERNEL);
 		caches++;
-	}
-	if (KMALLOC_MIN_SIZE <= 128) {
 		create_kmalloc_cache(&kmalloc_caches[2],
 				"kmalloc-192", 192, GFP_KERNEL);
 		caches++;
@@ -3026,6 +3024,16 @@
 	for (i = 8; i < KMALLOC_MIN_SIZE; i += 8)
 		size_index[(i - 1) / 8] = KMALLOC_SHIFT_LOW;
 
+	if (KMALLOC_MIN_SIZE == 128) {
+		/*
+		 * The 192 byte sized cache is not used if the alignment
+		 * is 128 byte. Redirect kmalloc to use the 256 byte cache
+		 * instead.
+		 */
+		for (i = 128 + 8; i <= 192; i += 8)
+			size_index[(i - 1) / 8] = 8;
+	}
+
 	slab_state = UP;
 
 	/* Provide the correct kmalloc names now that the caches are up */
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 99c4f36..a91b5f8 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -1,7 +1,7 @@
 /*
  * Virtual Memory Map support
  *
- * (C) 2007 sgi. Christoph Lameter <clameter@sgi.com>.
+ * (C) 2007 sgi. Christoph Lameter.
  *
  * Virtual memory maps allow VM primitives pfn_to_page, page_to_pfn,
  * virt_to_page, page_address() to be implemented as a base offset
diff --git a/net/core/dev.c b/net/core/dev.c
index 68d8df0..fca23a3 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -454,7 +454,7 @@
 	for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) {
 		if (s[i].name[0] == '\0' || s[i].name[0] == ' ') {
 			memset(s[i].name, 0, sizeof(s[i].name));
-			strcpy(s[i].name, name);
+			strlcpy(s[i].name, name, IFNAMSIZ);
 			memcpy(&s[i].map, map, sizeof(s[i].map));
 			break;
 		}
@@ -479,7 +479,7 @@
 
 	for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) {
 		if (s[i].name[0] != '\0' && s[i].name[0] != ' ' &&
-		    !strncmp(dev->name, s[i].name, strlen(s[i].name))) {
+		    !strcmp(dev->name, s[i].name)) {
 			dev->irq 	= s[i].map.irq;
 			dev->base_addr 	= s[i].map.base_addr;
 			dev->mem_start 	= s[i].map.mem_start;
@@ -2077,6 +2077,10 @@
 
 	rcu_read_lock();
 
+	/* Don't receive packets in an exiting network namespace */
+	if (!net_alive(dev_net(skb->dev)))
+		goto out;
+
 #ifdef CONFIG_NET_CLS_ACT
 	if (skb->tc_verd & TC_NCLS) {
 		skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
@@ -2969,7 +2973,7 @@
 /**
  *	dev_unicast_add		- add a secondary unicast address
  *	@dev: device
- *	@addr: address to delete
+ *	@addr: address to add
  *	@alen: length of @addr
  *
  *	Add a secondary unicast address to the device or increase
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index e3e9ab0..277a230 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -226,7 +226,7 @@
 
 	ops = lookup_rules_ops(net, frh->family);
 	if (ops == NULL) {
-		err = EAFNOSUPPORT;
+		err = -EAFNOSUPPORT;
 		goto errout;
 	}
 
@@ -365,7 +365,7 @@
 
 	ops = lookup_rules_ops(net, frh->family);
 	if (ops == NULL) {
-		err = EAFNOSUPPORT;
+		err = -EAFNOSUPPORT;
 		goto errout;
 	}
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 4f83697..df37443 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -68,7 +68,6 @@
  *	sk_filter - run a packet through a socket filter
  *	@sk: sock associated with &sk_buff
  *	@skb: buffer to filter
- *	@needlock: set to 1 if the sock is not locked by caller.
  *
  * Run the filter code and then cut skb->data to correct size returned by
  * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 72b4c18..7c52fe2 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -140,6 +140,9 @@
 	struct pernet_operations *ops;
 	struct net *net;
 
+	/* Be very certain incoming network packets will not find us */
+	rcu_barrier();
+
 	net = container_of(work, struct net, work);
 
 	mutex_lock(&net_mutex);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1e556d3..3666216 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1292,12 +1292,14 @@
 {
 	unsigned int nr_pages = spd->nr_pages;
 	unsigned int poff, plen, len, toff, tlen;
-	int headlen, seg;
+	int headlen, seg, error = 0;
 
 	toff = *offset;
 	tlen = *total_len;
-	if (!tlen)
+	if (!tlen) {
+		error = 1;
 		goto err;
+	}
 
 	/*
 	 * if the offset is greater than the linear part, go directly to
@@ -1339,7 +1341,8 @@
 		 * just jump directly to update and return, no point
 		 * in going over fragments when the output is full.
 		 */
-		if (spd_fill_page(spd, virt_to_page(p), plen, poff, skb))
+		error = spd_fill_page(spd, virt_to_page(p), plen, poff, skb);
+		if (error)
 			goto done;
 
 		tlen -= plen;
@@ -1369,7 +1372,8 @@
 		if (!plen)
 			break;
 
-		if (spd_fill_page(spd, f->page, plen, poff, skb))
+		error = spd_fill_page(spd, f->page, plen, poff, skb);
+		if (error)
 			break;
 
 		tlen -= plen;
@@ -1382,7 +1386,10 @@
 		return 0;
 	}
 err:
-	return 1;
+	/* update the offset to reflect the linear part skip, if any */
+	if (!error)
+		*offset = toff;
+	return error;
 }
 
 /*
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 4ed429b..0546a0b 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -192,14 +192,21 @@
 
 static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 		struct inet_frag_queue *qp_in, struct inet_frags *f,
-		unsigned int hash, void *arg)
+		void *arg)
 {
 	struct inet_frag_queue *qp;
 #ifdef CONFIG_SMP
 	struct hlist_node *n;
 #endif
+	unsigned int hash;
 
 	write_lock(&f->lock);
+	/*
+	 * While we stayed w/o the lock other CPU could update
+	 * the rnd seed, so we need to re-calculate the hash
+	 * chain. Fortunatelly the qp_in can be used to get one.
+	 */
+	hash = f->hashfn(qp_in);
 #ifdef CONFIG_SMP
 	/* With SMP race we have to recheck hash table, because
 	 * such entry could be created on other cpu, while we
@@ -247,7 +254,7 @@
 }
 
 static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
-		struct inet_frags *f, void *arg, unsigned int hash)
+		struct inet_frags *f, void *arg)
 {
 	struct inet_frag_queue *q;
 
@@ -255,7 +262,7 @@
 	if (q == NULL)
 		return NULL;
 
-	return inet_frag_intern(nf, q, f, hash, arg);
+	return inet_frag_intern(nf, q, f, arg);
 }
 
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
@@ -264,7 +271,6 @@
 	struct inet_frag_queue *q;
 	struct hlist_node *n;
 
-	read_lock(&f->lock);
 	hlist_for_each_entry(q, n, &f->hash[hash], list) {
 		if (q->net == nf && f->match(q, key)) {
 			atomic_inc(&q->refcnt);
@@ -274,6 +280,6 @@
 	}
 	read_unlock(&f->lock);
 
-	return inet_frag_create(nf, f, key, hash);
+	return inet_frag_create(nf, f, key);
 }
 EXPORT_SYMBOL(inet_frag_find);
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index 4a4d49f..cfd034a 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -383,8 +383,7 @@
 out2: /* send aggregated SKBs to stack */
 	lro_flush(lro_mgr, lro_desc);
 
-out:  /* Original SKB has to be posted to stack */
-	skb->ip_summed = lro_mgr->ip_summed;
+out:
 	return 1;
 }
 
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index cd6ce6a..37221f6 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -229,6 +229,8 @@
 
 	arg.iph = iph;
 	arg.user = user;
+
+	read_lock(&ip4_frags.lock);
 	hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
 
 	q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index fc54a48..850825d 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -260,6 +260,8 @@
 #include <linux/socket.h>
 #include <linux/random.h>
 #include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/swap.h>
 #include <linux/cache.h>
 #include <linux/err.h>
 #include <linux/crypto.h>
@@ -2620,7 +2622,7 @@
 void __init tcp_init(void)
 {
 	struct sk_buff *skb = NULL;
-	unsigned long limit;
+	unsigned long nr_pages, limit;
 	int order, i, max_share;
 
 	BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
@@ -2689,8 +2691,9 @@
 	 * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
 	 * memory, with a floor of 128 pages.
 	 */
-	limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
-	limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
+	nr_pages = totalram_pages - totalhigh_pages;
+	limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
+	limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
 	limit = max(limit, 128UL);
 	sysctl_tcp_mem[0] = limit / 4 * 3;
 	sysctl_tcp_mem[1] = limit;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 12695be..ffe869a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2291,7 +2291,7 @@
 	}
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-			"%08X %5d %8d %lu %d %p %u %u %u %u %d%n",
+			"%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n",
 		i, src, srcp, dest, destp, sk->sk_state,
 		tp->write_seq - tp->snd_una,
 		sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog :
@@ -2303,8 +2303,8 @@
 		icsk->icsk_probes_out,
 		sock_i_ino(sk),
 		atomic_read(&sk->sk_refcnt), sk,
-		icsk->icsk_rto,
-		icsk->icsk_ack.ato,
+		jiffies_to_clock_t(icsk->icsk_rto),
+		jiffies_to_clock_t(icsk->icsk_ack.ato),
 		(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
 		tp->snd_cwnd,
 		tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh,
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 4e5c861..17eb48b 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -102,6 +102,15 @@
 	if (hdr->version != 6)
 		goto err;
 
+	/*
+	 * RFC4291 2.5.3
+	 * A packet received on an interface with a destination address
+	 * of loopback must be dropped.
+	 */
+	if (!(dev->flags & IFF_LOOPBACK) &&
+	    ipv6_addr_loopback(&hdr->daddr))
+		goto err;
+
 	skb->transport_header = skb->network_header + sizeof(*hdr);
 	IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index c042ce1..86e28a7 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -345,18 +345,21 @@
 	case IPV6_DSTOPTS:
 	{
 		struct ipv6_txoptions *opt;
+
+		/* remove any sticky options header with a zero option
+		 * length, per RFC3542.
+		 */
 		if (optlen == 0)
 			optval = NULL;
+		else if (optlen < sizeof(struct ipv6_opt_hdr) ||
+			 optlen & 0x7 || optlen > 8 * 255)
+			goto e_inval;
 
 		/* hop-by-hop / destination options are privileged option */
 		retv = -EPERM;
 		if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
 			break;
 
-		if (optlen < sizeof(struct ipv6_opt_hdr) ||
-		    optlen & 0x7 || optlen > 8 * 255)
-			goto e_inval;
-
 		opt = ipv6_renew_options(sk, np->opt, optname,
 					 (struct ipv6_opt_hdr __user *)optval,
 					 optlen);
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 27a5e8b..f405cea 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -129,7 +129,7 @@
 		.priority	= NF_IP6_PRI_MANGLE,
 	},
 	{
-		.hook		= ip6t_local_hook,
+		.hook		= ip6t_route_hook,
 		.owner		= THIS_MODULE,
 		.pf		= PF_INET6,
 		.hooknum	= NF_INET_LOCAL_IN,
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index e65e26e..cf20bc4 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -207,9 +207,10 @@
 	arg.id = id;
 	arg.src = src;
 	arg.dst = dst;
+
+	read_lock_bh(&nf_frags.lock);
 	hash = ip6qhashfn(id, src, dst);
 
-	local_bh_disable();
 	q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
 	local_bh_enable();
 	if (q == NULL)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 798cabc..a60d7d1 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -247,6 +247,8 @@
 	arg.id = id;
 	arg.src = src;
 	arg.dst = dst;
+
+	read_lock(&ip6_frags.lock);
 	hash = ip6qhashfn(id, src, dst);
 
 	q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d1f3e19..7ff6870 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -240,7 +240,7 @@
 static inline struct rt6_info *rt6_device_match(struct net *net,
 						    struct rt6_info *rt,
 						    int oif,
-						    int strict)
+						    int flags)
 {
 	struct rt6_info *local = NULL;
 	struct rt6_info *sprt;
@@ -253,7 +253,7 @@
 			if (dev->flags & IFF_LOOPBACK) {
 				if (sprt->rt6i_idev == NULL ||
 				    sprt->rt6i_idev->dev->ifindex != oif) {
-					if (strict && oif)
+					if (flags & RT6_LOOKUP_F_IFACE && oif)
 						continue;
 					if (local && (!oif ||
 						      local->rt6i_idev->dev->ifindex == oif))
@@ -266,7 +266,7 @@
 		if (local)
 			return local;
 
-		if (strict)
+		if (flags & RT6_LOOKUP_F_IFACE)
 			return net->ipv6.ip6_null_entry;
 	}
 	return rt;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index cb46749..40ea9c3 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2036,7 +2036,7 @@
 
 	seq_printf(seq,
 		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
+		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
 		   i,
 		   src->s6_addr32[0], src->s6_addr32[1],
 		   src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -2052,8 +2052,8 @@
 		   icsk->icsk_probes_out,
 		   sock_i_ino(sp),
 		   atomic_read(&sp->sk_refcnt), sp,
-		   icsk->icsk_rto,
-		   icsk->icsk_ack.ato,
+		   jiffies_to_clock_t(icsk->icsk_rto),
+		   jiffies_to_clock_t(icsk->icsk_ack.ato),
 		   (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
 		   tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
 		   );
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 150d66d..220e83b 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -380,6 +380,15 @@
 	if (!key)
 		return;
 
+	if (!key->sdata) {
+		/* The key has not been linked yet, simply free it
+		 * and don't Oops */
+		if (key->conf.alg == ALG_CCMP)
+			ieee80211_aes_key_free(key->u.ccmp.tfm);
+		kfree(key);
+		return;
+	}
+
 	spin_lock_irqsave(&key->sdata->local->key_lock, flags);
 	__ieee80211_key_free(key);
 	spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 28d8bd5..c80d589 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1132,7 +1132,7 @@
 	ieee80211_tx_handler *handler;
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result res = TX_DROP, res_prepare;
-	int ret, i;
+	int ret, i, retries = 0;
 
 	WARN_ON(__ieee80211_queue_pending(local, control->queue));
 
@@ -1216,6 +1216,13 @@
 		if (!__ieee80211_queue_stopped(local, control->queue)) {
 			clear_bit(IEEE80211_LINK_STATE_PENDING,
 				  &local->state[control->queue]);
+			retries++;
+			/*
+			 * Driver bug, it's rejecting packets but
+			 * not stopping queues.
+			 */
+			if (WARN_ON_ONCE(retries > 5))
+				goto drop;
 			goto retry;
 		}
 		memcpy(&store->control, control,
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 6106cb7..e840421 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -95,6 +95,13 @@
 			}
 		}
 
+		if (alg == ALG_WEP &&
+			key_len != LEN_WEP40 && key_len != LEN_WEP104) {
+			ieee80211_key_free(key);
+			err = -EINVAL;
+			goto out_unlock;
+		}
+
 		ieee80211_key_link(key, sdata, sta);
 
 		if (set_tx_key || (!sta && !sdata->default_key && key))
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 635b996..5d09e86 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -323,8 +323,7 @@
 	struct ieee80211_hw *hw = &local->hw;
 	int queue;
 
-	tcf_destroy_chain(q->filter_list);
-	q->filter_list = NULL;
+	tcf_destroy_chain(&q->filter_list);
 
 	for (queue=0; queue < hw->queues; queue++) {
 		skb_queue_purge(&q->requeued[queue]);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ba94004..271cd01 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -331,12 +331,13 @@
 
    I.   Upper bound for valid data:	seq <= sender.td_maxend
    II.  Lower bound for valid data:	seq + len >= sender.td_end - receiver.td_maxwin
-   III.	Upper bound for valid ack:      sack <= receiver.td_end
-   IV.	Lower bound for valid ack:	ack >= receiver.td_end - MAXACKWINDOW
+   III.	Upper bound for valid (s)ack:   sack <= receiver.td_end
+   IV.	Lower bound for valid (s)ack:	sack >= receiver.td_end - MAXACKWINDOW
 
-   where sack is the highest right edge of sack block found in the packet.
+   where sack is the highest right edge of sack block found in the packet
+   or ack in the case of packet without SACK option.
 
-   The upper bound limit for a valid ack is not ignored -
+   The upper bound limit for a valid (s)ack is not ignored -
    we doesn't have to deal with fragments.
 */
 
@@ -606,12 +607,12 @@
 		 before(seq, sender->td_maxend + 1),
 		 after(end, sender->td_end - receiver->td_maxwin - 1),
 		 before(sack, receiver->td_end + 1),
-		 after(ack, receiver->td_end - MAXACKWINDOW(sender)));
+		 after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1));
 
 	if (before(seq, sender->td_maxend + 1) &&
 	    after(end, sender->td_end - receiver->td_maxwin - 1) &&
 	    before(sack, receiver->td_end + 1) &&
-	    after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
+	    after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) {
 		/*
 		 * Take into account window scaling (RFC 1323).
 		 */
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 0099da5b..52b2611 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1534,7 +1534,7 @@
 		}
 	}
 	list_for_each_entry_rcu(addr6, &iface->addr6_list, list) {
-		if (addr6->valid || iter_addr6++ < skip_addr6)
+		if (!addr6->valid || iter_addr6++ < skip_addr6)
 			continue;
 		if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
 					   iface,
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 9b97f80..349aba1 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -886,7 +886,7 @@
 		return netlink_unicast_kernel(sk, skb);
 
 	if (sk_filter(sk, skb)) {
-		int err = skb->len;
+		err = skb->len;
 		kfree_skb(skb);
 		sock_put(sk);
 		return err;
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
index 47bbf45..2d106cf 100644
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -132,6 +132,7 @@
  * @maxtype: maximum attribute type to be expected
  * @head: head of attribute stream
  * @len: length of attribute stream
+ * @policy: validation policy
  *
  * Parses a stream of attributes and stores a pointer to each attribute in
  * the tb array accessable via the attribute type. Attributes with a type
@@ -194,7 +195,7 @@
 /**
  * nla_strlcpy - Copy string attribute payload into a sized buffer
  * @dst: where to copy the string to
- * @src: attribute to copy the string from
+ * @nla: attribute to copy the string from
  * @dstsize: size of destination buffer
  *
  * Copies at most dstsize - 1 bytes into the destination buffer.
@@ -340,9 +341,9 @@
 }
 
 /**
- * nla_reserve - reserve room for attribute without header
+ * nla_reserve_nohdr - reserve room for attribute without header
  * @skb: socket buffer to reserve room on
- * @len: length of attribute payload
+ * @attrlen: length of attribute payload
  *
  * Reserves room for attribute payload without a header.
  *
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 82adfe6..9437b27 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -106,17 +106,6 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called sch_prio.
 
-config NET_SCH_RR
-	tristate "Multi Band Round Robin Queuing (RR)"
-	select NET_SCH_PRIO
-	---help---
-	  Say Y here if you want to use an n-band round robin packet
-	  scheduler.
-
-	  The module uses sch_prio for its framework and is aliased as
-	  sch_rr, so it will load sch_prio, although it is referred
-	  to using sch_rr.
-
 config NET_SCH_RED
 	tristate "Random Early Detection (RED)"
 	---help---
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index c40773c..10f01ad 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1252,12 +1252,12 @@
 	kfree(tp);
 }
 
-void tcf_destroy_chain(struct tcf_proto *fl)
+void tcf_destroy_chain(struct tcf_proto **fl)
 {
 	struct tcf_proto *tp;
 
-	while ((tp = fl) != NULL) {
-		fl = tp->next;
+	while ((tp = *fl) != NULL) {
+		*fl = tp->next;
 		tcf_destroy(tp);
 	}
 }
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 3352734..db0e23a 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -160,7 +160,7 @@
 	*prev = flow->next;
 	pr_debug("atm_tc_put: qdisc %p\n", flow->q);
 	qdisc_destroy(flow->q);
-	tcf_destroy_chain(flow->filter_list);
+	tcf_destroy_chain(&flow->filter_list);
 	if (flow->sock) {
 		pr_debug("atm_tc_put: f_count %d\n",
 			file_count(flow->sock->file));
@@ -586,10 +586,11 @@
 	struct atm_flow_data *flow;
 
 	pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
+	for (flow = p->flows; flow; flow = flow->next)
+		tcf_destroy_chain(&flow->filter_list);
+
 	/* races ? */
 	while ((flow = p->flows)) {
-		tcf_destroy_chain(flow->filter_list);
-		flow->filter_list = NULL;
 		if (flow->ref > 1)
 			printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
 			       flow->ref);
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 09969c1..2a3c97f 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1704,7 +1704,7 @@
 
 	BUG_TRAP(!cl->filters);
 
-	tcf_destroy_chain(cl->filter_list);
+	tcf_destroy_chain(&cl->filter_list);
 	qdisc_destroy(cl->q);
 	qdisc_put_rtab(cl->R_tab);
 	gen_kill_estimator(&cl->bstats, &cl->rate_est);
@@ -1728,10 +1728,8 @@
 	 * be bound to classes which have been destroyed already. --TGR '04
 	 */
 	for (h = 0; h < 16; h++) {
-		for (cl = q->classes[h]; cl; cl = cl->next) {
-			tcf_destroy_chain(cl->filter_list);
-			cl->filter_list = NULL;
-		}
+		for (cl = q->classes[h]; cl; cl = cl->next)
+			tcf_destroy_chain(&cl->filter_list);
 	}
 	for (h = 0; h < 16; h++) {
 		struct cbq_class *next;
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 64465ba..c4c1317 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -416,7 +416,7 @@
 
 	pr_debug("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p);
 
-	tcf_destroy_chain(p->filter_list);
+	tcf_destroy_chain(&p->filter_list);
 	qdisc_destroy(p->q);
 	kfree(p->mask);
 }
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index d355e5e..13afa72 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -468,7 +468,7 @@
 
 	return sch;
 errout:
-	return ERR_PTR(-err);
+	return ERR_PTR(err);
 }
 
 struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops,
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index fdfaa3f..e817aa0 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1123,7 +1123,7 @@
 {
 	struct hfsc_sched *q = qdisc_priv(sch);
 
-	tcf_destroy_chain(cl->filter_list);
+	tcf_destroy_chain(&cl->filter_list);
 	qdisc_destroy(cl->qdisc);
 	gen_kill_estimator(&cl->bstats, &cl->rate_est);
 	if (cl != &q->root)
@@ -1541,6 +1541,10 @@
 	unsigned int i;
 
 	for (i = 0; i < HFSC_HSIZE; i++) {
+		list_for_each_entry(cl, &q->clhash[i], hlist)
+			tcf_destroy_chain(&cl->filter_list);
+	}
+	for (i = 0; i < HFSC_HSIZE; i++) {
 		list_for_each_entry_safe(cl, next, &q->clhash[i], hlist)
 			hfsc_destroy_class(sch, cl);
 	}
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 6807c97..3fb58f4 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1238,7 +1238,7 @@
 	qdisc_put_rtab(cl->rate);
 	qdisc_put_rtab(cl->ceil);
 
-	tcf_destroy_chain(cl->filter_list);
+	tcf_destroy_chain(&cl->filter_list);
 
 	while (!list_empty(&cl->children))
 		htb_destroy_class(sch, list_entry(cl->children.next,
@@ -1267,7 +1267,7 @@
 	   and surprisingly it worked in 2.4. But it must precede it
 	   because filter need its target class alive to be able to call
 	   unbind_filter on it (without Oops). */
-	tcf_destroy_chain(q->filter_list);
+	tcf_destroy_chain(&q->filter_list);
 
 	while (!list_empty(&q->root))
 		htb_destroy_class(sch, list_entry(q->root.next,
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index 274b1dd..956c80a 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -104,7 +104,7 @@
 {
 	struct ingress_qdisc_data *p = qdisc_priv(sch);
 
-	tcf_destroy_chain(p->filter_list);
+	tcf_destroy_chain(&p->filter_list);
 }
 
 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 4aa2b45..5532f10 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -219,7 +219,7 @@
 	int prio;
 	struct prio_sched_data *q = qdisc_priv(sch);
 
-	tcf_destroy_chain(q->filter_list);
+	tcf_destroy_chain(&q->filter_list);
 	for (prio=0; prio<q->bands; prio++)
 		qdisc_destroy(q->queues[prio]);
 }
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index f0463d7..6a97afb 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -520,7 +520,7 @@
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
 
-	tcf_destroy_chain(q->filter_list);
+	tcf_destroy_chain(&q->filter_list);
 	q->perturb_period = 0;
 	del_timer_sync(&q->perturb_timer);
 }
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index e7e3baf..0dbcde6 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4401,7 +4401,9 @@
 	if (copy_from_user(&getaddrs, optval, len))
 		return -EFAULT;
 
-	if (getaddrs.addr_num <= 0) return -EINVAL;
+	if (getaddrs.addr_num <= 0 ||
+	    getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
+		return -EINVAL;
 	/*
 	 *  For UDP-style sockets, id specifies the association to query.
 	 *  If the id field is set to the value '0' then the locally bound
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 5905d567..81ae3d6 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1144,20 +1144,20 @@
 		case RPC_GSS_SVC_NONE:
 			break;
 		case RPC_GSS_SVC_INTEGRITY:
+			/* placeholders for length and seq. number: */
+			svc_putnl(resv, 0);
+			svc_putnl(resv, 0);
 			if (unwrap_integ_data(&rqstp->rq_arg,
 					gc->gc_seq, rsci->mechctx))
 				goto garbage_args;
+			break;
+		case RPC_GSS_SVC_PRIVACY:
 			/* placeholders for length and seq. number: */
 			svc_putnl(resv, 0);
 			svc_putnl(resv, 0);
-			break;
-		case RPC_GSS_SVC_PRIVACY:
 			if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
 					gc->gc_seq, rsci->mechctx))
 				goto garbage_args;
-			/* placeholders for length and seq. number: */
-			svc_putnl(resv, 0);
-			svc_putnl(resv, 0);
 			break;
 		default:
 			goto auth_err;
@@ -1170,8 +1170,6 @@
 		goto out;
 	}
 garbage_args:
-	/* Restore write pointer to its original value: */
-	xdr_ressize_check(rqstp, reject_stat);
 	ret = SVC_GARBAGE;
 	goto out;
 auth_err:
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 657835f..783317d 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -487,8 +487,8 @@
 static int unix_accept(struct socket *, struct socket *, int);
 static int unix_getname(struct socket *, struct sockaddr *, int *, int);
 static unsigned int unix_poll(struct file *, struct socket *, poll_table *);
-static unsigned int unix_datagram_poll(struct file *, struct socket *,
-				       poll_table *);
+static unsigned int unix_dgram_poll(struct file *, struct socket *,
+				    poll_table *);
 static int unix_ioctl(struct socket *, unsigned int, unsigned long);
 static int unix_shutdown(struct socket *, int);
 static int unix_stream_sendmsg(struct kiocb *, struct socket *,
@@ -534,7 +534,7 @@
 	.socketpair =	unix_socketpair,
 	.accept =	sock_no_accept,
 	.getname =	unix_getname,
-	.poll =		unix_datagram_poll,
+	.poll =		unix_dgram_poll,
 	.ioctl =	unix_ioctl,
 	.listen =	sock_no_listen,
 	.shutdown =	unix_shutdown,
@@ -555,7 +555,7 @@
 	.socketpair =	unix_socketpair,
 	.accept =	unix_accept,
 	.getname =	unix_getname,
-	.poll =		unix_datagram_poll,
+	.poll =		unix_dgram_poll,
 	.ioctl =	unix_ioctl,
 	.listen =	unix_listen,
 	.shutdown =	unix_shutdown,
@@ -1994,29 +1994,13 @@
 	return mask;
 }
 
-static unsigned int unix_datagram_poll(struct file *file, struct socket *sock,
-				       poll_table *wait)
+static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
+				    poll_table *wait)
 {
-	struct sock *sk = sock->sk, *peer;
-	unsigned int mask;
+	struct sock *sk = sock->sk, *other;
+	unsigned int mask, writable;
 
 	poll_wait(file, sk->sk_sleep, wait);
-
-	peer = unix_peer_get(sk);
-	if (peer) {
-		if (peer != sk) {
-			/*
-			 * Writability of a connected socket additionally
-			 * depends on the state of the receive queue of the
-			 * peer.
-			 */
-			poll_wait(file, &unix_sk(peer)->peer_wait, wait);
-		} else {
-			sock_put(peer);
-			peer = NULL;
-		}
-	}
-
 	mask = 0;
 
 	/* exceptional events? */
@@ -2042,14 +2026,26 @@
 	}
 
 	/* writable? */
-	if (unix_writable(sk) && !(peer && unix_recvq_full(peer)))
+	writable = unix_writable(sk);
+	if (writable) {
+		other = unix_peer_get(sk);
+		if (other) {
+			if (unix_peer(other) != sk) {
+				poll_wait(file, &unix_sk(other)->peer_wait,
+					  wait);
+				if (unix_recvq_full(other))
+					writable = 0;
+			}
+
+			sock_put(other);
+		}
+	}
+
+	if (writable)
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
 		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
-	if (peer)
-		sock_put(peer);
-
 	return mask;
 }
 
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 185488d..855bff4 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -80,6 +80,23 @@
 				     IEEE80211_CHAN_RADAR),
 };
 
+static const struct ieee80211_channel_range ieee80211_EU_channels[] = {
+	/* IEEE 802.11b/g, channels 1..13 */
+	RANGE_PWR(2412, 2472, 20, 6, 0),
+	/* IEEE 802.11a, channel 36*/
+	RANGE_PWR(5180, 5180, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+	/* IEEE 802.11a, channel 40*/
+	RANGE_PWR(5200, 5200, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+	/* IEEE 802.11a, channel 44*/
+	RANGE_PWR(5220, 5220, 23, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+	/* IEEE 802.11a, channels 48..64 */
+	RANGE_PWR(5240, 5320, 23, 6, IEEE80211_CHAN_NO_IBSS |
+				     IEEE80211_CHAN_RADAR),
+	/* IEEE 802.11a, channels 100..140 */
+	RANGE_PWR(5500, 5700, 30, 6, IEEE80211_CHAN_NO_IBSS |
+				     IEEE80211_CHAN_RADAR),
+};
+
 #define REGDOM(_code)							\
 	{								\
 		.code = __stringify(_code),				\
@@ -90,6 +107,7 @@
 static const struct ieee80211_regdomain ieee80211_regdoms[] = {
 	REGDOM(US),
 	REGDOM(JP),
+	REGDOM(EU),
 };
 
 
diff --git a/security/commoncap.c b/security/commoncap.c
index 5edabc7..33d3433 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -103,10 +103,16 @@
 	return (cap_capable(current, CAP_SETPCAP) != 0);
 }
 
+static inline int cap_limit_ptraced_target(void) { return 1; }
+
 #else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
 
 static inline int cap_block_setpcap(struct task_struct *t) { return 0; }
 static inline int cap_inh_is_capped(void) { return 1; }
+static inline int cap_limit_ptraced_target(void)
+{
+	return !capable(CAP_SETPCAP);
+}
 
 #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
 
@@ -342,9 +348,10 @@
 				bprm->e_uid = current->uid;
 				bprm->e_gid = current->gid;
 			}
-			if (!capable (CAP_SETPCAP)) {
-				new_permitted = cap_intersect (new_permitted,
-							current->cap_permitted);
+			if (cap_limit_ptraced_target()) {
+				new_permitted =
+					cap_intersect(new_permitted,
+						      current->cap_permitted);
 			}
 		}
 	}
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index baf3488..fd764a0 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -382,6 +382,8 @@
 	case 'a':
 		wh.type = DEV_ALL;
 		wh.access = ACC_MASK;
+		wh.major = ~0;
+		wh.minor = ~0;
 		goto handle;
 	case 'b':
 		wh.type = DEV_BLOCK;
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 91d1422..73d4572 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -925,7 +925,7 @@
 static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 {
 	unsigned char *val = chip->saved_regs;
-	snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
+	snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
 	for (; num_regs; num_regs--)
 		*val++ = snd_sbmixer_read(chip, *regs++);
 }
@@ -933,7 +933,7 @@
 static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
 {
 	unsigned char *val = chip->saved_regs;
-	snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
+	snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return);
 	for (; num_regs; num_regs--)
 		snd_sbmixer_write(chip, *regs++, *val++);
 }
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 56f87cd..3f00ddf 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -316,6 +316,8 @@
 		return -ENOMEM;
 	}
 
+	/* (2) initialization of the chip hardware */
+	snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
 
 	if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
 			IRQF_SHARED, "Audiowerk2", chip)) {
@@ -329,8 +331,6 @@
 	}
 	chip->irq = pci->irq;
 
-	/* (2) initialization of the chip hardware */
-	snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
 	if (err < 0) {
 		free_irq(chip->irq, (void *)chip);
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 98778cb..1dcf9f3 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -269,28 +269,9 @@
 	}
 }
 
-static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector)
+static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi)
 {
-	int i;
-
-	for (i = 0; i < IOAPIC_NUM_PINS; i++)
-		if (ioapic->redirtbl[i].fields.vector == vector)
-			return i;
-	return -1;
-}
-
-void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
-{
-	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
 	union ioapic_redir_entry *ent;
-	int gsi;
-
-	gsi = get_eoi_gsi(ioapic, vector);
-	if (gsi == -1) {
-		printk(KERN_WARNING "Can't find redir item for %d EOI\n",
-		       vector);
-		return;
-	}
 
 	ent = &ioapic->redirtbl[gsi];
 	ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
@@ -300,6 +281,16 @@
 		ioapic_deliver(ioapic, gsi);
 }
 
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
+{
+	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+	int i;
+
+	for (i = 0; i < IOAPIC_NUM_PINS; i++)
+		if (ioapic->redirtbl[i].fields.vector == vector)
+			__kvm_ioapic_update_eoi(ioapic, i);
+}
+
 static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
 {
 	struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;